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 { loadTexture, makeProgram } from "./gl";
|
||||||
import { blockLookup, BlockType, generateMissingChunks, makeWorld, updateWorldGeometry } from './world';
|
import { blockLookup, BlockType, generateMissingChunks, makeWorld, updateWorldGeometry } from './world';
|
||||||
import * as se3 from './se3';
|
import * as se3 from './se3';
|
||||||
|
import { makeBufferFromFaces, makeFace } from "./geometry";
|
||||||
|
|
||||||
const TEST_VSHADER = `
|
const TEST_VSHADER = `
|
||||||
attribute vec3 aPosition;
|
attribute vec3 aPosition;
|
||||||
@ -62,6 +63,8 @@ function draw(gl, params, objects) {
|
|||||||
|
|
||||||
gl.enable(gl.CULL_FACE);
|
gl.enable(gl.CULL_FACE);
|
||||||
gl.cullFace(gl.BACK);
|
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);
|
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
|
||||||
|
|
||||||
@ -196,6 +199,34 @@ function updatePhysics(params) {
|
|||||||
params.isOnGround = isOnGround;
|
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) {
|
function tick(time, gl, params) {
|
||||||
handleKeys(params);
|
handleKeys(params);
|
||||||
updatePhysics(params);
|
updatePhysics(params);
|
||||||
@ -218,6 +249,9 @@ function tick(time, gl, params) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const objects = getObjects(params.world, campos[2], campos[0], params.worldGl);
|
const objects = getObjects(params.world, campos[2], campos[0], params.worldGl);
|
||||||
|
|
||||||
|
tagABlock(gl, params, objects);
|
||||||
|
|
||||||
draw(gl, params, objects);
|
draw(gl, params, objects);
|
||||||
|
|
||||||
const dt = (time - stuff.lastFrameTime) * 0.001;
|
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
|
// Mine & place
|
||||||
// ------------
|
// ------------
|
||||||
// [ ] ray casting
|
// [x] ray casting
|
||||||
// [ ] block outline
|
// [x] block outline
|
||||||
// [ ] crosshair
|
// [ ] crosshair
|
||||||
// [ ] dynamic terrain re-rendering
|
// [ ] dynamic terrain re-rendering
|
||||||
// [ ] should use a linked list of air contact blocks
|
// [ ] 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:
|
// Stuff I need to do:
|
||||||
// [x] a skybox
|
// [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) {
|
export function product(a, b) {
|
||||||
const c = (i, j) => (
|
const c = (i, j) => (
|
||||||
a[4 * 0 + i] * b[4 * j + 0] +
|
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