skycraft: orbit computatino still borken
But we got ourselves a spaceship! Improved the camera a bit. Now we can see the ship's orbit.
This commit is contained in:
parent
2fccb1fb7c
commit
216ef470c5
@ -3,43 +3,8 @@
|
||||
import * as se3 from '../se3';
|
||||
import {loadTexture, makeProgram} from '../gl';
|
||||
import {makeFace, makeBufferFromFaces} from '../geometry';
|
||||
|
||||
const linalg = {
|
||||
cross: (a, b) => {
|
||||
return [
|
||||
a[1] * b[2] - a[2] * b[1],
|
||||
a[2] * b[0] - a[0] * b[2],
|
||||
a[0] * b[1] - a[1] * b[0],
|
||||
];
|
||||
},
|
||||
diff: (a, b) => {
|
||||
return [
|
||||
a[0] - b[0],
|
||||
a[1] - b[1],
|
||||
a[2] - b[2],
|
||||
];
|
||||
},
|
||||
add: (a, b) => {
|
||||
return [
|
||||
a[0] + b[0],
|
||||
a[1] + b[1],
|
||||
a[2] + b[2],
|
||||
];
|
||||
},
|
||||
norm: a => {
|
||||
return Math.sqrt(a[0]**2 + a[1]**2 + a[2]**2);
|
||||
},
|
||||
dot: (a, b) => {
|
||||
return a[0] * b[0] + a[1] * b[1] + a[2] * b[2];
|
||||
},
|
||||
scale: (a, s) => {
|
||||
return [
|
||||
a[0] * s,
|
||||
a[1] * s,
|
||||
a[2] * s,
|
||||
];
|
||||
},
|
||||
};
|
||||
import { loadStlModel } from './stl';
|
||||
import * as linalg from './linalg';
|
||||
|
||||
const VSHADER = `
|
||||
attribute vec3 aPosition;
|
||||
@ -462,7 +427,7 @@ function closeToPlanet(context) {
|
||||
}
|
||||
|
||||
function makeSun(seed) {
|
||||
const radius = 79;
|
||||
const radius = 7;
|
||||
const radiusChunks = Math.floor(radius / CHUNKSIZE);
|
||||
|
||||
const chunks = [];
|
||||
@ -756,6 +721,9 @@ function handleInput(context) {
|
||||
case 'KeyD':
|
||||
move(0.0, 0.5);
|
||||
return;
|
||||
case 'KeyR':
|
||||
context.timeOffset += 1;
|
||||
return;
|
||||
}
|
||||
});
|
||||
}
|
||||
@ -998,6 +966,7 @@ function getCartesianState(orbit, mu, time) {
|
||||
const rd = e * Math.sqrt(mu / p) * Math.sin(nu);
|
||||
|
||||
if (orbit.tf === undefined) {
|
||||
// FIXME: this is actually borken. :/
|
||||
orbit.tf = [se3.rotz(Om), se3.rotx(i), se3.rotz(w)].reduce(se3.product);
|
||||
}
|
||||
|
||||
@ -1023,11 +992,14 @@ function makeOrbitObject(context, orbit, parentPosition) {
|
||||
const {gl} = context;
|
||||
const position = parentPosition;
|
||||
const glContext = context.orbitGlContext;
|
||||
const orientation = [
|
||||
se3.rotz(orbit.ascendingNodeLongitude),
|
||||
se3.rotx(orbit.inclination),
|
||||
se3.rotz(orbit.periapsisArgument),
|
||||
].reduce(se3.product);
|
||||
const orientation = orbit.tf;
|
||||
|
||||
// FIXME: currently borken.
|
||||
// const orientation = [
|
||||
// se3.rotz(orbit.ascendingNodeLongitude),
|
||||
// se3.rotx(orbit.inclination),
|
||||
// se3.rotz(orbit.periapsisArgument),
|
||||
// ].reduce(se3.product);
|
||||
|
||||
const buffer = gl.createBuffer();
|
||||
gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
|
||||
@ -1062,7 +1034,7 @@ const kGravitationalConstant = 6.674e-11;
|
||||
|
||||
function getObjects(context, body, parentPosition) {
|
||||
const objects = [];
|
||||
const {gl, glContext} = context;
|
||||
const {gl, glContext, player} = context;
|
||||
const {position, orientation} = body;
|
||||
|
||||
if (body.glBuffer === undefined) {
|
||||
@ -1078,6 +1050,19 @@ function getObjects(context, body, parentPosition) {
|
||||
if (parentPosition !== undefined) {
|
||||
const orbitObject = makeOrbitObject(context, body.orbit, parentPosition);
|
||||
objects.push(orbitObject);
|
||||
} else {
|
||||
const shipOrientation = [
|
||||
se3.rotationOnly(player.tf),
|
||||
se3.rotationOnly(context.camera.tf),
|
||||
se3.rotxyz(-Math.PI / 2, 0, Math.PI / 2),
|
||||
].reduce(se3.product);
|
||||
const shipPos = player.position;
|
||||
objects.push({
|
||||
geometry: makeBufferFromFaces(gl, context.spaceship),
|
||||
orientation: shipOrientation,
|
||||
position: shipPos,
|
||||
glContext,
|
||||
});
|
||||
}
|
||||
|
||||
if (body.children !== undefined) {
|
||||
@ -1108,7 +1093,12 @@ function draw(context) {
|
||||
|
||||
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
|
||||
|
||||
const viewMatrix = se3.inverse(se3.product(context.player.tf, context.camera.tf));
|
||||
const viewMatrix = se3.inverse([
|
||||
context.player.tf, // player position & orientation
|
||||
|
||||
context.camera.tf, // camera orientation relative to player
|
||||
se3.translation(0, 1, 4), // step back from the player
|
||||
].reduce(se3.product));
|
||||
let lastGlContext;
|
||||
|
||||
for (const {position, orientation, geometry, glContext} of objects) {
|
||||
@ -1135,7 +1125,8 @@ function draw(context) {
|
||||
|
||||
function tick(time, context) {
|
||||
handleInput(context);
|
||||
updatePhysics(time * 0.001, context);
|
||||
const simTime = time * 0.001 + context.timeOffset;
|
||||
updatePhysics(simTime, context);
|
||||
|
||||
const campos = context.player.position;
|
||||
|
||||
@ -1198,6 +1189,15 @@ async function main() {
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO
|
||||
// [ ] loading bar
|
||||
// [ ] spaceship
|
||||
// [ ] landing
|
||||
// [ ] huge planets
|
||||
// [ ] lighting
|
||||
|
||||
const modelPromise = loadStlModel('spaceship.stl');
|
||||
|
||||
const context = {
|
||||
gl,
|
||||
projMatrix: se3.perspective(Math.PI / 3, canvas.clientWidth / canvas.clientHeight, 0.1, 10000.0),
|
||||
@ -1213,7 +1213,7 @@ async function main() {
|
||||
keys: new Set(),
|
||||
lightDirection: [-0.2, -0.5, 0.4],
|
||||
skyColor: [0.10, 0.15, 0.2],
|
||||
ambiantLight: 0.7,
|
||||
ambiantLight: 0.4,
|
||||
blockSelectDistance: 8,
|
||||
flying: true,
|
||||
isOnGround: false,
|
||||
@ -1221,6 +1221,7 @@ async function main() {
|
||||
jumpForce: 6.5,
|
||||
// objects: makeObjects(gl),
|
||||
universe: getSolarSystem(0),
|
||||
timeOffset: 0,
|
||||
};
|
||||
|
||||
context.glContext = await initWorldGl(gl);
|
||||
@ -1228,6 +1229,10 @@ async function main() {
|
||||
initUiListeners(canvas, context);
|
||||
|
||||
// setupParamPanel(context);
|
||||
const starshipGeom = await modelPromise;
|
||||
console.log(`loaded ${starshipGeom.length} triangles`);
|
||||
|
||||
context.spaceship = starshipGeom;
|
||||
|
||||
requestAnimationFrame(time => tick(time, context));
|
||||
}
|
||||
|
38
skycraft/linalg.js
Normal file
38
skycraft/linalg.js
Normal file
@ -0,0 +1,38 @@
|
||||
export function cross(a, b) {
|
||||
return [
|
||||
a[1] * b[2] - a[2] * b[1],
|
||||
a[2] * b[0] - a[0] * b[2],
|
||||
a[0] * b[1] - a[1] * b[0],
|
||||
];
|
||||
}
|
||||
|
||||
export function diff(a, b) {
|
||||
return [
|
||||
a[0] - b[0],
|
||||
a[1] - b[1],
|
||||
a[2] - b[2],
|
||||
];
|
||||
}
|
||||
|
||||
export function add(a, b) {
|
||||
return [
|
||||
a[0] + b[0],
|
||||
a[1] + b[1],
|
||||
a[2] + b[2],
|
||||
];
|
||||
}
|
||||
|
||||
export function norm(a) {
|
||||
return Math.sqrt(a[0] ** 2 + a[1] ** 2 + a[2] ** 2);
|
||||
}
|
||||
|
||||
export function dot(a, b) {
|
||||
return a[0] * b[0] + a[1] * b[1] + a[2] * b[2];
|
||||
}
|
||||
export function scale(a, s) {
|
||||
return [
|
||||
a[0] * s,
|
||||
a[1] * s,
|
||||
a[2] * s,
|
||||
];
|
||||
}
|
BIN
skycraft/spaceship.stl
Normal file
BIN
skycraft/spaceship.stl
Normal file
Binary file not shown.
76
skycraft/stl.js
Normal file
76
skycraft/stl.js
Normal file
@ -0,0 +1,76 @@
|
||||
import * as linalg from './linalg';
|
||||
|
||||
function parseTriangle(triangleData) {
|
||||
const dv = new DataView(triangleData.buffer);
|
||||
function data(idx) {
|
||||
const offset = 4 * idx;
|
||||
return dv.getFloat32(offset, /*littleEndian=*/true);
|
||||
}
|
||||
|
||||
const attributeByteCount = dv.getUint16(48, /*littleEndian=*/true);
|
||||
console.assert(attributeByteCount === 0);
|
||||
|
||||
const x = [data(3), data(4), data(5)];
|
||||
const y = [data(6), data(7), data(8)];
|
||||
const z = [data(9), data(10), data(11)];
|
||||
const n = linalg.cross(linalg.diff(y, x), linalg.diff(z, y));
|
||||
|
||||
return {
|
||||
vertices: [x, y, z],
|
||||
normals: new Array(3).fill(linalg.scale(n, 1 / linalg.norm(n))),
|
||||
textures: new Array(3).fill([0, 0]),
|
||||
}; // no normals, default texture
|
||||
}
|
||||
|
||||
export async function loadStlModel(url) {
|
||||
const stlDataStream = (await fetch(url)).body;
|
||||
const triangles = [];
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
let bytesReceived = 0;
|
||||
let gotHeader = false;
|
||||
const partial = new Uint8Array(50); // each triangle is 50 bytes
|
||||
let partialOffset = 0;
|
||||
const reader = stlDataStream.getReader();
|
||||
|
||||
function pump() {
|
||||
reader.read().then(({ done, value }) => {
|
||||
if (done) {
|
||||
return resolve(triangles);
|
||||
}
|
||||
|
||||
const skipped = bytesReceived;
|
||||
bytesReceived += value.length;
|
||||
let inputOffset = 0;
|
||||
|
||||
if (!gotHeader) {
|
||||
if (bytesReceived < 84) { // header + triangle count
|
||||
return pump();
|
||||
} else {
|
||||
gotHeader = true;
|
||||
inputOffset = 84 - skipped;
|
||||
}
|
||||
}
|
||||
|
||||
// parse triangle data
|
||||
while (true) {
|
||||
const spaceLeft = 50 - partialOffset;
|
||||
console.assert(spaceLeft > 0);
|
||||
|
||||
const leftToCopy = value.length - inputOffset;
|
||||
const toCopy = value.subarray(inputOffset, inputOffset + Math.min(leftToCopy, spaceLeft));
|
||||
partial.set(toCopy, partialOffset);
|
||||
if (leftToCopy < spaceLeft) {
|
||||
break;
|
||||
}
|
||||
// parse a triangle!
|
||||
triangles.push(parseTriangle(partial));
|
||||
partialOffset = 0;
|
||||
inputOffset += toCopy.length;
|
||||
}
|
||||
pump();
|
||||
});
|
||||
}
|
||||
pump();
|
||||
});
|
||||
}
|
Loading…
Reference in New Issue
Block a user