Skip to content

Commit

Permalink
Moved around the batching code to use the mesh, geometry, material cl…
Browse files Browse the repository at this point in the history
…asses
  • Loading branch information
HunterBarclay committed Dec 4, 2023
2 parents 59b2767 + 8f663c9 commit f98bf17
Show file tree
Hide file tree
Showing 6 changed files with 291 additions and 97 deletions.
114 changes: 114 additions & 0 deletions js/renderer/batch-geometry.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
import BatchInstance from "./batch-instance.mjs";
import { Geometry } from "./geometry.mjs";
import MeshHandler from "./mesh-handler.mjs";

/**
* Class for managing Buffers
*/
class BatchGeometry extends Geometry {

/** @type {Array<BatchInstance>} */
batchInstances;
/** @type {Number} */
batchSize;

/**
* Constructs a new BufferManager
*
* @param {WebGLRenderingContext} gl Rendering Context
* @param {MeshHandler} meshHandler Mesh handler for data of each batch instance
* @param {Number} batchSize Maximum number of batch instances that be can loaded in a single draw call
*/
constructor(gl, meshHandler, batchSize) {
super(gl);

this.batchSize = batchSize;

gl.bindBuffer(gl.ARRAY_BUFFER, this.positionBuffer);
gl.bufferData(gl.ARRAY_BUFFER, (meshHandler.vertexArray.length * Float32Array.BYTES_PER_ELEMENT) * batchSize, gl.DYNAMIC_DRAW);
gl.bindBuffer(gl.ARRAY_BUFFER, this.normalBuffer);
gl.bufferData(gl.ARRAY_BUFFER, (meshHandler.normalArray.length * Float32Array.BYTES_PER_ELEMENT) * batchSize, gl.DYNAMIC_DRAW);
gl.bindBuffer(gl.ARRAY_BUFFER, this.textureCoordBuffer);
gl.bufferData(gl.ARRAY_BUFFER, (meshHandler.texCoordArray.length * Float32Array.BYTES_PER_ELEMENT) * batchSize, gl.DYNAMIC_DRAW);
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this.indexBuffer);
gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, (meshHandler.indexArray.length * Uint32Array.BYTES_PER_ELEMENT) * batchSize, gl.DYNAMIC_DRAW);
}

/**
* Source(s):
* https://docs.gl/es2/
*
* @param {WebGLRenderingContext} gl - WebGL Context
* @param {Number} initialIndex - Index to start loading instances from
*
* @returns {Number} - loadedCount: Number of BatchInstance objects loaded
*/
loadBatchInstances(gl, initialIndex = 0) {
const instancesToLoad = Math.min(this.batchSize, this.batchInstances.length - initialIndex);

let loadedCount = 0;

let totalVertexOffset = 0;
let totalIndexOffset = 0;
let totalNormalOffset = 0;
let totalTexCoordOffset = 0;

for (let i = initialIndex; i < initialIndex + instancesToLoad; i++) {
const batchInstance = this.batchInstances[i];

if (batchInstance === undefined) {
console.log("Batch @ index " + i + " is undefined");
}

batchInstance.writeInstanceToBuffer(
gl,
totalVertexOffset, this.positionBuffer,
totalIndexOffset, this.indexBuffer,
totalNormalOffset, this.normalBuffer,
totalTexCoordOffset, this.textureCoordBuffer
);

// Increment offsets by the instance's buffer size
totalVertexOffset += batchInstance.getVertexBufferSize();
totalIndexOffset += batchInstance.getIndexBufferSize();
totalNormalOffset += batchInstance.getNormalBufferSize();
totalTexCoordOffset += batchInstance.getTexCoordBufferSize();

loadedCount++;
}

return loadedCount;
}

/**
* Draws the index buffer with provided other buffers
*
* @param {WebGLRenderingContext} gl Rendering Context
*/
draw(gl) {

if (this.batchInstances.length === 0) {
return;
}

var totalLoaded = 0;
do {
const loaded = this.loadBatchInstances(gl, totalLoaded);
totalLoaded++;
gl.drawElements(gl.TRIANGLES, this.batchInstances[0].meshData.indexArray.length * loaded, gl.UNSIGNED_INT, 0);
} while (totalLoaded < this.batchInstances.length);
}

deleteBuffers() {
this.gl.bindBuffer(this.gl.ARRAY_BUFFER, 0);
this.gl.bindBuffer(this.gl.ELEMENT_ARRAY_BUFFER, 0);

this.gl.deleteBuffer(this.batchBuffer.vertexBuffer);
this.gl.deleteBuffer(this.batchBuffer.indexBuffer);
this.gl.deleteBuffer(this.batchBuffer.normalBuffer);
this.gl.deleteBuffer(this.batchBuffer.texCoordBuffer);
this.batchBuffer.meshHandler = null;
}
}

export default BatchGeometry;
55 changes: 33 additions & 22 deletions js/renderer/batch-instance.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -14,31 +14,31 @@ class BatchInstance {
}

/**
* Returns the length of data that will be appended to Vertex Buffer
* Returns the length of data in bytes that will be appended to Vertex Buffer
*/
getVertexBufferLength() {
return this.meshData.vertexArray.length;
getVertexBufferSize() {
return this.meshData.vertexArray.length * Float32Array.BYTES_PER_ELEMENT;
}

/**
* Returns the length of data that will be appended to Index Buffer
* Returns the length of data in bytes that will be appended to Index Buffer
*/
getIndexBufferLength() {
return this.meshData.indexArray.length;
getIndexBufferSize() {
return this.meshData.indexArray.length * Uint32Array.BYTES_PER_ELEMENT;
}

/**
* Returns the length of data that will be appended to Normal Buffer
* Returns the length of data in bytes that will be appended to Normal Buffer
*/
getNormalBufferLength() {
return this.meshData.normalArray.length;
getNormalBufferSize() {
return this.meshData.normalArray.length * Float32Array.BYTES_PER_ELEMENT;
}

/**
* Returns the length of data that will be appended to TexCoord Buffer
* Returns the length of data in bytes that will be appended to TexCoord Buffer
*/
getTexCoordBufferLength() {
return this.meshData.texCoordArray.length;
getTexCoordBufferSize() {
return this.meshData.texCoordArray.length * Float32Array.BYTES_PER_ELEMENT;
}

/**
Expand Down Expand Up @@ -77,24 +77,35 @@ class BatchInstance {
texCoordBuffer
) {
gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer);
{
// The theory is that calling bufferSubData has a lot of overhead, so allocating all the altered data
// into an array, then loading the array into the buffer is faster. Who knows if thats true.
var tmpVertBuf = new Float32Array(this.getVertexBufferLength());
for (var i = 0; i < tmpVertBuf.length; i++) {
tmpVertBuf[i] = this.meshData.vertexArray[i] + this.position[i % 3];
}
gl.bufferSubData(gl.ARRAY_BUFFER, vertexOffset, tmpVertBuf);
}
gl.bufferSubData(
gl.ARRAY_BUFFER,
vertexOffset,
this.meshData.vertexArray.map(
(x, i) => x + this.position[i % 3]
)
);

gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, indexBuffer);
gl.bufferSubData(gl.ELEMENT_ARRAY_BUFFER, indexOffset, this.meshData.indexArray);
gl.bufferSubData(
gl.ELEMENT_ARRAY_BUFFER,
indexOffset,
this.meshData.indexArray.map(
x => x + vertexOffset / (Float32Array.BYTES_PER_ELEMENT * 3)
)
);

gl.bindBuffer(gl.ARRAY_BUFFER, normalBuffer);
gl.bufferSubData(gl.ARRAY_BUFFER, normalOffset, this.meshData.normalArray);

gl.bindBuffer(gl.ARRAY_BUFFER, texCoordBuffer);
gl.bufferSubData(gl.ARRAY_BUFFER, texCoordOffset, this.meshData.texCoordArray);

return [
vertexOffset + this.getVertexBufferSize(),
indexOffset + this.getIndexBufferSize(),
normalOffset + this.getNormalBufferSize(),
texCoordOffset + this.getTexCoordBufferSize()
];
}
}

Expand Down
40 changes: 40 additions & 0 deletions js/renderer/geometry.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import MeshHandler from "./mesh-handler.mjs";

/**
* Handle mesh handlers with associated WebGLBuffers
*/
export class Geometry {

/** @type {WebGLBuffer} */
positionBuffer;
/** @type {WebGLBuffer} */
normalBuffer;
/** @type {WebGLBuffer} */
textureCoordBuffer;
/** @type {WebGLBuffer} */
indexBuffer;

/**
* Constructs a new Geometry object
*
* @param {WebGLRenderingContext} gl Rendering Context
*/
constructor(gl) {
this.positionBuffer = gl.createBuffer();
this.normalBuffer = gl.createBuffer();
this.textureCoordBuffer = gl.createBuffer();
this.indexBuffer = gl.createBuffer();
}

/**
* Draws the index buffer with provided other buffers
*
* @param {WebGLRenderingContext} gl Rendering Context
*
* @abstract
*/
draw(gl) {
console.error("Must be overriden");
}

}
31 changes: 15 additions & 16 deletions js/renderer/materials.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ async function getShader(gl, type, src) {
var str = await fetch(src, {cache: "no-store"}).then(x => x.text());

var shader = gl.createShader(type);
console.log(str);
gl.shaderSource(shader, str);
gl.compileShader(shader);

Expand Down Expand Up @@ -49,7 +48,7 @@ export async function getShaderProgram(gl, vertSrc, fragSrc) {
return shaderProgram;
}

class Material {
export class Material {

/**
* Constructs a new material with a given shader program.
Expand Down Expand Up @@ -82,11 +81,14 @@ class Material {
* Binds buffers and their corresponding pointers
*
* @param {WebGLRenderbuffer} gl Rendering Context
* @param {Object} buffers Object containing buffers. Dependendant on implementation
* @param {WebGLBuffer?} positionBuffer
* @param {WebGLBuffer?} normalBuffer
* @param {WebGLBuffer?} textureCoordBuffer
* @param {WebGLBuffer?} indexBuffer
*
* @abstract
*/
bindVertexPointers(gl) { console.error("Must be overriden"); }
bindVertexPointers(gl, positionBuffer, normalBuffer, textureCoordBuffer, indexBuffer) { console.error("Must be overriden"); }
}

export class TestCubeMaterial extends Material {
Expand Down Expand Up @@ -195,26 +197,23 @@ export class TestCubeMaterial extends Material {
* Binds buffers and their corresponding pointers
*
* @param {WebGLRenderbuffer} gl Rendering Context
* @param {Object} buffers Object containing buffers. Following makeup:
* {
* positionBuffer: WebGLBuffer,
* normalBuffer: WebGLBuffer,
* textureCoordBuffer: WebGLBuffer,
* indexBuffer, WebGLBuffer
* }
* @param {WebGLBuffer} positionBuffer
* @param {WebGLBuffer} normalBuffer
* @param {WebGLBuffer} textureCoordBuffer
* @param {WebGLBuffer} indexBuffer
*
* @abstract
*/
bindVertexPointers(gl, buffers) {
gl.bindBuffer(gl.ARRAY_BUFFER, buffers.positionBuffer);
bindVertexPointers(gl, positionBuffer, normalBuffer, textureCoordBuffer, indexBuffer) {
gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);
gl.vertexAttribPointer(this.positionAttribute, 3, gl.FLOAT, false, 0, 0);

gl.bindBuffer(gl.ARRAY_BUFFER, buffers.normalBuffer);
gl.bindBuffer(gl.ARRAY_BUFFER, normalBuffer);
gl.vertexAttribPointer(this.normalAttribute, 3, gl.FLOAT, false, 0, 0);

gl.bindBuffer(gl.ARRAY_BUFFER, buffers.textureCoordBuffer);
gl.bindBuffer(gl.ARRAY_BUFFER, textureCoordBuffer);
gl.vertexAttribPointer(this.textureCoordAttribute, 2, gl.FLOAT, false, 0, 0);

gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, buffers.indexBuffer);
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, indexBuffer);
}
}
33 changes: 33 additions & 0 deletions js/renderer/mesh.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import { Geometry } from "./geometry.mjs";
import { Material } from "./materials.mjs";

export class Mesh {

/** @type {Geometry} */
geometry;
/** @type {Material} */
material;

constructor(geometry, material) {
this.geometry = geometry;
this.material = material;
}

/**
* Draws the mesh to the scene
*
* @param {WebGLRenderingContext} gl Rendering Context
*/
draw(gl) {
this.material.useShaderProgram(gl);
this.material.loadUniforms(gl);
this.material.bindVertexPointers(
gl,
this.geometry.positionBuffer,
this.geometry.normalBuffer,
this.geometry.textureCoordBuffer,
this.geometry.indexBuffer
);
this.geometry.draw(gl);
}
}
Loading

0 comments on commit f98bf17

Please sign in to comment.