From 0d8b0fa1ea0f7c2184b0db51ae1d3064609e3997 Mon Sep 17 00:00:00 2001 From: Rohan Julka Date: Tue, 28 May 2024 13:41:44 +0100 Subject: [PATCH] textures support while parsing obj and mtl files --- src/webgl/loading.js | 38 ++++++++++++++++++++++--- src/webgl/p5.Geometry.js | 32 +++++++++++++++++++-- src/webgl/p5.RendererGL.Retained.js | 44 ++++++++++++++++------------- 3 files changed, 87 insertions(+), 27 deletions(-) diff --git a/src/webgl/loading.js b/src/webgl/loading.js index bc1808f913..265c0139a4 100755 --- a/src/webgl/loading.js +++ b/src/webgl/loading.js @@ -531,8 +531,8 @@ function parseMtl(p5,mtlPath){ ]; }else if (tokens[0] === 'map_Kd') { - //Texture path - materials[currentMaterial].texturePath = tokens[1]; + // Diffuse Texture path + materials[currentMaterial].diffuseTexturePath = tokens[1]; } } resolve(materials); @@ -585,6 +585,17 @@ function parseObj(model, lines, materials= {}) { if (tokens[0] === 'usemtl') { // Switch to a new material currentMaterial = tokens[1]; + if( materials[currentMaterial] + && materials[currentMaterial].diffuseTexturePath + ) { + if (!model.textures[currentMaterial]) { + model.textures[currentMaterial] = {}; + } + model.hasTextures = true; + model.textures[currentMaterial].diffuseTexture = + loadImage(materials[currentMaterial].diffuseTexturePath); + model.textures[currentMaterial].faces = [] ; + } }else if (tokens[0] === 'v' || tokens[0] === 'vn') { // Check if this line describes a vertex or vertex normal. // It will have three numeric parameters. @@ -651,8 +662,15 @@ function parseObj(model, lines, materials= {}) { face[0] !== face[2] && face[1] !== face[2] ) { - model.faces.push(face); //same material for all vertices in a particular face + if (currentMaterial + && model.textures[currentMaterial] + && model.textures[currentMaterial].diffuseTexture + ) { + model.textures[currentMaterial].faces.push(face); + } else { + model.faces.push(face); + } if (currentMaterial && materials[currentMaterial] && materials[currentMaterial].diffuseColor) { @@ -1125,7 +1143,19 @@ p5.prototype.model = function(model) { this._renderer.createBuffers(model.gid, model); } - this._renderer.drawBuffers(model.gid); + // If model has textures for each texture update index buffer and invoke draw call. + if(model.hasTextures) { + this._renderer.updateIndexBuffer(model.gid, model.faces); + this._renderer.drawBuffers(model.gid); + for (let material of Object.keys(model.textures)) { + const texture = model.textures[material]; + this._renderer.updateIndexBuffer(model.gid, texture.faces); + this._renderer._tex = texture.diffuseTexture; + this._renderer.drawBuffers(model.gid); + } + } else { + this._renderer.drawBuffers(model.gid); + } } }; diff --git a/src/webgl/p5.Geometry.js b/src/webgl/p5.Geometry.js index ed48495b4d..583a1da12d 100644 --- a/src/webgl/p5.Geometry.js +++ b/src/webgl/p5.Geometry.js @@ -62,6 +62,11 @@ p5.Geometry = class Geometry { // One color per vertex representing the stroke color at that vertex this.vertexStrokeColors = []; + // Map storing the textures and faces for each texture + this.textures = {}; + + this.hasTextures = false; + // One color per line vertex, generated automatically based on // vertexStrokeColors in _edgesToVertices() this.lineVertexColors = new p5.DataArray(); @@ -707,10 +712,18 @@ p5.Geometry = class Geometry { _makeTriangleEdges() { this.edges.length = 0; + const _addEdge = face => { + this.edges.push([face[0], face[1]]); + this.edges.push([face[1], face[2]]); + this.edges.push([face[2], face[0]]); + }; + for (let j = 0; j < this.faces.length; j++) { - this.edges.push([this.faces[j][0], this.faces[j][1]]); - this.edges.push([this.faces[j][1], this.faces[j][2]]); - this.edges.push([this.faces[j][2], this.faces[j][0]]); + _addEdge(this.faces[j]); + } + + for (let material of Object.keys(this.textures)) { + this.textures[material].faces.map(face => _addEdge(face)); } return this; @@ -1003,5 +1016,18 @@ p5.Geometry = class Geometry { } return this; } + + /** + * When using textures each material contains all the face indices for that texture. + * this function collects all the faces mapped to different textures in a single array + * @method collectFaces + */ + collectFaces() { + const faces = []; + for (let materialName of Object.keys(this.textures)) { + faces.push(this.textures[materialName]['faces']); + } + return faces.flat(); + } }; export default p5.Geometry; diff --git a/src/webgl/p5.RendererGL.Retained.js b/src/webgl/p5.RendererGL.Retained.js index 9bd05739c8..189e9b71eb 100644 --- a/src/webgl/p5.RendererGL.Retained.js +++ b/src/webgl/p5.RendererGL.Retained.js @@ -64,6 +64,29 @@ p5.RendererGL.prototype._freeBuffers = function(gId) { freeBuffers(this.retainedMode.buffers.fill); }; +p5.RendererGL.prototype.updateIndexBuffer = function(gId, faces) { + const gl = this.GL; + const buffers = this.retainedMode.geometry[gId]; + let indexBuffer = buffers.indexBuffer; + + if (!indexBuffer) indexBuffer = buffers.indexBuffer = gl.createBuffer(); + const vals = p5.RendererGL.prototype._flatten(faces); + + // If any face references a vertex with an index greater than the maximum + // un-singed 16 bit integer, then we need to use a Uint32Array instead of a + // Uint16Array + + const hasVertexIndicesOverMaxUInt16 = vals.some(v => v > 65535); + let type = hasVertexIndicesOverMaxUInt16 ? Uint32Array : Uint16Array; + this._bindBuffer(indexBuffer, gl.ELEMENT_ARRAY_BUFFER, vals, type); + buffers.indexBufferType = hasVertexIndicesOverMaxUInt16 + ? gl.UNSIGNED_INT + : gl.UNSIGNED_SHORT; + + // the vertex count is based on the number of faces + buffers.vertexCount = faces.length * 3; +}; + /** * creates a buffers object that holds the WebGL render buffers * for a geometry. @@ -80,26 +103,7 @@ p5.RendererGL.prototype.createBuffers = function(gId, model) { let indexBuffer = buffers.indexBuffer; if (model.faces.length) { - // allocate space for faces - if (!indexBuffer) indexBuffer = buffers.indexBuffer = gl.createBuffer(); - const vals = p5.RendererGL.prototype._flatten(model.faces); - - // If any face references a vertex with an index greater than the maximum - // un-singed 16 bit integer, then we need to use a Uint32Array instead of a - // Uint16Array - const hasVertexIndicesOverMaxUInt16 = vals.some(v => v > 65535); - let type = hasVertexIndicesOverMaxUInt16 ? Uint32Array : Uint16Array; - this._bindBuffer(indexBuffer, gl.ELEMENT_ARRAY_BUFFER, vals, type); - - // If we're using a Uint32Array for our indexBuffer we will need to pass a - // different enum value to WebGL draw triangles. This happens in - // the _drawElements function. - buffers.indexBufferType = hasVertexIndicesOverMaxUInt16 - ? gl.UNSIGNED_INT - : gl.UNSIGNED_SHORT; - - // the vertex count is based on the number of faces - buffers.vertexCount = model.faces.length * 3; + this.updateIndexBuffer(gId, model.faces); } else { // the index buffer is unused, remove it if (indexBuffer) {