skycraft: optimize mesh generation
This commit is contained in:
parent
b0a39bb1ce
commit
e27151b796
@ -5,6 +5,7 @@ import {loadTexture, makeProgram} from '../gl';
|
|||||||
import {makeFace, makeBufferFromFaces} from '../geometry';
|
import {makeFace, makeBufferFromFaces} from '../geometry';
|
||||||
import { loadStlModel } from './stl';
|
import { loadStlModel } from './stl';
|
||||||
import * as linalg from './linalg';
|
import * as linalg from './linalg';
|
||||||
|
import { memoize } from '../memoize';
|
||||||
|
|
||||||
const VSHADER = `
|
const VSHADER = `
|
||||||
attribute vec3 aPosition;
|
attribute vec3 aPosition;
|
||||||
@ -243,7 +244,7 @@ const CHUNKSIZE = 32;
|
|||||||
*
|
*
|
||||||
* returns: a chunk
|
* returns: a chunk
|
||||||
*/
|
*/
|
||||||
function getChunk(seed, x, y, z) {
|
function makeDirtBlock(seed, x, y, z) {
|
||||||
// XXX: for now, return a premade chunk: a 24x24x24 cube of dirt
|
// XXX: for now, return a premade chunk: a 24x24x24 cube of dirt
|
||||||
// surrounded by 4 blocks of air all around
|
// surrounded by 4 blocks of air all around
|
||||||
const cs = CHUNKSIZE;
|
const cs = CHUNKSIZE;
|
||||||
@ -271,15 +272,83 @@ function getChunk(seed, x, y, z) {
|
|||||||
position: [-half, -half, -half],
|
position: [-half, -half, -half],
|
||||||
blocks,
|
blocks,
|
||||||
underground: false,
|
underground: false,
|
||||||
|
seed,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
function getBodyChunks(seed) {
|
function makeSunChunk(seed, i, j, k) {
|
||||||
if (seed === 0) {
|
const cs = CHUNKSIZE;
|
||||||
return makeSun();
|
const radius = 42;
|
||||||
|
if (Math.abs(cs * i) > radius
|
||||||
|
|| Math.abs(cs * j) > radius
|
||||||
|
|| Math.abs(cs * k) > radius) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
const half = cs / 2;
|
||||||
|
const blocks = new Array(cs**3);
|
||||||
|
blocks.fill(BlockType.SUN);
|
||||||
|
|
||||||
|
let underground = true;
|
||||||
|
|
||||||
|
for (let x = 0; x < cs; x++) {
|
||||||
|
for (let y = 0; y < cs; y++) {
|
||||||
|
for (let z = 0; z < cs; z++) {
|
||||||
|
const pos = [
|
||||||
|
x + i * cs - half,
|
||||||
|
y + j * cs - half,
|
||||||
|
z + k * cs - half,
|
||||||
|
];
|
||||||
|
const idx = (
|
||||||
|
z * cs * cs +
|
||||||
|
y * cs +
|
||||||
|
x
|
||||||
|
);
|
||||||
|
if (pos[0]**2 + pos[1]**2 + pos[2]**2 > radius**2) {
|
||||||
|
blocks[idx] = BlockType.AIR;
|
||||||
|
underground = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return [getChunk(seed, 0, 0, 0)];
|
return {
|
||||||
|
position: [i * cs - half, j * cs - half, k * cs - half],
|
||||||
|
layout: [i, j, k],
|
||||||
|
blocks,
|
||||||
|
seed,
|
||||||
|
underground,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function _getChunk(seed, chunkX, chunkY, chunkZ) {
|
||||||
|
if (seed === 0) {
|
||||||
|
return makeSunChunk(seed, chunkX, chunkY, chunkZ);
|
||||||
|
}
|
||||||
|
if (chunkX === 0 && chunkY === 0 && chunkZ === 0) {
|
||||||
|
return makeDirtBlock(seed); // x, y, z unused right now
|
||||||
|
}
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
const getChunk = memoize(_getChunk);
|
||||||
|
|
||||||
|
function getBodyChunks(seed) {
|
||||||
|
const chunks = [];
|
||||||
|
const toCheck = [[0, 0, 0]];
|
||||||
|
while (toCheck.length > 0) {
|
||||||
|
const [chunkX, chunkY, chunkZ] = toCheck.pop();
|
||||||
|
const thisChunk = getChunk(seed, chunkX, chunkY, chunkZ);
|
||||||
|
if (thisChunk === undefined || chunks.includes(thisChunk)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
chunks.push(thisChunk);
|
||||||
|
toCheck.push([chunkX - 1, chunkY, chunkZ]);
|
||||||
|
toCheck.push([chunkX + 1, chunkY, chunkZ]);
|
||||||
|
toCheck.push([chunkX, chunkY - 1, chunkZ]);
|
||||||
|
toCheck.push([chunkX, chunkY + 1, chunkZ]);
|
||||||
|
toCheck.push([chunkX, chunkY, chunkZ - 1]);
|
||||||
|
toCheck.push([chunkX, chunkY, chunkZ + 1]);
|
||||||
|
}
|
||||||
|
return chunks;
|
||||||
}
|
}
|
||||||
|
|
||||||
function faceTexture(type, dir) {
|
function faceTexture(type, dir) {
|
||||||
@ -320,6 +389,49 @@ function* makeChunkFaces(chunk) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function neighborChunk(dir) {
|
||||||
|
const [chunkX, chunkY, chunkZ] = chunk.layout;
|
||||||
|
if (chunk.neighbors === undefined) {
|
||||||
|
chunk.neighbors = {};
|
||||||
|
}
|
||||||
|
if (!(dir in chunk.neighbors)) {
|
||||||
|
if (dir === '-x') {
|
||||||
|
chunk.neighbors[dir] = getChunk(chunk.seed, chunkX - 1, chunkY, chunkZ);
|
||||||
|
} else if (dir === '+x') {
|
||||||
|
chunk.neighbors[dir] = getChunk(chunk.seed, chunkX + 1, chunkY, chunkZ);
|
||||||
|
} else if (dir === '-y') {
|
||||||
|
chunk.neighbors[dir] = getChunk(chunk.seed, chunkX, chunkY - 1, chunkZ);
|
||||||
|
} else if (dir === '+y') {
|
||||||
|
chunk.neighbors[dir] = getChunk(chunk.seed, chunkX, chunkY + 1, chunkZ);
|
||||||
|
} else if (dir === '-z') {
|
||||||
|
chunk.neighbors[dir] = getChunk(chunk.seed, chunkX, chunkY, chunkZ - 1);
|
||||||
|
} else if (dir === '+z') {
|
||||||
|
chunk.neighbors[dir] = getChunk(chunk.seed, chunkX, chunkY, chunkZ + 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return chunk.neighbors[dir];
|
||||||
|
}
|
||||||
|
|
||||||
|
const neighborIndices = {
|
||||||
|
'-x': (x, y, z) => z * cs * cs + y * cs + (cs - 1),
|
||||||
|
'+x': (x, y, z) => z * cs * cs + y * cs + 0,
|
||||||
|
'-y': (x, y, z) => z * cs * cs + (cs - 1) * cs + x,
|
||||||
|
'+y': (x, y, z) => z * cs * cs + 0 * cs + x,
|
||||||
|
'-z': (x, y, z) => (cs - 1) * cs * cs + y * cs + x,
|
||||||
|
'+z': (x, y, z) => 0 * cs * cs + y * cs + x,
|
||||||
|
};
|
||||||
|
|
||||||
|
function neighborBlock(dir, x, y, z) {
|
||||||
|
const neighbor = neighborChunk(dir);
|
||||||
|
let block;
|
||||||
|
if (neighbor === undefined) {
|
||||||
|
block = BlockType.AIR;
|
||||||
|
} else {
|
||||||
|
block = neighbor.blocks[neighborIndices[dir](x, y, z)];
|
||||||
|
}
|
||||||
|
return { dir, block };
|
||||||
|
}
|
||||||
|
|
||||||
function* neighbors(x, y, z) {
|
function* neighbors(x, y, z) {
|
||||||
const idx = (
|
const idx = (
|
||||||
z * cs * cs +
|
z * cs * cs +
|
||||||
@ -332,21 +444,15 @@ function* makeChunkFaces(chunk) {
|
|||||||
dir: '-x',
|
dir: '-x',
|
||||||
};
|
};
|
||||||
} else {
|
} else {
|
||||||
yield {
|
yield neighborBlock('-x', x, y, z);
|
||||||
block: BlockType.AIR,
|
|
||||||
dir: '-x',
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
if (x < 31) {
|
if (x < cs - 1) {
|
||||||
yield {
|
yield {
|
||||||
block: chunk.blocks[idx + 1],
|
block: chunk.blocks[idx + 1],
|
||||||
dir: '+x',
|
dir: '+x',
|
||||||
};
|
};
|
||||||
} else {
|
} else {
|
||||||
yield {
|
yield neighborBlock('+x', x, y, z);
|
||||||
block: BlockType.AIR,
|
|
||||||
dir: '+x',
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
if (y > 0) {
|
if (y > 0) {
|
||||||
yield {
|
yield {
|
||||||
@ -354,21 +460,15 @@ function* makeChunkFaces(chunk) {
|
|||||||
dir: '-y',
|
dir: '-y',
|
||||||
};
|
};
|
||||||
} else {
|
} else {
|
||||||
yield {
|
yield neighborBlock('-y', x, y, z);
|
||||||
block: BlockType.AIR,
|
|
||||||
dir: '-y',
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
if (y < 31) {
|
if (y < cs - 1) {
|
||||||
yield {
|
yield {
|
||||||
block: chunk.blocks[idx + cs],
|
block: chunk.blocks[idx + cs],
|
||||||
dir: '+y',
|
dir: '+y',
|
||||||
};
|
};
|
||||||
} else {
|
} else {
|
||||||
yield {
|
yield neighborBlock('+y', x, y, z);
|
||||||
block: BlockType.AIR,
|
|
||||||
dir: '+y',
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
if (z > 0) {
|
if (z > 0) {
|
||||||
yield {
|
yield {
|
||||||
@ -376,21 +476,15 @@ function* makeChunkFaces(chunk) {
|
|||||||
dir: '-z',
|
dir: '-z',
|
||||||
};
|
};
|
||||||
} else {
|
} else {
|
||||||
yield {
|
yield neighborBlock('-z', x, y, z);
|
||||||
block: BlockType.AIR,
|
|
||||||
dir: '-z',
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
if (z < 31) {
|
if (z < cs - 1) {
|
||||||
yield {
|
yield {
|
||||||
block: chunk.blocks[idx + cs * cs],
|
block: chunk.blocks[idx + cs * cs],
|
||||||
dir: '+z',
|
dir: '+z',
|
||||||
};
|
};
|
||||||
} else {
|
} else {
|
||||||
yield {
|
yield neighborBlock('+z', x, y, z);
|
||||||
block: BlockType.AIR,
|
|
||||||
dir: '+z',
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -430,59 +524,6 @@ function closeToPlanet(context) {
|
|||||||
return linalg.norm(relativePos) < 20;
|
return linalg.norm(relativePos) < 20;
|
||||||
}
|
}
|
||||||
|
|
||||||
function makeSun(seed) {
|
|
||||||
const radius = 7;
|
|
||||||
const radiusChunks = Math.floor(radius / CHUNKSIZE);
|
|
||||||
|
|
||||||
const chunks = [];
|
|
||||||
|
|
||||||
function makeSunChunk(i, j, k) {
|
|
||||||
const cs = CHUNKSIZE;
|
|
||||||
const half = cs / 2;
|
|
||||||
const blocks = new Array(cs**3);
|
|
||||||
blocks.fill(BlockType.SUN);
|
|
||||||
|
|
||||||
let underground = true;
|
|
||||||
|
|
||||||
for (let x = 0; x < cs; x++) {
|
|
||||||
for (let y = 0; y < cs; y++) {
|
|
||||||
for (let z = 0; z < cs; z++) {
|
|
||||||
const pos = [
|
|
||||||
x + i * cs - half,
|
|
||||||
y + j * cs - half,
|
|
||||||
z + k * cs - half,
|
|
||||||
];
|
|
||||||
const idx = (
|
|
||||||
z * cs * cs +
|
|
||||||
y * cs +
|
|
||||||
x
|
|
||||||
);
|
|
||||||
if (pos[0]**2 + pos[1]**2 + pos[2]**2 > radius**2) {
|
|
||||||
blocks[idx] = BlockType.AIR;
|
|
||||||
underground = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
|
||||||
position: [i * cs - half, j * cs - half, k * cs - half],
|
|
||||||
blocks,
|
|
||||||
underground,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
for (let i = -radiusChunks; i <= radiusChunks; i++) {
|
|
||||||
for (let j = -radiusChunks; j <= radiusChunks; j++) {
|
|
||||||
for (let k = -radiusChunks; k <= radiusChunks; k++) {
|
|
||||||
chunks.push(makeSunChunk(i, j, k));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return chunks;
|
|
||||||
}
|
|
||||||
|
|
||||||
function getBodyGeometry(seed) {
|
function getBodyGeometry(seed) {
|
||||||
const faces = getBodyChunks(seed)
|
const faces = getBodyChunks(seed)
|
||||||
.filter(chunk => !chunk.underground)
|
.filter(chunk => !chunk.underground)
|
||||||
@ -1208,6 +1249,7 @@ async function main() {
|
|||||||
// [ ] huge planets
|
// [ ] huge planets
|
||||||
// [x] lighting
|
// [x] lighting
|
||||||
// [ ] better lighting
|
// [ ] better lighting
|
||||||
|
// [x] optimize geometry generation
|
||||||
|
|
||||||
const modelPromise = loadStlModel('spaceship.stl');
|
const modelPromise = loadStlModel('spaceship.stl');
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user