From ca314d734a69e539be49b55f6faf1608e6ec161a Mon Sep 17 00:00:00 2001 From: RandomityGuy <31925790+RandomityGuy@users.noreply.github.com> Date: Fri, 28 Jun 2024 13:45:27 +0530 Subject: [PATCH] multimaterial optimization --- src/DifBuilder.hx | 19 +++-- src/DtsObject.hx | 34 +++++---- src/InstanceManager.hx | 156 +++++++++++++++++++++++------------------ src/Polygon.hx | 49 +++++++++---- 4 files changed, 161 insertions(+), 97 deletions(-) diff --git a/src/DifBuilder.hx b/src/DifBuilder.hx index 6cbed055..7cda4399 100644 --- a/src/DifBuilder.hx +++ b/src/DifBuilder.hx @@ -1,5 +1,6 @@ package src; +import h3d.scene.MultiMaterial; import shaders.NormalMaterial; import shaders.NoiseTileMaterial; import shaders.DirLight; @@ -672,6 +673,10 @@ class DifBuilder { onFinish(); }); + var prim = new Polygon(); + + var materials = []; + for (grp => tris in mats) { var points = []; var normals = []; @@ -696,9 +701,12 @@ class DifBuilder { uvs.push(uv2); uvs.push(uv1); } - var prim = new Polygon(points); - prim.setUVs(uvs); - prim.setNormals(normals); + + prim.addPoints(points); + prim.addUVs(uvs); + prim.addNormals(normals); + prim.nextMaterial(); + var material:Material; var texture:Texture; if (canFindTex(grp)) { @@ -740,9 +748,12 @@ class DifBuilder { // material.mainPass.addShader(new h3d.shader.pbr.PropsValues(1, 0, 0, 1)); if (Debug.wireFrame) material.mainPass.wireframe = true; - var mesh = new Mesh(prim, material, itr); + materials.push(material); } + prim.endPrimitive(); + var mesh = new MultiMaterial(prim, materials, itr); + shaderWorker.run(); }); for (f in loadtexs) { diff --git a/src/DtsObject.hx b/src/DtsObject.hx index fe4548d5..fb6e3c2c 100644 --- a/src/DtsObject.hx +++ b/src/DtsObject.hx @@ -1,5 +1,6 @@ package src; +import h3d.scene.MultiMaterial; import shaders.EnvMap; import h3d.shader.CubeMap; import dts.TSDrawPrimitive; @@ -196,28 +197,33 @@ class DtsObject extends GameObject { var vertexNormals = mesh.normals.map(v -> new Vector(-v.x, v.y, v.z)); var geometry = this.generateMaterialGeometry(mesh, vertices, vertexNormals); + var poly = new Polygon(); + var usedMats = []; for (k in 0...geometry.length) { if (geometry[k].vertices.length == 0) continue; - var poly = new Polygon(geometry[k].vertices.map(x -> x.toPoint())); - poly.setNormals(geometry[k].normals.map(x -> x.toPoint())); - poly.setUVs(geometry[k].uvs); + poly.addPoints(geometry[k].vertices.map(x -> x.toPoint())); + poly.addNormals(geometry[k].normals.map(x -> x.toPoint())); + poly.addUVs(geometry[k].uvs); + poly.nextMaterial(); - var obj = new Mesh(poly, materials[k], this.graphNodes[i]); + usedMats.push(materials[k]); } + poly.endPrimitive(); + var obj = new MultiMaterial(poly, usedMats, this.graphNodes[i]); } else { - var usedMats = []; + // var usedMats = []; - for (prim in mesh.primitives) { - if (!usedMats.contains(prim.matIndex)) { - usedMats.push(prim.matIndex); - } - } + // for (prim in mesh.primitives) { + // if (!usedMats.contains(prim.matIndex)) { + // usedMats.push(prim.matIndex); + // } + // } - for (k in usedMats) { - var obj = new Object(this.graphNodes[i]); - } + // for (k in usedMats) { + var obj = new Object(this.graphNodes[i]); + // } } } } @@ -274,7 +280,7 @@ class DtsObject extends GameObject { poly.normals = geometry[k].normals.map(x -> x.toPoint()); poly.uvs = geometry[k].uvs; - var obj = new Mesh(poly, materials[k], skinObj); + var obj = new MultiMaterial(poly, [materials[k]], skinObj); } skinMeshData = { meshIndex: i, diff --git a/src/InstanceManager.hx b/src/InstanceManager.hx index 2c0562f1..4a5937d4 100644 --- a/src/InstanceManager.hx +++ b/src/InstanceManager.hx @@ -1,5 +1,7 @@ package src; +import h3d.mat.Material; +import h3d.scene.MultiMaterial; import shaders.EnvMap; import h3d.shader.CubeMap; import shaders.NormalMaterial; @@ -160,8 +162,8 @@ class InstanceManager { } var transform = instance.emptyObj.getAbsPos(); // minfo.meshbatch.shadersChanged = true; - minfo.meshbatch.material.mainPass.setPassName(minfo.mesh.material.mainPass.name); - minfo.meshbatch.material.mainPass.enableLights = minfo.mesh.material.mainPass.enableLights; + // minfo.meshbatch.material.mainPass.setPassName(minfo.mesh.material.mainPass.name); + // minfo.meshbatch.material.mainPass.enableLights = minfo.mesh.material.mainPass.enableLights; minfo.meshbatch.worldPosition = transform; minfo.meshbatch.emitInstance(); } @@ -177,7 +179,7 @@ class InstanceManager { // minfo.transparencymeshbatch.material.color.a = instance.gameObject.currentOpacity; // minfo.transparencymeshbatch.material.mainPass.setPassName(minfo.mesh.material.mainPass.name); // minfo.transparencymeshbatch.shadersChanged = true; - minfo.transparencymeshbatch.material.mainPass.enableLights = minfo.mesh.material.mainPass.enableLights; + // minfo.transparencymeshbatch.material.mainPass.enableLights = minfo.mesh.material.mainPass.enableLights; // minfo.transparencymeshbatch.material.mainPass.depthWrite = false; // if (dtsShader != null) { // dtsShader.currentOpacity = instance.gameObject.currentOpacity; @@ -214,79 +216,99 @@ class InstanceManager { var objs = getAllChildren(object); var minfos = []; for (obj in objs) { - var isMesh = obj is Mesh; + var isMesh = obj is MultiMaterial; var minfo:MeshBatchInfo = new MeshBatchInfo(); minfo.instances = [new MeshInstance(obj, object)]; - minfo.meshbatch = isMesh ? new MeshBatch(cast(cast(obj, Mesh).primitive), cast(cast(obj, Mesh)).material.clone(), scene) : null; + minfo.meshbatch = isMesh ? new MeshBatch(cast(cast(obj, MultiMaterial).primitive), null, scene) : null; minfo.mesh = isMesh ? cast obj : null; minfo.baseBounds = isMesh ? @:privateAccess cast(minfo.meshbatch.primitive, Instanced).baseBounds : null; if (isMesh) { - var mat = cast(obj, Mesh).material; - var dtsshader = mat.mainPass.getShader(DtsTexture); - if (dtsshader != null) { - minfo.meshbatch.material.mainPass.removeShader(minfo.meshbatch.material.textureShader); - minfo.meshbatch.material.mainPass.addShader(dtsshader); - minfo.meshbatch.material.mainPass.culling = mat.mainPass.culling; - minfo.meshbatch.material.mainPass.depthWrite = mat.mainPass.depthWrite; - minfo.meshbatch.material.mainPass.blendSrc = mat.mainPass.blendSrc; - minfo.meshbatch.material.mainPass.blendDst = mat.mainPass.blendDst; - minfo.meshbatch.material.mainPass.blendOp = mat.mainPass.blendOp; - minfo.meshbatch.material.mainPass.blendAlphaSrc = mat.mainPass.blendAlphaSrc; - minfo.meshbatch.material.mainPass.blendAlphaDst = mat.mainPass.blendAlphaDst; - minfo.meshbatch.material.mainPass.blendAlphaOp = mat.mainPass.blendAlphaOp; - minfo.dtsShader = dtsshader; - } - var phongshader = mat.mainPass.getShader(PhongMaterial); - if (phongshader != null) { - minfo.meshbatch.material.mainPass.removeShader(minfo.meshbatch.material.textureShader); - minfo.meshbatch.material.mainPass.addShader(phongshader); - // minfo.meshbatch.material.mainPass.culling = mat.mainPass.culling; - } - var noiseshder = mat.mainPass.getShader(NoiseTileMaterial); - if (noiseshder != null) { - minfo.meshbatch.material.mainPass.removeShader(minfo.meshbatch.material.textureShader); - minfo.meshbatch.material.mainPass.addShader(noiseshder); - // minfo.meshbatch.material.mainPass.culling = mat.mainPass.culling; - } - var nmapshdr = mat.mainPass.getShader(NormalMaterial); - if (nmapshdr != null) { - minfo.meshbatch.material.mainPass.removeShader(minfo.meshbatch.material.textureShader); - minfo.meshbatch.material.mainPass.addShader(nmapshdr); - // minfo.meshbatch.material.mainPass.culling = mat.mainPass.culling; - } - var cubemapshdr = mat.mainPass.getShader(EnvMap); - if (cubemapshdr != null) { - minfo.meshbatch.material.mainPass.addShader(cubemapshdr); - } - minfo.transparencymeshbatch = new MeshBatch(cast(cast(obj, Mesh).primitive), cast(cast(obj, Mesh)).material.clone(), scene); - minfo.transparencymeshbatch.material.mainPass.removeShader(minfo.meshbatch.material.textureShader); - minfo.transparencymeshbatch.material.mainPass.addShader(dtsshader); + minfo.meshbatch.materials = []; + for (mat in cast(obj, MultiMaterial).materials) { + var matclone:Material = cast mat.clone(); + var dtsshader = mat.mainPass.getShader(DtsTexture); + if (dtsshader != null) { + matclone.mainPass.removeShader(matclone.textureShader); + matclone.mainPass.addShader(dtsshader); + matclone.mainPass.culling = mat.mainPass.culling; + matclone.mainPass.depthWrite = mat.mainPass.depthWrite; + matclone.mainPass.blendSrc = mat.mainPass.blendSrc; + matclone.mainPass.blendDst = mat.mainPass.blendDst; + matclone.mainPass.blendOp = mat.mainPass.blendOp; + matclone.mainPass.blendAlphaSrc = mat.mainPass.blendAlphaSrc; + matclone.mainPass.blendAlphaDst = mat.mainPass.blendAlphaDst; + matclone.mainPass.blendAlphaOp = mat.mainPass.blendAlphaOp; + minfo.dtsShader = dtsshader; + } + var phongshader = mat.mainPass.getShader(PhongMaterial); + if (phongshader != null) { + matclone.mainPass.removeShader(matclone.textureShader); + matclone.mainPass.addShader(phongshader); + // minfo.meshbatch.material.mainPass.culling = mat.mainPass.culling; + } + var noiseshder = mat.mainPass.getShader(NoiseTileMaterial); + if (noiseshder != null) { + matclone.mainPass.removeShader(matclone.textureShader); + matclone.mainPass.addShader(noiseshder); + // minfo.meshbatch.material.mainPass.culling = mat.mainPass.culling; + } + var nmapshdr = mat.mainPass.getShader(NormalMaterial); + if (nmapshdr != null) { + matclone.mainPass.removeShader(matclone.textureShader); + matclone.mainPass.addShader(nmapshdr); + // minfo.meshbatch.material.mainPass.culling = mat.mainPass.culling; + } + var cubemapshdr = mat.mainPass.getShader(EnvMap); + if (cubemapshdr != null) { + matclone.mainPass.addShader(cubemapshdr); + } + matclone.mainPass.enableLights = mat.mainPass.enableLights; + matclone.mainPass.setPassName(mat.mainPass.name); - minfo.transparencymeshbatch.material.blendMode = Alpha; + for (p in matclone.getPasses()) + @:privateAccess p.batchMode = true; + minfo.meshbatch.materials.push(matclone); - minfo.transparencymeshbatch.material.mainPass.culling = mat.mainPass.culling; - minfo.transparencymeshbatch.material.mainPass.depthWrite = mat.mainPass.depthWrite; - if (mat.blendMode == Alpha) { - minfo.transparencymeshbatch.material.mainPass.blendSrc = mat.mainPass.blendSrc; - minfo.transparencymeshbatch.material.mainPass.blendDst = mat.mainPass.blendDst; - minfo.transparencymeshbatch.material.mainPass.blendOp = mat.mainPass.blendOp; - minfo.transparencymeshbatch.material.mainPass.blendAlphaSrc = mat.mainPass.blendAlphaSrc; - minfo.transparencymeshbatch.material.mainPass.blendAlphaDst = mat.mainPass.blendAlphaDst; - minfo.transparencymeshbatch.material.mainPass.blendAlphaOp = mat.mainPass.blendAlphaOp; - minfo.transparencymeshbatch.material.mainPass.enableLights = mat.mainPass.enableLights; - minfo.transparencymeshbatch.material.receiveShadows = mat.receiveShadows; + var matclonetransp:Material = cast mat.clone(); + + minfo.transparencymeshbatch = new MeshBatch(cast(cast(obj, MultiMaterial).primitive), null, scene); + minfo.transparencymeshbatch.materials = []; + + matclonetransp.mainPass.removeShader(minfo.meshbatch.material.textureShader); + matclonetransp.mainPass.addShader(dtsshader); + + matclonetransp.blendMode = Alpha; + + matclonetransp.mainPass.culling = mat.mainPass.culling; + matclonetransp.mainPass.depthWrite = mat.mainPass.depthWrite; + if (mat.blendMode == Alpha) { + matclonetransp.mainPass.blendSrc = mat.mainPass.blendSrc; + matclonetransp.mainPass.blendDst = mat.mainPass.blendDst; + matclonetransp.mainPass.blendOp = mat.mainPass.blendOp; + matclonetransp.mainPass.blendAlphaSrc = mat.mainPass.blendAlphaSrc; + matclonetransp.mainPass.blendAlphaDst = mat.mainPass.blendAlphaDst; + matclonetransp.mainPass.blendAlphaOp = mat.mainPass.blendAlphaOp; + matclonetransp.mainPass.enableLights = mat.mainPass.enableLights; + matclonetransp.receiveShadows = mat.receiveShadows; + } + + matclonetransp.mainPass.enableLights = mat.mainPass.enableLights; + + for (p in matclonetransp.getPasses()) + @:privateAccess p.batchMode = true; + minfo.transparencymeshbatch.materials.push(matclonetransp); + // minfo.transparencymeshbatch.material.mainPass.culling = mat.mainPass.culling; + + // minfo.meshbatch.material.mainPass.removeShader(minfo.meshbatch.material.mainPass.getShader(PropsValues)); + // minfo.transparencymeshbatch.material.mainPass.removeShader(minfo.transparencymeshbatch.material.mainPass.getShader(PropsValues)); + + // var pbrshader = mat.mainPass.getShader(PropsValues); + // if (pbrshader != null) { + // minfo.meshbatch.material.mainPass.addShader(pbrshader); + // minfo.transparencymeshbatch.material.mainPass.addShader(pbrshader); + // } } - // minfo.transparencymeshbatch.material.mainPass.culling = mat.mainPass.culling; - - // minfo.meshbatch.material.mainPass.removeShader(minfo.meshbatch.material.mainPass.getShader(PropsValues)); - // minfo.transparencymeshbatch.material.mainPass.removeShader(minfo.transparencymeshbatch.material.mainPass.getShader(PropsValues)); - - // var pbrshader = mat.mainPass.getShader(PropsValues); - // if (pbrshader != null) { - // minfo.meshbatch.material.mainPass.addShader(pbrshader); - // minfo.transparencymeshbatch.material.mainPass.addShader(pbrshader); - // } } minfos.push(minfo); } diff --git a/src/Polygon.hx b/src/Polygon.hx index 02bcf7b5..c13ad057 100644 --- a/src/Polygon.hx +++ b/src/Polygon.hx @@ -10,34 +10,40 @@ class Polygon extends MeshPrimitive { public var tangents:Array; public var uvs:Array; public var idx:hxd.IndexBuffer; + public var indexStarts:Array; + public var indexCounts:Array; + + var currentMaterial:Int = 0; + var curTris = 0; var bounds:h3d.col.Bounds; - var scaled = 1.; - var translatedX = 0.; - var translatedY = 0.; - var translatedZ = 0.; - - public function new(points:Array, ?idx) { + public function new(?idx) { + this.indexStarts = [0]; + this.indexCounts = []; + this.idx = idx; this.points = []; + this.uvs = []; + this.normals = []; + } + + public function addPoints(points:Array) { for (p in points) { this.points.push(p.x); this.points.push(p.y); this.points.push(p.z); } - this.idx = idx; + curTris += Math.floor(points.length / 3); } - public function setUVs(uvs:Array) { - this.uvs = []; + public function addUVs(uvs:Array) { for (uv in uvs) { this.uvs.push(uv.u); this.uvs.push(uv.v); } } - public function setNormals(normals:Array) { - this.normals = []; + public function addNormals(normals:Array) { for (n in normals) { this.normals.push(n.x); this.normals.push(n.y); @@ -45,6 +51,17 @@ class Polygon extends MeshPrimitive { } } + public function nextMaterial() { + indexStarts.push(Math.floor(this.points.length / 9)); + indexCounts.push(curTris); + curTris = 0; + } + + public function endPrimitive() { + indexCounts.push(curTris); + curTris = 0; + } + override function getBounds() { if (bounds == null) { var b = new h3d.col.Bounds(); @@ -182,6 +199,14 @@ class Polygon extends MeshPrimitive { return Std.int(points.length / 3); } + override function selectMaterial(material:Int) { + currentMaterial = material; + } + + override function getMaterialIndexes(material:Int):{count:Int, start:Int} { + return {start: indexStarts[material] * 3, count: indexCounts[material] * 3}; + } + override function render(engine:h3d.Engine) { if (buffer == null || buffer.isDisposed()) alloc(engine); @@ -191,6 +216,6 @@ class Polygon extends MeshPrimitive { else if (buffer.flags.has(Quads)) engine.renderMultiBuffers(bufs, engine.mem.quadIndexes, 0, triCount()); else - engine.renderMultiBuffers(bufs, engine.mem.triIndexes, 0, triCount()); + engine.renderMultiBuffers(bufs, engine.mem.triIndexes, indexStarts[currentMaterial], indexCounts[currentMaterial]); } }