diff options
| author | Tyler Murphy <tylermurphy534@gmail.com> | 2023-01-18 22:43:02 -0500 |
|---|---|---|
| committer | Tyler Murphy <tylermurphy534@gmail.com> | 2023-01-18 22:43:02 -0500 |
| commit | 30cf48cd70f1c52f89362245891be355af110afe (patch) | |
| tree | 5cfee873428a8519c5d117917f3abbb3659b631b /public/gl/core | |
| parent | initial (diff) | |
| download | webgl-30cf48cd70f1c52f89362245891be355af110afe.tar.gz webgl-30cf48cd70f1c52f89362245891be355af110afe.tar.bz2 webgl-30cf48cd70f1c52f89362245891be355af110afe.zip | |
cube
Diffstat (limited to 'public/gl/core')
| -rw-r--r-- | public/gl/core/Camera.js | 18 | ||||
| -rw-r--r-- | public/gl/core/Entity.js | 25 | ||||
| -rw-r--r-- | public/gl/core/Material.js | 46 | ||||
| -rw-r--r-- | public/gl/core/Mesh.js | 48 | ||||
| -rw-r--r-- | public/gl/core/Renderer.js | 79 | ||||
| -rw-r--r-- | public/gl/core/Scene.js | 38 | ||||
| -rw-r--r-- | public/gl/core/Shader.js | 98 |
7 files changed, 352 insertions, 0 deletions
diff --git a/public/gl/core/Camera.js b/public/gl/core/Camera.js new file mode 100644 index 0000000..870c13f --- /dev/null +++ b/public/gl/core/Camera.js @@ -0,0 +1,18 @@ +import { Vec3 } from '../math/Vec3.js' +import { Mat4 } from '../math/Mat4.js' + +export class Camera { + + constructor() { + this.position = new Vec3() + this.rotation = new Vec3() + } + + view() { + return new Mat4() + .identity() + .rot(this.rotation.clone().multS(Math.PI/180)) + .pos(this.position.clone().multS(-1)) + } + +}
\ No newline at end of file diff --git a/public/gl/core/Entity.js b/public/gl/core/Entity.js new file mode 100644 index 0000000..d0d6e4a --- /dev/null +++ b/public/gl/core/Entity.js @@ -0,0 +1,25 @@ +import { Vec3 } from '../math/Vec3.js' +import { Mat4 } from '../math/Mat4.js' + +export class Entity { + + static #id = 0 + + constructor(mesh) { + this.mesh = mesh + this.position = new Vec3() + this.rotation = new Vec3() + this.scale = new Vec3(1, 1, 1) + this.id = Entity.#id + Entity.#id++ + } + + tran() { + return new Mat4() + .identity() + .pos(this.position) + .rot(this.rotation.clone().multS(Math.PI/180)) + .scale(this.scale) + } + +}
\ No newline at end of file diff --git a/public/gl/core/Material.js b/public/gl/core/Material.js new file mode 100644 index 0000000..c99b9e8 --- /dev/null +++ b/public/gl/core/Material.js @@ -0,0 +1,46 @@ +export class Material { + + static #id = 0 + + constructor(shader, data = {}) { + this.shader = shader + this.data = data + this.id = Material.#id + Material.#id++ + } + + set(data) { + this.data = data + return this + } + + bind() { + this.shader.start() + for (const key in this.data) { + const value = this.data[key] + if (typeof value == 'number' && !isNaN(x)) { + if (Number.isInteger(value)) { + this.shader.loadInt(key, value) + } else { + this.shader.loadFloat(key, value) + } + } else if (typeof value == 'boolean') { + this.shader.loadBool(key, value) + } else if (typeof value == 'object') { + const name = value.constructor.name + if (name == 'Vec2') { + this.shader.loadVec2(key, value) + } else if (name == 'Vec3') { + this.shader.loadVec3(key,value) + } else if (name == 'Mat4') { + this.shader.loadMat4(key, value) + } + } + } + } + + unbind() { + this.shader.stop() + } + +}
\ No newline at end of file diff --git a/public/gl/core/Mesh.js b/public/gl/core/Mesh.js new file mode 100644 index 0000000..b35c13c --- /dev/null +++ b/public/gl/core/Mesh.js @@ -0,0 +1,48 @@ +import { gl, ext } from './Renderer.js' + +export class Mesh { + + static #vaos = [] + static #vbos = [] + + #vertexCount + #count + #id + + constructor(vertexCount) { + this.#id = ext.createVertexArrayOES() + ext.bindVertexArrayOES(this.#id) + Mesh.#vaos.push(this.#id) + this.#vertexCount = vertexCount + this.#count = 0 + } + + store(data, dim) { + let id = gl.createBuffer() + Mesh.#vbos.push(id) + gl.bindBuffer(gl.ARRAY_BUFFER, id) + gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(data), gl.STATIC_DRAW) + gl.vertexAttribPointer(this.#count, dim, gl.FLOAT, false, Float32Array.BYTES_PER_ELEMENT * dim, 0) + gl.enableVertexAttribArray(this.#count) + this.#count++; + return this + } + + finish() { + this.unbind() + return this + } + + bind() { + ext.bindVertexArrayOES(this.#id) + } + + unbind() { + ext.bindVertexArrayOES(null) + } + + draw() { + gl.drawArrays(gl.TRIANGLES, 0, this.#vertexCount) + } + +}
\ No newline at end of file diff --git a/public/gl/core/Renderer.js b/public/gl/core/Renderer.js new file mode 100644 index 0000000..32f5e9c --- /dev/null +++ b/public/gl/core/Renderer.js @@ -0,0 +1,79 @@ +import { Mat4 } from '../math/Mat4.js' + +export var gl +export var ext +export var canvas + +export class Renderer { + constructor() { + canvas = document.createElement("canvas") + canvas.id = "canvas" + canvas.width = window.innerWidth + canvas.height = window.innerHeight + canvas.style = "display: block;" + document.body.appendChild(canvas) + document.body.style.margin = 0 + + gl = canvas.getContext('webgl') + + if(!gl) { + console.log("Your browser does not support webgl") + return + } + + ext = gl.getExtension('OES_vertex_array_object'); + if(!ext) { + console.log("Your browser does not support webgl 2") + return + } + + window.onresize = (event) => { + canvas.width = window.innerWidth + canvas.height = window.innerHeight + gl.viewport(0, 0, canvas.width, canvas.height) + } + } + + draw(scene, camera) { + for (const material_id in scene.map) { + const material = scene.materials[material_id] + gl.enable(gl.DEPTH_TEST); + gl.enable(gl.CULL_FACE); + gl.cullFace(gl.BACK); + gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT); + gl.clearColor(0, 0, 0, 1); + material.bind() + material.shader.loadMat4("proj", this.proj()) + material.shader.loadMat4("view", camera.view()) + scene.map[material_id].forEach((entity_id) => { + const entity = scene.entities[entity_id] + material.shader.loadMat4("tran", entity.tran()) + entity.mesh.bind() + entity.mesh.draw() + entity.mesh.unbind() + }) + material.unbind() + } + } + + proj() { + const fov = 90 + const far = 100 + const near = 0.1 + + const aspect = canvas.width / canvas.height + const f = 1.0 / Math.tan((fov * (Math.PI/180)) / 2) + const fa = f / aspect + const nf = 1.0 / (near - far) + + const c1 = (near + far) * nf + const c2 = near * far * nf * 2 + + return new Mat4().set( + fa, 0, 0, 0, + 0, f, 0, 0, + 0, 0, c1, c2, + 0, 0, -1, 0 + ) + } +}
\ No newline at end of file diff --git a/public/gl/core/Scene.js b/public/gl/core/Scene.js new file mode 100644 index 0000000..568fe37 --- /dev/null +++ b/public/gl/core/Scene.js @@ -0,0 +1,38 @@ +export class Scene { + + constructor() { + this.map = {} + this.entities = {} + this.materials = {} + } + + add(material, entity) { + var arr = this.map[material.id] + if (arr == undefined) { + arr = [] + this.materials[material.id] = material + } + if (!arr.includes(entity.id)) { + arr.push(entity.id) + this.entities[entity.id] = entity + } + this.map[material.id] = arr + } + + remove(material, entity) { + var arr = this.objects[material.id] + if (arr == undefined) { + return + } + const i = arr.indexOf(entity.id) + if(i > -1) { + arr = arr.splice(i, 1) + delete this.entities[entity.id] + if(arr.length < 1) { + delete this.map[material.id] + delete this.materials[material.id] + } + } + } + +}
\ No newline at end of file diff --git a/public/gl/core/Shader.js b/public/gl/core/Shader.js new file mode 100644 index 0000000..f5e0a88 --- /dev/null +++ b/public/gl/core/Shader.js @@ -0,0 +1,98 @@ +import { gl } from './Renderer.js' + +export class Shader { + + #vertexShader; + #fragmentShader; + #program; + #attributes; + #uniforms; + + constructor(vertexCode, fragmentCode) { + + this.#vertexShader = gl.createShader(gl.VERTEX_SHADER) + this.#fragmentShader = gl.createShader(gl.FRAGMENT_SHADER) + + gl.shaderSource(this.#vertexShader, vertexCode) + gl.shaderSource(this.#fragmentShader, fragmentCode) + + gl.compileShader(this.#vertexShader) + if (!gl.getShaderParameter(this.#vertexShader, gl.COMPILE_STATUS)) { + console.error('Failed to compile vertex shader!', gl.getShaderInfoLog(this.#vertexShader)) + return + } + + gl.compileShader(this.#fragmentShader) + if (!gl.getShaderParameter(this.#fragmentShader, gl.COMPILE_STATUS)) { + console.error('Failed to compile fragment shader!', gl.getShaderInfoLog(this.#fragmentShader)) + return + } + + this.#program = gl.createProgram() + gl.attachShader(this.#program, this.#vertexShader) + gl.attachShader(this.#program, this.#fragmentShader) + gl.linkProgram(this.#program) + if (!gl.getProgramParameter(this.#program, gl.LINK_STATUS)) { + console.error("Failed to link shader program!", gl.getProgramInfoLog(this.#program)); + return + } + + gl.validateProgram(this.#program); + if (!gl.getProgramParameter(this.#program, gl.VALIDATE_STATUS)) { + console.error("Failed to validate shader program!", gl.getProgramInfoLog(this.#program)); + return + } + + this.#attributes = [] + this.#uniforms = {} + + vertexCode.split('\n').forEach((line) => { + const tokens = line.split(" ") + if (tokens.length != 3) return + if (tokens[0] === "attribute") { + this.#attributes.push(tokens[2].replace(/\s+/g, '').split(';')[0]) + } + if (tokens[0] == "uniform") { + const loc = gl.getUniformLocation(this.#program, tokens[2].replace(/\s+/g, '').split(';')[0]) + this.#uniforms[tokens[2].replace(/\s+/g, '').split(';')[0]] = loc + } + }) + + } + + start() { + gl.useProgram(this.#program) + for (let i = 0; i < this.#attributes.length; i++) { + gl.bindAttribLocation(this.#program, i, this.#attributes[i]) + } + } + + stop() { + gl.useProgram(null) + } + + loadFloat(name, float) { + gl.uniform1f(this.#uniforms[name], float) + } + + loadInt(name, int) { + gl.uniform1i(this.#uniforms[name], int) + } + + loadVec2(name, v) { + gl.uniform2f(this.#uniforms[name], v.x, v.y) + } + + loadVec3(name, v) { + gl.uniform3f(this.#uniforms[name], v.x, v.y, v.z) + } + + loadMat4(name, m) { + gl.uniformMatrix4fv(this.#uniforms[name], gl.FALSE, new Float32Array(m.get())) + } + + loadBool(name, bool) { + gl.uniform1f(this.#uniforms[name], bool ? 1 : 0) + } + +}
\ No newline at end of file |