Optimised block assigning

This commit is contained in:
Lucas Dower 2022-02-12 18:58:44 +00:00
parent 8549901a43
commit 8619f9fa18
5 changed files with 75 additions and 67 deletions

View File

@ -46,7 +46,6 @@
"eslint-config-google": "^0.14.0",
"expand-vertex-data": "^1.1.2",
"jpeg-js": "^0.4.3",
"mesh-simplify": "^2.0.0",
"mtltojs": "^0.2.1",
"obj-file-parser": "^0.5.3",
"pngjs": "^6.0.0",

View File

@ -2,11 +2,12 @@ import { BasicBlockAssigner, OrderedDitheringBlockAssigner } from './block_assig
import { Voxel, VoxelMesh } from './voxel_mesh';
import { BlockInfo } from './block_atlas';
import { CustomError, LOG } from './util';
import { RenderBuffer, VoxelData } from './buffer';
import { RenderBuffer, VoxelData, Attribute } from './buffer';
import { OcclusionManager } from './occlusion';
import { GeometryTemplates } from './geometry';
import { AppConfig } from './config';
import { Vector3 } from './vector';
import { Renderer } from './renderer';
interface Block {
voxel: Voxel;
@ -65,59 +66,21 @@ export class BlockMesh {
}
public createBuffer(ambientOcclusionEnabled: boolean) {
const buffer = new RenderBuffer([
{ name: 'position', numComponents: 3},
{ name: 'normal', numComponents: 3 },
{ name: 'occlusion', numComponents: 4 },
{ name: 'texcoord', numComponents: 2 },
{ name: 'blockTexcoord', numComponents: 2 },
]);
// const buffer = this.getVoxelMesh().createBuffer(ambientOcclusionEnabled);
const buffer = Renderer.Get._voxelBuffer.copy();
const blockTexcoords: number[] = [];
for (const block of this._blocks) {
// Each vertex of a face needs the occlusion data for the other 3 vertices
// in it's face, not just itself. Also flatten occlusion data.
let occlusions: number[];
if (ambientOcclusionEnabled) {
occlusions = OcclusionManager.Get.getOcclusions(block.voxel.position, this.getVoxelMesh());
} else {
occlusions = OcclusionManager.Get.getBlankOcclusions();
}
const data: VoxelData = GeometryTemplates.getBoxBufferData(block.voxel.position);
data.custom.occlusion = occlusions;
// Assign the textures to each face
data.custom.blockTexcoord = [];
const faceOrder = ['north', 'south', 'up', 'down', 'east', 'west'];
for (const face of faceOrder) {
for (let i = 0; i < 4; ++i) {
const texcoord = block.blockInfo.faces[face].texcoord;
data.custom.blockTexcoord.push(texcoord.u, texcoord.v);
blockTexcoords.push(texcoord.u, texcoord.v);
}
}
const faceNormals = OcclusionManager.Get.getFaceNormals();
if (AppConfig.FACE_CULLING) {
// TODO: Optmise, enabling FACE_CULLING is slower than not bothering
for (let i = 0; i < 6; ++i) {
if (!this.getVoxelMesh().isVoxelAt(Vector3.add(block.voxel.position, faceNormals[i]))) {
buffer.add({
custom: {
position: data.custom.position.slice(i * 12, (i+1) * 12),
occlusion: data.custom.occlusion.slice(i * 16, (i+1) * 16),
normal: data.custom.normal.slice(i * 12, (i+1) * 12),
texcoord: data.custom.texcoord.slice(i * 8, (i+1) * 8),
colour: data.custom.colour.slice(i * 12, (i+1) * 12),
blockTexcoord: data.custom.blockTexcoord.slice(i * 8, (i+1) * 8),
},
indices: data.indices.slice(0, 6),
});
}
}
} else {
buffer.add(data);
}
}
buffer.attachNewAttribute({ name: 'blockTexcoord', numComponents: 2 }, blockTexcoords);
buffer.removeAttribute('colour');
return buffer;
}

View File

@ -1,9 +1,10 @@
import { Renderer } from './renderer';
import { ASSERT, LOG } from './util';
import { AppConfig } from './config';
import * as twgl from 'twgl.js';
import { ASSERT } from './util';
interface Attribute {
export interface Attribute {
name: string,
numComponents: number
}
@ -32,13 +33,11 @@ export class RenderBuffer {
};
private _buffer!: BottomlessBufferData;
private _attributes: {[name: string]: Attribute};
private _maxIndex: number = 0;
private _compiled: boolean = false;
private _sanityCheck: boolean = false;
private _maxIndex: number;
private _compiled: boolean;
private _needsCompiling: boolean;
public constructor(attributes: Array<Attribute>) {
this._compiled = false;
this._attributes = {};
for (const attr of attributes) {
this._attributes[attr.name] = {
@ -46,15 +45,19 @@ export class RenderBuffer {
numComponents: attr.numComponents,
};
}
this._needsCompiling = false;
this._compiled = false;
this._maxIndex = 0;
this._getNewBuffer();
}
public add(data: VoxelData) {
if (this._sanityCheck) {
this._checkDataMatchesAttributes(data);
ASSERT(!this._compiled);
if (AppConfig.DEBUG_ENABLED) {
// this._checkDataMatchesAttributes(data);
}
const mappedIndicesToAdd = new Array<number>(data.indices.length);
@ -70,14 +73,27 @@ export class RenderBuffer {
for (const attr in this._attributes) {
this._buffer[attr].data.push(...data.custom[attr]);
}
this._needsCompiling = true;
}
public attachNewAttribute(data: VoxelData) {
public attachNewAttribute(attribute: Attribute, data: Array<number>) {
ASSERT(this._buffer[attribute.name] === undefined, 'Attribute already exists in buffer');
ASSERT(this._attributes[attribute.name] === undefined, 'Attribute already exists in attributes');
const expectedDataLength = this._maxIndex * attribute.numComponents;
ASSERT(data.length === expectedDataLength, `Data length expected to be ${expectedDataLength}, got ${data.length}`);
this._buffer[attribute.name] = {
numComponents: attribute.numComponents,
data: data,
};
this._attributes[attribute.name] = attribute;
this._needsCompiling = true;
}
public removeAttribute(attribute: string) {
public removeAttribute(attributeName: string) {
delete this._buffer[attributeName];
delete this._attributes[attributeName];
this._needsCompiling = true;
}
public getWebGLBuffer() {
@ -87,7 +103,7 @@ export class RenderBuffer {
}
private _compile() {
if (this._compiled) {
if (this._compiled && !this._needsCompiling) {
return;
}
@ -109,6 +125,7 @@ export class RenderBuffer {
};
this._compiled = true;
this._needsCompiling = false;
}
private _getNewBuffer() {
@ -142,4 +159,29 @@ export class RenderBuffer {
}
}
}
public copy(): RenderBuffer {
const copiedBuffer = new RenderBuffer([]);
copiedBuffer._buffer = {
indices: {
numComponents: this._buffer.indices.numComponents,
data: Array.from(this._buffer.indices.data),
},
};
for (const key in this._buffer) {
if (key !== 'indices') {
copiedBuffer._buffer[key] = {
numComponents: this._buffer[key].numComponents,
data: Array.from(this._buffer[key].data),
};
}
}
copiedBuffer._attributes = JSON.parse(JSON.stringify(this._attributes));
copiedBuffer._maxIndex = this._maxIndex;
copiedBuffer._compiled = false;
copiedBuffer._needsCompiling = true;
return copiedBuffer;
}
}

View File

@ -10,4 +10,6 @@ export namespace AppConfig {
export const ASSERTIONS_ENABLED = true;
export const FACE_CULLING = false;
export const DEBUG_ENABLED = true;
}

View File

@ -31,7 +31,8 @@ export class Renderer {
private _meshToUse: MeshType = MeshType.None;
private _voxelSize: number = 1.0;
private _buffer: RenderBuffer;
public _voxelBuffer: RenderBuffer;
private _blockBuffer: RenderBuffer;
private _materialBuffers: Array<{
buffer: RenderBuffer,
material: (SolidMaterial | (TexturedMaterial & { texture: WebGLTexture }))
@ -48,7 +49,8 @@ export class Renderer {
this._setupOcclusions();
this._buffer = new RenderBuffer([]);
this._voxelBuffer = new RenderBuffer([]);
this._blockBuffer = new RenderBuffer([]);
this._materialBuffers = [];
this._atlasTexture = twgl.createTexture(this._gl, {
@ -130,7 +132,7 @@ export class Renderer {
public useVoxelMesh(voxelMesh: VoxelMesh, ambientOcclusionEnabled: boolean) {
LOG('Using voxel mesh');
LOG(voxelMesh);
this._buffer = voxelMesh.createBuffer(ambientOcclusionEnabled);
this._voxelBuffer = voxelMesh.createBuffer(ambientOcclusionEnabled);
this._meshToUse = MeshType.VoxelMesh;
this._voxelSize = voxelMesh?.getVoxelSize();
}
@ -138,7 +140,7 @@ export class Renderer {
public useBlockMesh(blockMesh: BlockMesh, ambientOcclusionEnabled: boolean) {
LOG('Using block mesh');
LOG(blockMesh);
this._buffer = blockMesh.createBuffer(ambientOcclusionEnabled);
this._blockBuffer = blockMesh.createBuffer(ambientOcclusionEnabled);
this._meshToUse = MeshType.BlockMesh;
this._voxelSize = blockMesh.getVoxelMesh().getVoxelSize();
}
@ -166,14 +168,14 @@ export class Renderer {
}
private _drawVoxelMesh() {
this._drawRegister(this._buffer, ShaderManager.Get.voxelProgram, {
this._drawRegister(this._voxelBuffer, ShaderManager.Get.voxelProgram, {
u_worldViewProjection: ArcballCamera.Get.getWorldViewProjection(),
u_voxelSize: this._voxelSize,
});
}
private _drawBlockMesh() {
this._drawRegister(this._buffer, ShaderManager.Get.blockProgram, {
this._drawRegister(this._blockBuffer, ShaderManager.Get.blockProgram, {
u_worldViewProjection: ArcballCamera.Get.getWorldViewProjection(),
u_texture: this._atlasTexture,
u_voxelSize: this._voxelSize,