skycraft: smoother ship controls
This commit is contained in:
parent
c709b1308e
commit
f86697aad8
@ -138,7 +138,7 @@ function faceTexture(type: number, dir: direction) {
|
||||
function* makeChunkFaces(chunk) {
|
||||
const cs = CHUNKSIZE;
|
||||
|
||||
function faceCenter(pos: linalg.vec3, dir: direction) {
|
||||
function faceCenter(pos: linalg.Vec3, dir: direction) {
|
||||
switch (dir) {
|
||||
case '-x': return [pos[0] - 0.5, pos[1], pos[2]];
|
||||
case '+x': return [pos[0] + 0.5, pos[1], pos[2]];
|
||||
|
@ -259,7 +259,7 @@ function getObjects(context, body, parentPosition = undefined) {
|
||||
} else {
|
||||
const shipOrientation = [
|
||||
se3.rotationOnly(player.tf),
|
||||
se3.rotationOnly(context.camera.tf),
|
||||
//se3.rotationOnly(context.camera.tf),
|
||||
se3.rotxyz(-Math.PI / 2, Math.PI / 2, Math.PI / 2),
|
||||
].reduce(se3.product);
|
||||
const shipPos = player.position;
|
||||
@ -280,7 +280,7 @@ function getObjects(context, body, parentPosition = undefined) {
|
||||
return objects;
|
||||
}
|
||||
|
||||
function sunDirection(position: linalg.vec3) {
|
||||
function sunDirection(position: linalg.Vec3) {
|
||||
return linalg.scale(position, 1/linalg.norm(position));
|
||||
}
|
||||
|
||||
|
@ -6,6 +6,7 @@ import * as se3 from '../se3';
|
||||
import { computeOrbit, findSoi, getCartesianState, updateBodyPhysics } from './orbit';
|
||||
import { getBodyGeometry } from './chunk';
|
||||
import { draw, getOrbitDrawContext, initWorldGl } from './draw';
|
||||
import * as quat from './quat';
|
||||
|
||||
const kEpoch = 0;
|
||||
|
||||
@ -175,12 +176,13 @@ function initUiListeners(canvas: HTMLCanvasElement, context) {
|
||||
}
|
||||
};
|
||||
const moveListener = e => {
|
||||
context.camera.orientation[0] -= e.movementY / 500;
|
||||
context.camera.orientation[1] -= e.movementX / 500;
|
||||
context.camera.tf = se3.product(
|
||||
se3.roty(context.camera.orientation[1]),
|
||||
se3.rotx(context.camera.orientation[0]),
|
||||
);
|
||||
// context.camera.orientation[0] -= e.movementY / 500;
|
||||
// context.camera.orientation[1] -= e.movementX / 500;
|
||||
context.camera.tf =[
|
||||
context.camera.tf,
|
||||
se3.roty(-e.movementX / 500),
|
||||
se3.rotx(-e.movementY / 500),
|
||||
].reduce(se3.product);
|
||||
};
|
||||
const changeListener = () => {
|
||||
if (document.pointerLockElement === canvas) {
|
||||
@ -224,11 +226,8 @@ function handleInput(context) {
|
||||
if (context.flying) {
|
||||
context.player.tf = [
|
||||
context.player.tf,
|
||||
context.camera.tf,
|
||||
se3.translation(...dir),
|
||||
].reduce(se3.product);
|
||||
context.camera.tf = se3.identity();
|
||||
context.camera.orientation = [0, 0, 0];
|
||||
} else {
|
||||
const vel = context.player.velocity;
|
||||
const dv = linalg.scale(se3.apply(tf, dir), 1/dir[3]);
|
||||
@ -258,6 +257,17 @@ function handleInput(context) {
|
||||
});
|
||||
}
|
||||
|
||||
function slerp(current: linalg.Mat4, target: linalg.Mat4, maxVelocity: number) : linalg.Mat4 {
|
||||
const q0 = quat.mat2Quat(current);
|
||||
const q1 = quat.mat2Quat(target);
|
||||
|
||||
const dq = quat.diff(q1, q0);
|
||||
const maxt = maxVelocity / quat.norm(dq);
|
||||
|
||||
const q = quat.normalize(quat.add(q0, quat.scale(dq, Math.min(1, maxt))));
|
||||
return quat.quat2Mat(q);
|
||||
}
|
||||
|
||||
function updatePhysics(time: number, context) {
|
||||
const {player} = context;
|
||||
const dt = time - (context.lastTime || 0);
|
||||
@ -267,6 +277,10 @@ function updatePhysics(time: number, context) {
|
||||
|
||||
updateBodyPhysics(time, context.universe);
|
||||
|
||||
const dr = slerp(se3.identity(), context.camera.tf, 0.007);
|
||||
player.tf = se3.product(player.tf, dr);
|
||||
context.camera.tf = se3.product(context.camera.tf, se3.inverse(dr));
|
||||
|
||||
if (!context.flying) {
|
||||
if (context.orbit === undefined) {
|
||||
const newPos = linalg.add(player.position, linalg.scale(player.velocity, dt));
|
||||
@ -293,7 +307,6 @@ function updatePhysics(time: number, context) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
function updateGeometry(context, timeout_ms = 10) {
|
||||
@ -304,8 +317,6 @@ function tick(time: number, context) {
|
||||
const simTime = time * 0.001 + context.timeOffset;
|
||||
updatePhysics(simTime, context);
|
||||
|
||||
const campos = context.player.position;
|
||||
|
||||
// world generation / geometry update
|
||||
{
|
||||
// frame time is typically 16.7ms, so this may lag a bit
|
||||
|
@ -1,6 +1,7 @@
|
||||
export type vec3 = [number, number, number];
|
||||
export type Vec3 = [number, number, number];
|
||||
export type Mat4 = number[];
|
||||
|
||||
export function cross(a: vec3, b: vec3) : vec3 {
|
||||
export function cross(a: Vec3, b: Vec3) : Vec3 {
|
||||
return [
|
||||
a[1] * b[2] - a[2] * b[1],
|
||||
a[2] * b[0] - a[0] * b[2],
|
||||
@ -8,7 +9,7 @@ export function cross(a: vec3, b: vec3) : vec3 {
|
||||
];
|
||||
}
|
||||
|
||||
export function diff(a: vec3, b: vec3) : vec3 {
|
||||
export function diff(a: Vec3, b: Vec3) : Vec3 {
|
||||
return [
|
||||
a[0] - b[0],
|
||||
a[1] - b[1],
|
||||
@ -16,7 +17,7 @@ export function diff(a: vec3, b: vec3) : vec3 {
|
||||
];
|
||||
}
|
||||
|
||||
export function add(a: vec3, b: vec3) : vec3 {
|
||||
export function add(a: Vec3, b: Vec3) : Vec3 {
|
||||
return [
|
||||
a[0] + b[0],
|
||||
a[1] + b[1],
|
||||
@ -24,14 +25,14 @@ export function add(a: vec3, b: vec3) : vec3 {
|
||||
];
|
||||
}
|
||||
|
||||
export function norm(a: vec3) : number {
|
||||
export function norm(a: Vec3) : number {
|
||||
return Math.sqrt(a[0] ** 2 + a[1] ** 2 + a[2] ** 2);
|
||||
}
|
||||
|
||||
export function dot(a: vec3, b: vec3) : number {
|
||||
export function dot(a: Vec3, b: Vec3) : number {
|
||||
return a[0] * b[0] + a[1] * b[1] + a[2] * b[2];
|
||||
}
|
||||
export function scale(a: vec3, s: number) : vec3 {
|
||||
export function scale(a: Vec3, s: number) : Vec3 {
|
||||
return [
|
||||
a[0] * s,
|
||||
a[1] * s,
|
||||
|
@ -1,9 +1,6 @@
|
||||
import * as se3 from '../se3';
|
||||
import * as linalg from './linalg';
|
||||
import {vec3} from './linalg';
|
||||
|
||||
type mat4 = number[];
|
||||
type vec4 = [number, number, number, number];
|
||||
import {Vec3} from './linalg';
|
||||
|
||||
interface Orbit {
|
||||
excentricity: number,
|
||||
@ -18,13 +15,13 @@ interface Orbit {
|
||||
}
|
||||
|
||||
interface Body {
|
||||
position: vec3,
|
||||
velocity: vec3,
|
||||
orientation: vec4,
|
||||
position: Vec3,
|
||||
velocity: Vec3,
|
||||
orientation: Vec3,
|
||||
children: Body[],
|
||||
mass: number,
|
||||
orbit: Orbit,
|
||||
spin: vec3,
|
||||
spin: Vec3,
|
||||
name: string,
|
||||
}
|
||||
|
||||
|
124
skycraft/quat.ts
Normal file
124
skycraft/quat.ts
Normal file
@ -0,0 +1,124 @@
|
||||
import {Mat4} from './linalg';
|
||||
import * as se3 from '../se3';
|
||||
|
||||
export interface Quat {
|
||||
x: number,
|
||||
y: number,
|
||||
z: number,
|
||||
w: number,
|
||||
}
|
||||
|
||||
export function mat2Quat(m: Mat4) : Quat {
|
||||
const q : Quat = {};
|
||||
|
||||
if (m[0 * 4 + 0] + m[1 * 4 + 1] + m[2 * 4 + 2] > 0.0) {
|
||||
const t = + m[0 * 4 + 0] + m[1 * 4 + 1] + m[2 * 4 + 2] + 1.0;
|
||||
const s = 0.5 / Math.sqrt(t);
|
||||
q.w = s * t;
|
||||
q.z = (m[1 * 4 + 0] - m[0 * 4 + 1]) * s;
|
||||
q.y = (m[0 * 4 + 2] - m[2 * 4 + 0]) * s;
|
||||
q.x = (m[2 * 4 + 1] - m[1 * 4 + 2]) * s;
|
||||
} else if (m[0 * 4 + 0] > m[1 * 4 + 1] && m[0 * 4 + 0] > m[2 * 4 + 2]) {
|
||||
const t = + m[0 * 4 + 0] - m[1 * 4 + 1] - m[2 * 4 + 2] + 1.0;
|
||||
const s = 0.5 / Math.sqrt(t);
|
||||
q.x = s * t;
|
||||
q.y = (m[1 * 4 + 0] + m[0 * 4 + 1]) * s;
|
||||
q.z = (m[0 * 4 + 2] + m[2 * 4 + 0]) * s;
|
||||
q.w = (m[2 * 4 + 1] - m[1 * 4 + 2]) * s;
|
||||
} else if (m[1 * 4 + 1] > m[2 * 4 + 2]) {
|
||||
const t = - m[0 * 4 + 0] + m[1 * 4 + 1] - m[2 * 4 + 2] + 1.0;
|
||||
const s = 0.5 / Math.sqrt(t);
|
||||
q.y = s * t;
|
||||
q.x = (m[1 * 4 + 0] + m[0 * 4 + 1]) * s;
|
||||
q.w = (m[0 * 4 + 2] - m[2 * 4 + 0]) * s;
|
||||
q.z = (m[2 * 4 + 1] + m[1 * 4 + 2]) * s;
|
||||
} else {
|
||||
const t = - m[0 * 4 + 0] - m[1 * 4 + 1] + m[2 * 4 + 2] + 1.0;
|
||||
const s = 0.5 / Math.sqrt(t);
|
||||
q.z = s * t;
|
||||
q.w = (m[1 * 4 + 0] - m[0 * 4 + 1]) * s;
|
||||
q.x = (m[0 * 4 + 2] + m[2 * 4 + 0]) * s;
|
||||
q.y = (m[2 * 4 + 1] + m[1 * 4 + 2]) * s;
|
||||
}
|
||||
|
||||
return q;
|
||||
}
|
||||
|
||||
export function quat2Mat(q: Quat): Mat4 {
|
||||
const m: Mat4 = se3.identity();
|
||||
|
||||
const x2 = q.x + q.x;
|
||||
const y2 = q.y + q.y;
|
||||
const z2 = q.z + q.z;
|
||||
{
|
||||
const xx2 = q.x * x2;
|
||||
const yy2 = q.y * y2;
|
||||
const zz2 = q.z * z2;
|
||||
m[0 * 4 + 0] = 1.0 - yy2 - zz2;
|
||||
m[1 * 4 + 1] = 1.0 - xx2 - zz2;
|
||||
m[2 * 4 + 2] = 1.0 - xx2 - yy2;
|
||||
}
|
||||
{
|
||||
const yz2 = q.y * z2;
|
||||
const wx2 = q.w * x2;
|
||||
m[1 * 4 + 2] = yz2 - wx2;
|
||||
m[2 * 4 + 1] = yz2 + wx2;
|
||||
}
|
||||
{
|
||||
const xy2 = q.x * y2;
|
||||
const wz2 = q.w * z2;
|
||||
m[0 * 4 + 1] = xy2 - wz2;
|
||||
m[1 * 4 + 0] = xy2 + wz2;
|
||||
}
|
||||
{
|
||||
const xz2 = q.x * z2;
|
||||
const wy2 = q.w * y2;
|
||||
m[2 * 4 + 0] = xz2 - wy2;
|
||||
m[0 * 4 + 2] = xz2 + wy2;
|
||||
}
|
||||
|
||||
return m;
|
||||
}
|
||||
|
||||
export function normalize(q: Quat) : Quat {
|
||||
const n = norm(q);
|
||||
if (n < 1e-10) {
|
||||
return {x: 0, y: 0, z: 0, w: 1};
|
||||
}
|
||||
return {
|
||||
x: q.x / n,
|
||||
y: q.y / n,
|
||||
z: q.z / n,
|
||||
w: q.w / n,
|
||||
};
|
||||
}
|
||||
|
||||
export function diff(q0: Quat, q1: Quat) {
|
||||
return {
|
||||
x: q0.x - q1.x,
|
||||
y: q0.y - q1.y,
|
||||
z: q0.z - q1.z,
|
||||
w: q0.w - q1.w,
|
||||
};
|
||||
}
|
||||
export function norm(q: Quat) {
|
||||
return Math.sqrt(q.x**2 + q.y**2 + q.z**2 + q.w**2);
|
||||
}
|
||||
|
||||
export function add(q0: Quat, q1: Quat) {
|
||||
return {
|
||||
x: q0.x + q1.x,
|
||||
y: q0.y + q1.y,
|
||||
z: q0.z + q1.z,
|
||||
w: q0.w + q1.w,
|
||||
};
|
||||
}
|
||||
|
||||
export function scale(q: Quat, a: number): Quat {
|
||||
return {
|
||||
x: a * q.x,
|
||||
y: a * q.y,
|
||||
z: a * q.z,
|
||||
w: a * q.w,
|
||||
};
|
||||
}
|
Loading…
Reference in New Issue
Block a user