forked from mirror/ObjToSchematic
Optimised voxel and block mesh buffer generation
This commit is contained in:
parent
968f90f436
commit
b8cc31d75a
@ -6,6 +6,7 @@ import { Mesh, SolidMaterial, TexturedMaterial } from './mesh';
|
||||
import { OcclusionManager } from './occlusion';
|
||||
import { ProgressManager } from './progress';
|
||||
import { AttributeData } from './render_buffer';
|
||||
import { AppUtil } from './util';
|
||||
import { ASSERT } from './util/error_util';
|
||||
import { Vector3 } from './vector';
|
||||
import { VoxelMesh } from './voxel_mesh';
|
||||
@ -71,38 +72,56 @@ export class ChunkedBufferGenerator {
|
||||
const cube: AttributeData = GeometryTemplates.getBoxBufferData(new Vector3(0, 0, 0));
|
||||
const voxels = voxelMesh.getVoxels();
|
||||
|
||||
// Build position buffer
|
||||
for (let i = 0; i < numBufferVoxels; ++i) {
|
||||
const voxelIndex = i + voxelsStartIndex;
|
||||
|
||||
const voxel = voxels[voxelIndex];
|
||||
const voxelColourArray = [voxel.colour.r, voxel.colour.g, voxel.colour.b, voxel.colour.a];
|
||||
const voxel = voxels[i + voxelsStartIndex];
|
||||
const voxelPositionArray = voxel.position.toArray();
|
||||
|
||||
for (let j = 0; j < AppConstants.VoxelMeshBufferComponentOffsets.POSITION; ++j) {
|
||||
newBuffer.position.data[i * AppConstants.VoxelMeshBufferComponentOffsets.POSITION + j] = cube.custom.position[j] + voxelPositionArray[j % 3];
|
||||
}
|
||||
}
|
||||
|
||||
for (let j = 0; j < AppConstants.VoxelMeshBufferComponentOffsets.COLOUR; ++j) {
|
||||
newBuffer.colour.data[i * AppConstants.VoxelMeshBufferComponentOffsets.COLOUR + j] = voxelColourArray[j % 4];
|
||||
}
|
||||
// Build colour buffer
|
||||
for (let i = 0; i < numBufferVoxels; ++i) {
|
||||
const voxel = voxels[i + voxelsStartIndex];
|
||||
newBuffer.colour.data[i * 96 + 0] = voxel.colour.r;
|
||||
newBuffer.colour.data[i * 96 + 1] = voxel.colour.g;
|
||||
newBuffer.colour.data[i * 96 + 2] = voxel.colour.b;
|
||||
newBuffer.colour.data[i * 96 + 3] = voxel.colour.a;
|
||||
|
||||
for (let j = 0; j < AppConstants.VoxelMeshBufferComponentOffsets.NORMAL; ++j) {
|
||||
newBuffer.normal.data[i * AppConstants.VoxelMeshBufferComponentOffsets.NORMAL + j] = cube.custom.normal[j];
|
||||
}
|
||||
AppUtil.Array.repeatedFill(newBuffer.colour.data, i * 96, 4, 24);
|
||||
}
|
||||
|
||||
for (let j = 0; j < AppConstants.VoxelMeshBufferComponentOffsets.TEXCOORD; ++j) {
|
||||
newBuffer.texcoord.data[i * AppConstants.VoxelMeshBufferComponentOffsets.TEXCOORD + j] = cube.custom.texcoord[j];
|
||||
}
|
||||
// Build normal buffer
|
||||
{
|
||||
newBuffer.normal.data.set(cube.custom.normal, 0);
|
||||
AppUtil.Array.repeatedFill(newBuffer.normal.data, 0, 72, numBufferVoxels);
|
||||
}
|
||||
|
||||
// Build texcoord buffer
|
||||
{
|
||||
newBuffer.texcoord.data.set(cube.custom.texcoord, 0);
|
||||
AppUtil.Array.repeatedFill(newBuffer.texcoord.data, 0, 48, numBufferVoxels);
|
||||
}
|
||||
|
||||
|
||||
// Build indices buffer
|
||||
for (let i = 0; i < numBufferVoxels; ++i) {
|
||||
for (let j = 0; j < AppConstants.VoxelMeshBufferComponentOffsets.INDICES; ++j) {
|
||||
newBuffer.indices.data[i * AppConstants.VoxelMeshBufferComponentOffsets.INDICES + j] = cube.indices[j] + (i * AppConstants.INDICES_PER_VOXEL);
|
||||
}
|
||||
}
|
||||
|
||||
if (params.enableAmbientOcclusion) {
|
||||
const voxelOcclusionArray = OcclusionManager.Get.getOcclusions(voxel.position, voxelMesh);
|
||||
for (let j = 0; j < AppConstants.VoxelMeshBufferComponentOffsets.OCCLUSION; ++j) {
|
||||
newBuffer.occlusion.data[i * AppConstants.VoxelMeshBufferComponentOffsets.OCCLUSION + j] = voxelOcclusionArray[j];
|
||||
}
|
||||
// Build occlusion buffer
|
||||
if (params.enableAmbientOcclusion) {
|
||||
const voxelOcclusionArray = new Float32Array(96);
|
||||
|
||||
for (let i = 0; i < numBufferVoxels; ++i) {
|
||||
const voxel = voxels[i + voxelsStartIndex];
|
||||
OcclusionManager.Get.getOcclusions(voxelOcclusionArray, voxel.position, voxelMesh);
|
||||
|
||||
newBuffer.occlusion.data.set(voxelOcclusionArray, i * AppConstants.VoxelMeshBufferComponentOffsets.OCCLUSION);
|
||||
}
|
||||
}
|
||||
|
||||
@ -149,6 +168,7 @@ export class ChunkedBufferGenerator {
|
||||
let insertIndex = 0;
|
||||
let lightingInsertIndex = 0;
|
||||
|
||||
//const blockPositionArray = new Float32Array(3);
|
||||
for (let i = 0; i < numBufferBlocks; ++i) {
|
||||
const blockIndex = i + blocksStartIndex;
|
||||
const blockLighting = blockMesh.getBlockLighting(blocks[blockIndex].voxel.position);
|
||||
@ -166,10 +186,13 @@ export class ChunkedBufferGenerator {
|
||||
}
|
||||
}
|
||||
|
||||
const blockPosition = blocks[blockIndex].voxel.position.toArray();
|
||||
for (let j = 0; j < AppConstants.VoxelMeshBufferComponentOffsets.POSITION; ++j) {
|
||||
newBuffer.blockPosition.data[i * AppConstants.VoxelMeshBufferComponentOffsets.POSITION + j] = blockPosition[j % 3];
|
||||
}
|
||||
//const blockPosition = blocks[blockIndex].voxel.position.toArray();
|
||||
//blocks[blockIndex].voxel.position.intoArray(blockPositionArray, 0);
|
||||
|
||||
newBuffer.blockPosition.data[i * 72 + 0] = blocks[blockIndex].voxel.position.x;
|
||||
newBuffer.blockPosition.data[i * 72 + 1] = blocks[blockIndex].voxel.position.y;
|
||||
newBuffer.blockPosition.data[i * 72 + 2] = blocks[blockIndex].voxel.position.z;
|
||||
AppUtil.Array.repeatedFill(newBuffer.blockPosition.data, i * 72, 3, 24);
|
||||
}
|
||||
|
||||
return {
|
||||
|
@ -16,7 +16,7 @@ export class AppConfig {
|
||||
public readonly MINECRAFT_VERSION = '1.19.4';
|
||||
|
||||
public readonly LOCALE = 'en_GB';
|
||||
public readonly VOXEL_BUFFER_CHUNK_SIZE = 5_000;
|
||||
public readonly VOXEL_BUFFER_CHUNK_SIZE = 50_000;
|
||||
public readonly AMBIENT_OCCLUSION_OVERRIDE_CORNER = true;
|
||||
public readonly USE_WORKER_THREAD = true;
|
||||
public readonly MULTISAMPLE_COUNT = 16;
|
||||
|
@ -26,6 +26,10 @@ export namespace AppMath {
|
||||
export function uint8(decimal: number) {
|
||||
return Math.floor(decimal * 255);
|
||||
}
|
||||
|
||||
export function largestPowerOfTwoLessThanN(n: number) {
|
||||
return Math.floor(Math.log2(n));
|
||||
}
|
||||
}
|
||||
|
||||
export const argMax = (array: [number]) => {
|
||||
|
@ -25,12 +25,14 @@ export class OcclusionManager {
|
||||
return new Array<number>(96).fill(1.0);
|
||||
}
|
||||
|
||||
public getOcclusions(centre: Vector3, voxelMesh: VoxelMesh) {
|
||||
// Assume's buffer is of length 96
|
||||
public getOcclusions(buffer: Float32Array, centre: Vector3, voxelMesh: VoxelMesh): void {
|
||||
// Cache local neighbours
|
||||
const neighbourData = voxelMesh.getNeighbours(centre);
|
||||
if (neighbourData === undefined) {
|
||||
// This voxel has no neighbours within a 1-block radius
|
||||
return this.getBlankOcclusions();
|
||||
buffer.fill(0.0);
|
||||
return;
|
||||
}
|
||||
|
||||
for (let i = 0; i < 27; ++i) {
|
||||
@ -69,7 +71,8 @@ export class OcclusionManager {
|
||||
}
|
||||
}
|
||||
|
||||
return this._occlusions;
|
||||
buffer.set(this._occlusions, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
public static getNeighbourIndex(neighbour: Vector3) {
|
||||
|
22
src/util.ts
22
src/util.ts
@ -1,3 +1,5 @@
|
||||
import { AppMath } from "./math";
|
||||
|
||||
export namespace AppUtil {
|
||||
export namespace Text {
|
||||
export function capitaliseFirstLetter(text: string) {
|
||||
@ -17,6 +19,26 @@ export namespace AppUtil {
|
||||
return blockName.includes(':');
|
||||
}
|
||||
}
|
||||
|
||||
export namespace Array {
|
||||
|
||||
/**
|
||||
* An optimised function for repeating a subarray contained within a buffer multiple times by
|
||||
* repeatedly doubling the subarray's length.
|
||||
*/
|
||||
export function repeatedFill(buffer: Float32Array, start: number, startLength: number, desiredCount: number) {
|
||||
const pow = AppMath.largestPowerOfTwoLessThanN(desiredCount);
|
||||
|
||||
let len = startLength;
|
||||
for (let i = 0; i < pow; ++i) {
|
||||
buffer.copyWithin(start + len, start, start + len);
|
||||
len *= 2;
|
||||
}
|
||||
|
||||
const finalLength = desiredCount * startLength;
|
||||
buffer.copyWithin(start + len, start, start + finalLength - len);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* eslint-disable */
|
||||
|
@ -249,6 +249,12 @@ export class Vector3 implements IHashable {
|
||||
public stringify() {
|
||||
return `${this.x}_${this.y}_${this.z}`;
|
||||
}
|
||||
|
||||
public intoArray(array: Float32Array, start: number) {
|
||||
array[start + 0] = this.x;
|
||||
array[start + 1] = this.y;
|
||||
array[start + 2] = this.z;
|
||||
}
|
||||
}
|
||||
|
||||
export const fastCrossXAxis = (vec: Vector3) => {
|
||||
|
Loading…
Reference in New Issue
Block a user