Skip to content

Commit

Permalink
feat(graphics): add instance UVs for textured meshes
Browse files Browse the repository at this point in the history
  • Loading branch information
tomaisthorpe committed Aug 25, 2024
1 parent e6e2310 commit 03f7c7b
Show file tree
Hide file tree
Showing 6 changed files with 98 additions and 26 deletions.
5 changes: 5 additions & 0 deletions .changeset/itchy-hounds-eat.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@tedengine/ted': minor
---

Add instance UVs for textured meshes
1 change: 1 addition & 0 deletions packages/ted/src/renderer/frame-params.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,5 +55,6 @@ export interface TSerializedTexturedMaterial {
type: 'textured';
options: {
texture: string;
instanceUVs?: number[];
};
}
35 changes: 22 additions & 13 deletions packages/ted/src/renderer/program.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import type { IAsset } from '../core/resource-manager';
const compileShader = (
gl: WebGL2RenderingContext,
shaderSource: string,
shaderType: number
shaderType: number,
): WebGLShader => {
// @todo add error handling here
const shader = gl.createShader(shaderType);
Expand All @@ -22,7 +22,7 @@ const compileShader = (
const createProgram = (
gl: WebGL2RenderingContext,
vertexShader: WebGLShader,
fragmentShader: WebGLShader
fragmentShader: WebGLShader,
) => {
// @todo add error handling here
const program = gl.createProgram();
Expand Down Expand Up @@ -73,56 +73,65 @@ export default class TProgram implements IAsset {
const vertexShader = compileShader(
gl,
this.vertexShaderSource!,
gl.VERTEX_SHADER
gl.VERTEX_SHADER,
);
const fragmentShader = compileShader(
gl,
this.fragmentShaderSource!,
gl.FRAGMENT_SHADER
gl.FRAGMENT_SHADER,
);

this.program = createProgram(gl, vertexShader, fragmentShader);
this.compiled = true;

this.attribLocations.vertexPosition = gl.getAttribLocation(
this.program,
'aVertexPosition'
'aVertexPosition',
);
this.attribLocations.normalPosition = gl.getAttribLocation(
this.program,
'aVertexNormal'
'aVertexNormal',
);
this.attribLocations.colorPosition = gl.getAttribLocation(
this.program,
'aVertexColor'
'aVertexColor',
);
this.attribLocations.uvPosition = gl.getAttribLocation(
this.program,
'aVertexUV'
'aVertexUV',
);

this.attribLocations.instanceUVPosition = gl.getAttribLocation(
this.program,
'aVertexInstanceUV',
);

this.uniformLocations.mMatrix = gl.getUniformLocation(
this.program,
'uMMatrix'
'uMMatrix',
);
this.uniformLocations.uPalette = gl.getUniformLocation(
this.program,
'uPalette'
'uPalette',
);
this.uniformLocations.uEnableInstanceUVs = gl.getUniformLocation(
this.program,
'uEnableInstanceUVs',
);
}

public getAttributeLocations(
gl: WebGL2RenderingContext,
attributes: string[]
attributes: string[],
): WebGLUniformLocation[] {
return attributes.map(
(attribute) => gl.getUniformLocation(this.program!, attribute)!
(attribute) => gl.getUniformLocation(this.program!, attribute)!,
);
}

public getUniformLocation(
gl: WebGL2RenderingContext,
name: string
name: string,
): WebGLUniformLocation {
if (!this.uniformLocations[name]) {
this.uniformLocations[name] = gl.getUniformLocation(this.program!, name);
Expand Down
62 changes: 52 additions & 10 deletions packages/ted/src/renderer/renderable-textured-mesh.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,13 +19,17 @@ export default class TRenderableTexturedMesh {
private indexBuffer?: WebGLBuffer;
private uvBuffer?: WebGLBuffer;

// Instance buffers, used to override the UVs of the mesh
private instanceUVBuffer?: WebGLBuffer;

private vao?: WebGLVertexArrayObject;

public render(
gl: WebGL2RenderingContext,
texturedProgram: TTexturedProgram,
texture: TRenderableTexture,
m: mat4
m: mat4,
instanceUVs?: number[],
) {
if (this.positionBuffer === undefined) {
this.createBuffers(gl);
Expand Down Expand Up @@ -54,9 +58,23 @@ export default class TRenderableTexturedMesh {
gl.uniformMatrix4fv(
texturedProgram.program!.uniformLocations.mMatrix,
false,
m
m,
);

gl.uniform1f(
texturedProgram.program!.uniformLocations.uEnableInstanceUVs,
instanceUVs ? 1 : 0,
);

if (instanceUVs && this.instanceUVBuffer) {
gl.bindBuffer(gl.ARRAY_BUFFER, this.instanceUVBuffer);
gl.bufferData(
gl.ARRAY_BUFFER,
new Float32Array(instanceUVs),
gl.STATIC_DRAW,
);
}

const vertexCount = this.indexes.length;
const type = gl.UNSIGNED_SHORT;
const offset = 0;
Expand All @@ -65,7 +83,7 @@ export default class TRenderableTexturedMesh {
}

private createVAO(gl: WebGL2RenderingContext, program: TProgram) {
const { vertexPosition, normalPosition, uvPosition } =
const { vertexPosition, normalPosition, uvPosition, instanceUVPosition } =
program.attribLocations;

this.vao = gl.createVertexArray()!;
Expand All @@ -85,7 +103,7 @@ export default class TRenderableTexturedMesh {
type,
normalize,
stride,
offset
offset,
);

gl.enableVertexAttribArray(vertexPosition);
Expand All @@ -106,14 +124,14 @@ export default class TRenderableTexturedMesh {
type,
normalize,
stride,
offset
offset,
);

gl.enableVertexAttribArray(normalPosition);
}

if (uvPosition !== -1) {
// Color buffer
// UV buffer

const numComponents = 2;
const type = gl.FLOAT;
Expand All @@ -127,11 +145,32 @@ export default class TRenderableTexturedMesh {
type,
normalize,
stride,
offset
offset,
);

gl.enableVertexAttribArray(uvPosition);
}

if (instanceUVPosition !== -1) {
// Instance UV buffer

const numComponents = 2;
const type = gl.FLOAT;
const normalize = false;
const stride = 0;
const offset = 0;
gl.bindBuffer(gl.ARRAY_BUFFER, this.instanceUVBuffer!);
gl.vertexAttribPointer(
instanceUVPosition,
numComponents,
type,
normalize,
stride,
offset,
);

gl.enableVertexAttribArray(instanceUVPosition);
}
}

/**
Expand All @@ -143,27 +182,30 @@ export default class TRenderableTexturedMesh {
gl.bufferData(
gl.ARRAY_BUFFER,
new Float32Array(this.positions),
gl.STATIC_DRAW
gl.STATIC_DRAW,
);

this.normalBuffer = gl.createBuffer()!;
gl.bindBuffer(gl.ARRAY_BUFFER, this.normalBuffer);
gl.bufferData(
gl.ARRAY_BUFFER,
new Float32Array(this.normals),
gl.STATIC_DRAW
gl.STATIC_DRAW,
);

this.indexBuffer = gl.createBuffer()!;
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this.indexBuffer);
gl.bufferData(
gl.ELEMENT_ARRAY_BUFFER,
new Uint16Array(this.indexes),
gl.STATIC_DRAW
gl.STATIC_DRAW,
);

this.uvBuffer = gl.createBuffer()!;
gl.bindBuffer(gl.ARRAY_BUFFER, this.uvBuffer);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(this.uvs), gl.STATIC_DRAW);

// Data will be buffered at render time if provided
this.instanceUVBuffer = gl.createBuffer()!;
}
}
16 changes: 14 additions & 2 deletions packages/ted/src/renderer/renderer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -153,7 +153,13 @@ export default class TRenderer {

const mesh = this.registeredTexturedMeshes[task.uuid];
const texture = this.registeredTextures[task.material.options.texture];
mesh.render(gl, this.texturedProgram!, texture, task.transform);
mesh.render(
gl,
this.texturedProgram!,
texture,
task.transform,
task.material.options.instanceUVs,
);
}
}

Expand All @@ -171,7 +177,13 @@ export default class TRenderer {
for (const task of layer) {
const mesh = this.registeredTexturedMeshes[task.uuid];
const texture = this.registeredTextures[task.material.options.texture];
mesh.render(gl, this.texturedProgram!, texture, task.transform);
mesh.render(
gl,
this.texturedProgram!,
texture,
task.transform,
task.material.options.instanceUVs,
);
}
}
}
Expand Down
5 changes: 4 additions & 1 deletion packages/ted/src/shaders/textured.program
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@
in vec4 aVertexPosition;
in vec2 aVertexUV;

uniform float uEnableInstanceUVs;
in vec2 aVertexInstanceUV;

uniform mat4 uMMatrix;

uniform Settings {
Expand All @@ -14,7 +17,7 @@ out highp vec2 vUV;
void main() {
gl_Position = uVPMatrix * uMMatrix * aVertexPosition;

vUV = aVertexUV;
vUV = aVertexInstanceUV * uEnableInstanceUVs + aVertexUV * (1.0 - uEnableInstanceUVs);
}
----
#version 300 es
Expand Down

0 comments on commit 03f7c7b

Please sign in to comment.