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) {
|
function* makeChunkFaces(chunk) {
|
||||||
const cs = CHUNKSIZE;
|
const cs = CHUNKSIZE;
|
||||||
|
|
||||||
function faceCenter(pos: linalg.vec3, dir: direction) {
|
function faceCenter(pos: linalg.Vec3, dir: direction) {
|
||||||
switch (dir) {
|
switch (dir) {
|
||||||
case '-x': return [pos[0] - 0.5, pos[1], pos[2]];
|
case '-x': return [pos[0] - 0.5, pos[1], pos[2]];
|
||||||
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 {
|
} else {
|
||||||
const shipOrientation = [
|
const shipOrientation = [
|
||||||
se3.rotationOnly(player.tf),
|
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),
|
se3.rotxyz(-Math.PI / 2, Math.PI / 2, Math.PI / 2),
|
||||||
].reduce(se3.product);
|
].reduce(se3.product);
|
||||||
const shipPos = player.position;
|
const shipPos = player.position;
|
||||||
@ -280,7 +280,7 @@ function getObjects(context, body, parentPosition = undefined) {
|
|||||||
return objects;
|
return objects;
|
||||||
}
|
}
|
||||||
|
|
||||||
function sunDirection(position: linalg.vec3) {
|
function sunDirection(position: linalg.Vec3) {
|
||||||
return linalg.scale(position, 1/linalg.norm(position));
|
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 { computeOrbit, findSoi, getCartesianState, updateBodyPhysics } from './orbit';
|
||||||
import { getBodyGeometry } from './chunk';
|
import { getBodyGeometry } from './chunk';
|
||||||
import { draw, getOrbitDrawContext, initWorldGl } from './draw';
|
import { draw, getOrbitDrawContext, initWorldGl } from './draw';
|
||||||
|
import * as quat from './quat';
|
||||||
|
|
||||||
const kEpoch = 0;
|
const kEpoch = 0;
|
||||||
|
|
||||||
@ -175,12 +176,13 @@ function initUiListeners(canvas: HTMLCanvasElement, context) {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
const moveListener = e => {
|
const moveListener = e => {
|
||||||
context.camera.orientation[0] -= e.movementY / 500;
|
// context.camera.orientation[0] -= e.movementY / 500;
|
||||||
context.camera.orientation[1] -= e.movementX / 500;
|
// context.camera.orientation[1] -= e.movementX / 500;
|
||||||
context.camera.tf = se3.product(
|
context.camera.tf =[
|
||||||
se3.roty(context.camera.orientation[1]),
|
context.camera.tf,
|
||||||
se3.rotx(context.camera.orientation[0]),
|
se3.roty(-e.movementX / 500),
|
||||||
);
|
se3.rotx(-e.movementY / 500),
|
||||||
|
].reduce(se3.product);
|
||||||
};
|
};
|
||||||
const changeListener = () => {
|
const changeListener = () => {
|
||||||
if (document.pointerLockElement === canvas) {
|
if (document.pointerLockElement === canvas) {
|
||||||
@ -224,11 +226,8 @@ function handleInput(context) {
|
|||||||
if (context.flying) {
|
if (context.flying) {
|
||||||
context.player.tf = [
|
context.player.tf = [
|
||||||
context.player.tf,
|
context.player.tf,
|
||||||
context.camera.tf,
|
|
||||||
se3.translation(...dir),
|
se3.translation(...dir),
|
||||||
].reduce(se3.product);
|
].reduce(se3.product);
|
||||||
context.camera.tf = se3.identity();
|
|
||||||
context.camera.orientation = [0, 0, 0];
|
|
||||||
} else {
|
} else {
|
||||||
const vel = context.player.velocity;
|
const vel = context.player.velocity;
|
||||||
const dv = linalg.scale(se3.apply(tf, dir), 1/dir[3]);
|
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) {
|
function updatePhysics(time: number, context) {
|
||||||
const {player} = context;
|
const {player} = context;
|
||||||
const dt = time - (context.lastTime || 0);
|
const dt = time - (context.lastTime || 0);
|
||||||
@ -267,6 +277,10 @@ function updatePhysics(time: number, context) {
|
|||||||
|
|
||||||
updateBodyPhysics(time, context.universe);
|
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.flying) {
|
||||||
if (context.orbit === undefined) {
|
if (context.orbit === undefined) {
|
||||||
const newPos = linalg.add(player.position, linalg.scale(player.velocity, dt));
|
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) {
|
function updateGeometry(context, timeout_ms = 10) {
|
||||||
@ -304,8 +317,6 @@ function tick(time: number, context) {
|
|||||||
const simTime = time * 0.001 + context.timeOffset;
|
const simTime = time * 0.001 + context.timeOffset;
|
||||||
updatePhysics(simTime, context);
|
updatePhysics(simTime, context);
|
||||||
|
|
||||||
const campos = context.player.position;
|
|
||||||
|
|
||||||
// world generation / geometry update
|
// world generation / geometry update
|
||||||
{
|
{
|
||||||
// frame time is typically 16.7ms, so this may lag a bit
|
// 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 [
|
return [
|
||||||
a[1] * b[2] - a[2] * b[1],
|
a[1] * b[2] - a[2] * b[1],
|
||||||
a[2] * b[0] - a[0] * b[2],
|
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 [
|
return [
|
||||||
a[0] - b[0],
|
a[0] - b[0],
|
||||||
a[1] - b[1],
|
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 [
|
return [
|
||||||
a[0] + b[0],
|
a[0] + b[0],
|
||||||
a[1] + b[1],
|
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);
|
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];
|
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 [
|
return [
|
||||||
a[0] * s,
|
a[0] * s,
|
||||||
a[1] * s,
|
a[1] * s,
|
||||||
|
@ -1,9 +1,6 @@
|
|||||||
import * as se3 from '../se3';
|
import * as se3 from '../se3';
|
||||||
import * as linalg from './linalg';
|
import * as linalg from './linalg';
|
||||||
import {vec3} from './linalg';
|
import {Vec3} from './linalg';
|
||||||
|
|
||||||
type mat4 = number[];
|
|
||||||
type vec4 = [number, number, number, number];
|
|
||||||
|
|
||||||
interface Orbit {
|
interface Orbit {
|
||||||
excentricity: number,
|
excentricity: number,
|
||||||
@ -18,13 +15,13 @@ interface Orbit {
|
|||||||
}
|
}
|
||||||
|
|
||||||
interface Body {
|
interface Body {
|
||||||
position: vec3,
|
position: Vec3,
|
||||||
velocity: vec3,
|
velocity: Vec3,
|
||||||
orientation: vec4,
|
orientation: Vec3,
|
||||||
children: Body[],
|
children: Body[],
|
||||||
mass: number,
|
mass: number,
|
||||||
orbit: Orbit,
|
orbit: Orbit,
|
||||||
spin: vec3,
|
spin: Vec3,
|
||||||
name: string,
|
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