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:
		@@ -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();
 | 
			
		||||
    });
 | 
			
		||||
}
 | 
			
		||||
		Reference in New Issue
	
	Block a user