Skip to content

Commit

Permalink
feat: example #1 - basic triangle.
Browse files Browse the repository at this point in the history
  • Loading branch information
bhouston committed Jun 17, 2020
1 parent 1af4c2e commit 705ab3d
Show file tree
Hide file tree
Showing 9 changed files with 156 additions and 34 deletions.
9 changes: 9 additions & 0 deletions src/examples/gettingstarted/1_triangle/fragment.glsl
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
precision highp float;

varying vec3 v_color;

void main() {

gl_FragColor = vec4(v_color, 1.0);

}
38 changes: 38 additions & 0 deletions src/examples/gettingstarted/1_triangle/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import { Geometry } from "@threeify/geometry/Geometry";
import { ShaderMaterial } from "@threeify/materials/ShaderMaterial";
import { RenderingContext } from "@threeify/renderers/webgl2";
import { BufferGeometry } from "@threeify/renderers/webgl2/buffers/BufferGeometry";
import { Float32AttributeAccessor, Int32AttributeAccessor } from "lib/geometry/AttributeAccessor";
import fragmentSourceCode from "./fragment.glsl";
import vertexSourceCode from "./vertex.glsl";

// create triangle buffers.

function createGeometry(): Geometry {
const positions: Float32Array = new Float32Array([0, 0.5, 0.5, -0.5, -0.5, -0.5]);
const colors: Float32Array = new Float32Array([1, 0, 0, 0, 1, 0, 0, 0, 1]);
const indices: Int32Array = new Int32Array([0, 1, 2]);

const positionAttribute = new Float32AttributeAccessor(positions, 2);
const colorsAttribute = new Float32AttributeAccessor(colors, 3);
const indicesAttribute = new Int32AttributeAccessor(indices, 3);

const triangleGeometry = new Geometry();
triangleGeometry.attributeAccessors.set("position", positionAttribute);
triangleGeometry.attributeAccessors.set("color", colorsAttribute);
triangleGeometry.indices = indicesAttribute;

return triangleGeometry;
}

const geometry = createGeometry();
const material = new ShaderMaterial(vertexSourceCode, fragmentSourceCode);

const context = new RenderingContext();
const canvasFramebuffer = context.canvasFramebuffer;
document.body.appendChild(canvasFramebuffer.canvas);

const bufferGeometry = BufferGeometry.FromAttributeGeometry(context, geometry);
const program = context.programPool.request(material);

canvasFramebuffer.renderBufferGeometry(program, {}, bufferGeometry);
12 changes: 12 additions & 0 deletions src/examples/gettingstarted/1_triangle/vertex.glsl
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
attribute vec2 position;
attribute vec3 color;

varying vec3 v_color;

void main() {

v_color = a_color;

gl_Position = vec4( a_position.x, a_position.y, 0.5, 1.0 );

}
4 changes: 2 additions & 2 deletions src/lib/renderers/Pool.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,14 +39,14 @@ export class Pool<U extends IPoolUser, R extends IDisposable> {

constructor(public context: RenderingContext, public updater: UserResourceUpdater<U, R>) {}

request(user: U): UserResource<U, R> {
request(user: U): R {
let userResource = this.userResources.find((userResource) => userResource.user.uuid === user.uuid);
if (userResource === undefined) {
userResource = new UserResource(user, this.updater(this.context, user, undefined));
this.userResources.push(userResource);
}

return userResource;
return userResource.resource;
}

update(): this {
Expand Down
26 changes: 2 additions & 24 deletions src/lib/renderers/webgl2/VertexArrayObject.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ export class VertexArrayObject {
offset = 0;
count = -1;

constructor(public program: Program, bufferGeometry: BufferGeometry) {
constructor(public readonly program: Program, bufferGeometry: BufferGeometry) {
this.primitive = bufferGeometry.primitive;
this.count = bufferGeometry.count;

Expand All @@ -33,28 +33,6 @@ export class VertexArrayObject {
// and make it the one we're currently working with
gl.bindVertexArray(this.glVertexArrayObject);

bufferGeometry.bufferAccessors.forEach((bufferAccessor, name) => {
const attribute = this.program.attributes.get(name);
if (attribute === undefined) {
// only bind the attributes that exist in the program.
return;
}

gl.enableVertexAttribArray(attribute.glLocation);

// Bind it to ARRAY_BUFFER (think of it as ARRAY_BUFFER = positionBuffer)
const buffer = bufferAccessor.buffer;
gl.bindBuffer(buffer.target, buffer.glBuffer);

// Tell the attribute how to get data out of positionBuffer (ARRAY_BUFFER)
gl.vertexAttribPointer(
attribute.glLocation,
bufferAccessor.componentsPerVertex,
bufferAccessor.componentType,
bufferAccessor.normalized,
bufferAccessor.vertexStride,
bufferAccessor.byteOffset,
);
});
program.setAttributeBuffers(bufferGeometry);
}
}
17 changes: 13 additions & 4 deletions src/lib/renderers/webgl2/framebuffers/CanvasFramebuffer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,22 +7,31 @@

import { Camera } from "../../../nodes/cameras/Camera";
import { Node } from "../../../nodes/Node";
import { BufferGeometry } from "../buffers/BufferGeometry";
import { Program } from "../programs/Program";
import { RenderingContext } from "../RenderingContext";
import { VertexArrayObject } from "../VertexArrayObject";
import { Framebuffer } from "./Framebuffer";
import { VirtualFramebuffer } from "./VirtualFramebuffer";

export class CanvasFramebuffer extends Framebuffer {
export class CanvasFramebuffer extends VirtualFramebuffer {
devicePixelRatio = 1.0;

constructor(context: RenderingContext, public readonly canvas: HTMLCanvasElement) {
super(context);
// TODO: add listening to the canvas and resize the canvas width/height?
}

renderDraw(program: Program, uniforms: any, vao: VertexArrayObject): void {
// eslint-disable-next-line @typescript-eslint/no-empty-function
dispose(): void {}

renderVertexArrayObject(program: Program, uniforms: any, vao: VertexArrayObject): void {
this.syncCanvas();
super.renderVertexArrayObject(program, uniforms, vao);
}

renderBufferGeometry(program: Program, uniforms: any, bufferGeometry: BufferGeometry): void {
this.syncCanvas();
super.renderDraw(program, uniforms, vao);
super.renderBufferGeometry(program, uniforms, bufferGeometry);
}

renderPass(program: Program, uniforms: any): void {
Expand Down
23 changes: 20 additions & 3 deletions src/lib/renderers/webgl2/framebuffers/VirtualFramebuffer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,16 +5,17 @@
// * @bhouston
//

import { VertexArrayObject } from "..";
import { IDisposable } from "../../../core/types";
import { Camera } from "../../../nodes/cameras/Camera";
import { Node } from "../../../nodes/Node";
import { BufferGeometry } from "../buffers/BufferGeometry";
import { ClearState } from "../ClearState";
import { Program } from "../programs/Program";
import { RenderingContext } from "../RenderingContext";
import { sizeOfDataType } from "../textures/DataType";
import { numPixelFormatComponents, PixelFormat } from "../textures/PixelFormat";
import { TexImage2D } from "../textures/TexImage2D";
import { VertexArrayObject } from "../VertexArrayObject";
import { AttachmentPoints } from "./AttachmentPoints";
import { Attachments } from "./Attachments";

Expand Down Expand Up @@ -52,14 +53,30 @@ export abstract class VirtualFramebuffer implements IDisposable {
gl.clear(attachmentFlags);
}

renderDraw(program: Program, uniforms: any, vao: VertexArrayObject): void {
renderBufferGeometry(program: Program, uniforms: any, bufferGeometry: BufferGeometry): void {
this.context.framebuffer = this;
this.context.program = program;
this.context.program.setUniformValues(uniforms);
this.context.program.setAttributeBuffers(bufferGeometry);

// draw
const gl = this.context.gl;
if (bufferGeometry.indices !== undefined) {
throw new Error("not implemented");
} else {
gl.drawArrays(bufferGeometry.primitive, 0, bufferGeometry.count);
}
}

renderVertexArrayObject(program: Program, uniforms: any, vao: VertexArrayObject): void {
this.context.framebuffer = this;
this.context.program = program;
this.context.program.setUniformValues(uniforms);
this.context.program.setAttributeBuffers(vao);

// draw
this.context.gl.drawArrays(vao.primitive, vao.offset, vao.count);
const gl = this.context.gl;
gl.drawArrays(vao.primitive, vao.offset, vao.count);
}

renderPass(program: Program, uniforms: any): void {
Expand Down
42 changes: 41 additions & 1 deletion src/lib/renderers/webgl2/programs/Program.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,9 @@ import { Dictionary } from "../../../core/Dictionary";
import { IDisposable } from "../../../core/types";
import { ShaderMaterial } from "../../../materials/ShaderMaterial";
import { Pool } from "../../Pool";
import { BufferGeometry } from "../buffers/BufferGeometry";
import { ShaderType } from "../shaders/ShaderType";
import { VertexArrayObject } from "../VertexArrayObject";
import { RenderingContext } from "./../RenderingContext";
import { Shader } from "./../shaders/Shader";
import { ProgramAttribute } from "./ProgramAttribute";
Expand Down Expand Up @@ -75,7 +77,7 @@ export class Program implements IDisposable {
}
}

setUniformValues(uniformValues: any, uniformNames: string[] | undefined = undefined): void {
setUniformValues(uniformValues: any, uniformNames: string[] | undefined = undefined): this {
this.context.program = this;
if (uniformNames === undefined) {
uniformNames = Object.keys(uniformValues) as string[];
Expand All @@ -87,6 +89,44 @@ export class Program implements IDisposable {
uniform.set(uniformValues[uniformName]);
}
});
return this;
}

setAttributeBuffers(vao: VertexArrayObject): this;
setAttributeBuffers(bufferGeometry: BufferGeometry): this;
setAttributeBuffers(buffers: VertexArrayObject | BufferGeometry): this {
const gl = this.context.gl;
if (buffers instanceof BufferGeometry) {
const bufferGeometry = buffers as BufferGeometry;
this.attributes.forEach((attribute, name) => {
const bufferAccessor = bufferGeometry.bufferAccessors.get(name);
if (bufferAccessor !== undefined) {
attribute.setBuffer(bufferAccessor);
}
});
bufferGeometry.bufferAccessors.forEach((bufferAccessor, name) => {
const attribute = this.attributes.get(name);
if (attribute !== undefined) {
gl.enableVertexAttribArray(attribute.glLocation);
// Bind the position buffer.
gl.bindBuffer(gl.ARRAY_BUFFER, bufferAccessor.buffer);

const size = 2; // 2 components per iteration
const type = gl.FLOAT; // the data is 32bit floats
const normalize = false; // don't normalize the data
const stride = 0; // 0 = move forward size * sizeof(type) each iteration to get the next position
const offset = 0; // start at the beginning of the buffer
gl.vertexAttribPointer(attribute.glLocation, size, type, normalize, stride, offset);
}
});
} else if (buffers instanceof VertexArrayObject) {
const vao = buffers as VertexArrayObject;
gl.bindVertexArray(vao.glVertexArrayObject);
} else {
throw new Error("not implemented");
}

return this;
}

dispose(): void {
Expand Down
19 changes: 19 additions & 0 deletions src/lib/renderers/webgl2/programs/ProgramAttribute.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
// * @bhouston
//

import { BufferAccessor } from "../buffers/BufferAccessor";
import { Program } from "./Program";

export class ProgramAttribute {
Expand Down Expand Up @@ -37,4 +38,22 @@ export class ProgramAttribute {
this.glLocation = glLocation;
}
}

setBuffer(bufferAccessor: BufferAccessor): this {
const gl = this.program.context.gl;
gl.enableVertexAttribArray(this.glLocation);
// Bind the position buffer.
gl.bindBuffer(gl.ARRAY_BUFFER, bufferAccessor.buffer);

// Tell the attribute how to get data out of positionBuffer (ARRAY_BUFFER)
gl.vertexAttribPointer(
this.glLocation,
bufferAccessor.componentsPerVertex,
bufferAccessor.componentType,
bufferAccessor.normalized,
bufferAccessor.vertexStride,
bufferAccessor.byteOffset,
);
return this;
}
}

0 comments on commit 705ab3d

Please sign in to comment.