Block tagging
This commit is contained in:
parent
612f8a223e
commit
fff1fe89a2
124
index.js
124
index.js
@ -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
10
se3.js
@ -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] +
|
||||
|
BIN
texture.png
BIN
texture.png
Binary file not shown.
Before Width: | Height: | Size: 39 KiB After Width: | Height: | Size: 39 KiB |
Loading…
Reference in New Issue
Block a user