Block tagging

This commit is contained in:
Paul Mathieu 2021-12-17 06:16:57 -08:00
parent 612f8a223e
commit fff1fe89a2
3 changed files with 132 additions and 2 deletions

124
index.js
View File

@ -1,6 +1,7 @@
import { loadTexture, makeProgram } from "./gl";
import { blockLookup, BlockType, generateMissingChunks, makeWorld, updateWorldGeometry } from './world';
import * as se3 from './se3';
import { makeBufferFromFaces, makeFace } from "./geometry";
const TEST_VSHADER = `
attribute vec3 aPosition;
@ -62,6 +63,8 @@ function draw(gl, params, objects) {
gl.enable(gl.CULL_FACE);
gl.cullFace(gl.BACK);
gl.enable(gl.BLEND);
gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA);
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
@ -196,6 +199,34 @@ function updatePhysics(params) {
params.isOnGround = isOnGround;
}
function tagABlock(gl, params, objects) {
const dir = [0, 0, -1, 1.0];
const camori = params.camera.orientation;
const ori = se3.inverse(se3.rotxyz(-camori[0], -camori[1], -camori[2]));
const viewDirection = se3.apply(ori, dir).slice(0, 3);
const face = markBlock(params.world, params.camera.position, viewDirection);
if (face === undefined) {
return;
}
if (params.tagBuffer !== undefined) {
gl.deleteBuffer(params.tagBuffer.glBuffer);
delete params.tagBuffer;
}
const buffer = makeBufferFromFaces(gl, [face]);
params.tagBuffer = buffer;
const obj = {
position: [0.0, 0.0, 0.0],
orientation: [0.0, 0.0, 0.0],
geometry: buffer,
glContext: params.worldGl,
};
objects.push(obj);
}
function tick(time, gl, params) {
handleKeys(params);
updatePhysics(params);
@ -218,6 +249,9 @@ function tick(time, gl, params) {
}
const objects = getObjects(params.world, campos[2], campos[0], params.worldGl);
tagABlock(gl, params, objects);
draw(gl, params, objects);
const dt = (time - stuff.lastFrameTime) * 0.001;
@ -278,13 +312,99 @@ function checkCollision(curPos, newPos, world) {
};
}
function minIndex(arr) {
return arr.reduce((min, val, i) => val >= arr[min] ? min : i, -1);
}
function movePoint(p, s, u) {
return [p[0] + s * u[0], p[1] + s * u[1], p[2] + s * u[2]];
}
function rayThroughGrid(origin, direction, maxDistance) {
const range = i => [...Array(i).keys()];
const length = p => Math.sqrt(p[0] * p[0] + p[1] * p[1] + p[2] * [2]);
const nextGrid = range(3).map(i => direction[i] > 0 ?
Math.floor(origin[i] + 0.5) + 0.5 :
Math.floor(origin[i] + 0.5) - 0.5);
const distanceToGrid = range(3).map(i => (nextGrid[i] - origin[i]) / direction[i])
.map(v => v === 0.0 ? Number.POSITIVE_INFINITY : v);
const axis = minIndex(distanceToGrid);
const rayLength = distanceToGrid[axis];
if (rayLength > maxDistance) {
return {};
}
const position = movePoint(origin, distanceToGrid[axis], direction);
const normal = range(3).map(i => i === axis ? -Math.sign(direction[i]) : 0);
return {position, normal, distance: rayLength};
}
function castRay(world, origin, direction, maxDistance) {
let currentPoint = origin;
while (maxDistance > 0) {
const {position, normal, distance} = rayThroughGrid(currentPoint, direction, maxDistance);
if (position === undefined) {
return;
}
maxDistance -= distance;
currentPoint = position;
const blockCenter = movePoint(position, -0.5, normal);
const block = blockLookup(world, ...blockCenter);
if (block.type === BlockType.AIR) {
continue;
}
return {
block,
normal,
};
}
}
function markBlock(world, cameraPosition, direction) {
const maxDistance = 10;
const hit = castRay(world, cameraPosition, direction, maxDistance);
if (hit === undefined) {
return;
}
const texture = [0, 14];
const {normal, block} = hit;
const faceCenter = movePoint(block.centerPosition, 0.51, normal);
if (normal[0] > 0) {
return makeFace('+x', texture, faceCenter);
} else if (normal[0] < 0) {
return makeFace('-x', texture, faceCenter);
} else if (normal[1] > 0) {
return makeFace('+y', texture, faceCenter);
} else if (normal[1] < 0) {
return makeFace('-y', texture, faceCenter);
} else if (normal[2] > 0) {
return makeFace('+z', texture, faceCenter);
} else if (normal[2] < 0) {
return makeFace('-z', texture, faceCenter);
}
}
// Mine & place
// ------------
// [ ] ray casting
// [ ] block outline
// [x] ray casting
// [x] block outline
// [ ] crosshair
// [ ] dynamic terrain re-rendering
// [ ] should use a linked list of air contact blocks
// --> might not be needed. Only need to re-render a single chunk,
// should be fast enough. We render 16 of them every time we
// walk 16 blocks in any direction.
// Stuff I need to do:
// [x] a skybox

10
se3.js
View File

@ -68,6 +68,16 @@ export function translation(x, y, z) {
];
}
export function inverse(m) {
// TODO: translation
return [
m[0], m[4], m[8], 0.0,
m[1], m[5], m[9], 0.0,
m[2], m[6], m[10], 0.0,
0, 0, 0, 1,
];
}
export function product(a, b) {
const c = (i, j) => (
a[4 * 0 + i] * b[4 * j + 0] +

Binary file not shown.

Before

Width:  |  Height:  |  Size: 39 KiB

After

Width:  |  Height:  |  Size: 39 KiB