From dc0f2df24655ecb70c3a739f498be6234f94696e Mon Sep 17 00:00:00 2001 From: RandomityGuy <31925790+RandomityGuy@users.noreply.github.com> Date: Fri, 2 Feb 2024 14:33:41 +0530 Subject: [PATCH] shader optim --- src/InstanceManager.hx | 2 +- src/MarbleWorld.hx | 2 +- src/MeshBatch.hx | 440 ++++++++++++++++++ src/Renderer.hx | 3 +- src/shaders/DefaultCubemapMaterial.hx | 3 +- src/shaders/DefaultCubemapNormalMaterial.hx | 3 +- .../DefaultCubemapNormalNoSpecMaterial.hx | 3 +- src/shaders/DefaultDiffuseMaterial.hx | 3 +- src/shaders/DefaultMaterial.hx | 3 +- src/shaders/DefaultNormalMaterial.hx | 3 +- src/shaders/NoiseTileMaterial.hx | 3 +- src/shaders/RefractMaterial.hx | 3 +- src/shaders/RendererDefaultPass.hx | 155 ++++++ src/shaders/marble/ClassicGlass.hx | 1 + src/shaders/marble/ClassicGlassPureSphere.hx | 1 + src/shaders/marble/ClassicMarb.hx | 1 + src/shaders/marble/ClassicMarb2.hx | 1 + src/shaders/marble/ClassicMarb3.hx | 1 + src/shaders/marble/ClassicMetal.hx | 1 + src/shaders/marble/CrystalMarb.hx | 1 + 20 files changed, 622 insertions(+), 11 deletions(-) create mode 100644 src/MeshBatch.hx create mode 100644 src/shaders/RendererDefaultPass.hx diff --git a/src/InstanceManager.hx b/src/InstanceManager.hx index 9f87447d..e2df72fa 100644 --- a/src/InstanceManager.hx +++ b/src/InstanceManager.hx @@ -16,7 +16,7 @@ import src.GameObject; import h3d.scene.Scene; import h3d.scene.Object; import h3d.scene.Mesh; -import h3d.scene.MeshBatch; +import src.MeshBatch; import src.MarbleGame; import src.ProfilerUI; diff --git a/src/MarbleWorld.hx b/src/MarbleWorld.hx index 70548d49..7d27bc6a 100644 --- a/src/MarbleWorld.hx +++ b/src/MarbleWorld.hx @@ -86,7 +86,7 @@ import collision.SphereCollisionEntity; import src.Sky; import h3d.scene.Mesh; import src.InstanceManager; -import h3d.scene.MeshBatch; +import src.MeshBatch; import src.DtsObject; import src.PathedInterior; import hxd.Key; diff --git a/src/MeshBatch.hx b/src/MeshBatch.hx new file mode 100644 index 00000000..51347d34 --- /dev/null +++ b/src/MeshBatch.hx @@ -0,0 +1,440 @@ +package src; + +import h3d.scene.RenderContext; +import h3d.Matrix; +import h3d.scene.MultiMaterial; +import hxsl.ShaderList; + +private class BatchData { + public var paramsCount:Int; + public var maxInstance:Int; + public var matIndex:Int; + public var indexCount:Int; + public var indexStart:Int; + public var instanceBuffers:Array; + public var buffers:Array = []; + public var data:hxd.FloatBuffer; + public var params:hxsl.RuntimeShader.AllocParam; + public var shader:hxsl.BatchShader; + public var shaders:Array; + public var pass:h3d.mat.Pass; + public var next:BatchData; + + public function new() {} +} + +class MeshBatchPart { + public var indexStart:Int; + public var indexCount:Int; + public var baseVertex:Int; + public var bounds:h3d.col.Bounds; + + public function new() {} +} + +/** + h3d.scene.MeshBatch allows to draw multiple meshed in a single draw call. + See samples/MeshBatch.hx for an example. +**/ +class MeshBatch extends MultiMaterial { + static var modelViewID = hxsl.Globals.allocID("global.modelView"); + static var modelViewTransposeID = hxsl.Globals.allocID("global.modelViewTranspose"); + static var modelViewInverseID = hxsl.Globals.allocID("global.modelViewInverse"); + static var MAX_BUFFER_ELEMENTS = 4096; + + var instanced:h3d.prim.Instanced; + var dataPasses:BatchData; + var needUpload = false; + + /** + Set if shader list or shader constants has changed, before calling begin() + **/ + public var shadersChanged = true; + + /** + The number of instances on this batch + **/ + public var instanceCount(default, null):Int = 0; + + /** + * If set, use this position in emitInstance() instead MeshBatch absolute position + **/ + public var worldPosition:Matrix; + + var invWorldPosition:Matrix; + + /** + Tells the mesh batch to draw only a subpart of the primitive + **/ + public var primitiveSubPart:MeshBatchPart; + + var primitiveSubBytes:haxe.io.Bytes; + + /** + If set, exact bounds will be recalculated during emitInstance (default true) + **/ + public var calcBounds = true; + + var instancedParams:hxsl.Cache.BatchInstanceParams; + + public function new(primitive, ?material, ?parent) { + instanced = new h3d.prim.Instanced(); + instanced.commands = new h3d.impl.InstanceBuffer(); + instanced.setMesh(primitive); + super(instanced, material == null ? null : [material], parent); + for (p in this.material.getPasses()) + @:privateAccess p.batchMode = true; + } + + override function onRemove() { + super.onRemove(); + cleanPasses(); + } + + function cleanPasses() { + var alloc = hxd.impl.Allocator.get(); + while (dataPasses != null) { + dataPasses.pass.removeShader(dataPasses.shader); + for (b in dataPasses.buffers) + alloc.disposeBuffer(b); + if (dataPasses.instanceBuffers != null) { + for (b in dataPasses.instanceBuffers) + b.dispose(); + } + alloc.disposeFloats(dataPasses.data); + dataPasses = dataPasses.next; + } + if (instanced.commands != null) + instanced.commands.dispose(); + shadersChanged = true; + } + + function initShadersMapping() { + var scene = getScene(); + if (scene == null) + return; + cleanPasses(); + for (index in 0...materials.length) { + var mat = materials[index]; + if (mat == null) + continue; + var matInfo = @:privateAccess instanced.primitive.getMaterialIndexes(index); + for (p in mat.getPasses()) + @:privateAccess { + var ctx = scene.renderer.getPassByName(p.name); + if (ctx == null) + throw "Could't find renderer pass " + p.name; + + var manager = cast(ctx, shaders.RendererDefaultPass).manager; + var shaders = p.getShadersRec(); + var rt = manager.compileShaders(shaders, false); + var shader = manager.shaderCache.makeBatchShader(rt, shaders, instancedParams); + + var b = new BatchData(); + b.indexCount = matInfo.count; + b.indexStart = matInfo.start; + b.paramsCount = shader.paramsSize; + b.maxInstance = Std.int(MAX_BUFFER_ELEMENTS / b.paramsCount); + if (b.maxInstance <= 0) + throw "Mesh batch shaders needs at least one perInstance parameter"; + b.params = shader.params; + b.shader = shader; + b.pass = p; + b.matIndex = index; + b.shaders = [null /*link shader*/]; + p.dynamicParameters = true; + p.batchMode = true; + + b.next = dataPasses; + dataPasses = b; + + var sl = shaders; + while (sl != null) { + b.shaders.push(sl.s); + sl = sl.next; + } + shader.Batch_Count = b.maxInstance * b.paramsCount; + shader.Batch_HasOffset = primitiveSubPart != null; + shader.constBits = (shader.Batch_Count << 1) | (shader.Batch_HasOffset ? 1 : 0); + shader.updateConstants(null); + } + } + + // add batch shaders + var p = dataPasses; + while (p != null) { + @:privateAccess p.pass.addSelfShader(p.shader); + p = p.next; + } + } + + public function begin(emitCountTip = -1, resizeDown = false) { + instanceCount = 0; + instanced.initBounds(); + if (shadersChanged) { + initShadersMapping(); + shadersChanged = false; + } + + if (emitCountTip < 0) + emitCountTip = 128; + var p = dataPasses; + var alloc = hxd.impl.Allocator.get(); + while (p != null) { + var size = emitCountTip * p.paramsCount * 4; + if (p.data == null || p.data.length < size || (resizeDown && p.data.length > size << 1)) { + if (p.data != null) + alloc.disposeFloats(p.data); + p.data = alloc.allocFloats(size); + } + p = p.next; + } + } + + function syncData(batch:BatchData) { + var startPos = batch.paramsCount * instanceCount << 2; + // in case we are bigger than emitCountTip + if (startPos + (batch.paramsCount << 2) > batch.data.length) + batch.data.grow(batch.data.length << 1); + + var p = batch.params; + var buf = batch.data; + var shaders = batch.shaders; + + var calcInv = false; + while (p != null) { + var pos = startPos + p.pos; + inline function addMatrix(m:h3d.Matrix) { + buf[pos++] = m._11; + buf[pos++] = m._21; + buf[pos++] = m._31; + buf[pos++] = m._41; + buf[pos++] = m._12; + buf[pos++] = m._22; + buf[pos++] = m._32; + buf[pos++] = m._42; + buf[pos++] = m._13; + buf[pos++] = m._23; + buf[pos++] = m._33; + buf[pos++] = m._43; + buf[pos++] = m._14; + buf[pos++] = m._24; + buf[pos++] = m._34; + buf[pos++] = m._44; + } + if (p.perObjectGlobal != null) { + if (p.perObjectGlobal.gid == modelViewID) { + addMatrix(worldPosition != null ? worldPosition : absPos); + } else if (p.perObjectGlobal.gid == modelViewInverseID) { + if (worldPosition == null) + addMatrix(getInvPos()); + else { + if (!calcInv) { + calcInv = true; + if (invWorldPosition == null) + invWorldPosition = new h3d.Matrix(); + invWorldPosition.initInverse(worldPosition); + } + addMatrix(invWorldPosition); + } + } else if (p.perObjectGlobal.gid == modelViewTransposeID) { + var m = worldPosition != null ? worldPosition : absPos; + m.transpose(); + addMatrix(m); + m.transpose(); + } else + throw "Unsupported global param " + p.perObjectGlobal.path; + p = p.next; + continue; + } + var curShader = shaders[p.instance]; + switch (p.type) { + case TVec(size, _): + var v:h3d.Vector = curShader.getParamValue(p.index); + switch (size) { + case 2: + buf[pos++] = v.x; + buf[pos++] = v.y; + case 3: + buf[pos++] = v.x; + buf[pos++] = v.y; + buf[pos++] = v.z; + default: + buf[pos++] = v.x; + buf[pos++] = v.y; + buf[pos++] = v.z; + buf[pos++] = v.w; + } + case TFloat: + buf[pos++] = curShader.getParamFloatValue(p.index); + case TMat4: + var m:h3d.Matrix = curShader.getParamValue(p.index); + addMatrix(m); + default: + throw "Unsupported batch type " + p.type; + } + p = p.next; + } + needUpload = true; + } + + override function addBoundsRec(b:h3d.col.Bounds, relativeTo:h3d.Matrix) { + var old = primitive; + primitive = null; + super.addBoundsRec(b, relativeTo); + primitive = old; + if (primitive == null || flags.has(FIgnoreBounds)) + return; + // already transformed in absolute + var bounds = primitive.getBounds(); + if (relativeTo == null) + b.add(bounds); + else + b.addTransform(bounds, relativeTo); + } + + public function emitInstance() { + if (worldPosition == null) + syncPos(); + var ps = primitiveSubPart; + if (ps != null) + @:privateAccess { + // instanced.tmpBounds.load(primitiveSubPart.bounds); + // instanced.tmpBounds.transform(worldPosition == null ? absPos : worldPosition); + // instanced.bounds.add(instanced.tmpBounds); + + if (primitiveSubBytes == null) { + primitiveSubBytes = haxe.io.Bytes.alloc(128); + instanced.commands = null; + } + if (primitiveSubBytes.length < (instanceCount + 1) * 20) { + var next = haxe.io.Bytes.alloc(Std.int(primitiveSubBytes.length * 3 / 2)); + next.blit(0, primitiveSubBytes, 0, instanceCount * 20); + primitiveSubBytes = next; + } + var p = instanceCount * 20; + primitiveSubBytes.setInt32(p, ps.indexCount); + primitiveSubBytes.setInt32(p + 4, 1); + primitiveSubBytes.setInt32(p + 8, ps.indexStart); + primitiveSubBytes.setInt32(p + 12, ps.baseVertex); + primitiveSubBytes.setInt32(p + 16, 0); + } else if (calcBounds) + instanced.addInstanceBounds(worldPosition == null ? absPos : worldPosition); + var p = dataPasses; + while (p != null) { + syncData(p); + p = p.next; + } + instanceCount++; + } + + public function disposeBuffers() { + if (instanceCount == 0) + return; + var p = dataPasses; + var alloc = hxd.impl.Allocator.get(); + while (p != null) { + for (b in p.buffers) + b.dispose(); + p = p.next; + } + } + + override function sync(ctx:RenderContext) { + super.sync(ctx); + if (instanceCount == 0) + return; + var p = dataPasses; + var alloc = hxd.impl.Allocator.get(); + var psBytes = primitiveSubBytes; + while (p != null) { + var index = 0; + var start = 0; + while (start < instanceCount) { + var upload = needUpload; + var buf = p.buffers[index]; + var count = instanceCount - start; + if (count > p.maxInstance) + count = p.maxInstance; + if (buf == null || buf.isDisposed()) { + buf = alloc.allocBuffer(MAX_BUFFER_ELEMENTS, 4, UniformDynamic); + p.buffers[index] = buf; + upload = true; + } + if (upload) + buf.uploadVector(p.data, start * p.paramsCount * 4, count * p.paramsCount); + if (psBytes != null) { + if (p.instanceBuffers == null) + p.instanceBuffers = []; + var buf = p.instanceBuffers[index]; + if (buf == null /*|| buf.isDisposed()*/) { + buf = new h3d.impl.InstanceBuffer(); + var sub = psBytes.sub(start * 20, count * 20); + for (i in 0...count) + sub.setInt32(i * 20 + 16, i); + buf.setBuffer(count, sub); + p.instanceBuffers[index] = buf; + } + } + start += count; + index++; + } + while (p.buffers.length > index) + alloc.disposeBuffer(p.buffers.pop()); + p = p.next; + } + if (psBytes != null) { + var prim = cast(primitive, h3d.prim.MeshPrimitive); + var offsets = @:privateAccess prim.getBuffer("Batch_Start"); + if (offsets == null || offsets.vertices < instanceCount || offsets.isDisposed()) { + if (offsets != null) + offsets.dispose(); + var tmp = haxe.io.Bytes.alloc(4 * instanceCount); + for (i in 0...instanceCount) + tmp.setFloat(i << 2, i); + offsets = new h3d.Buffer(instanceCount, 1); + offsets.uploadBytes(tmp, 0, instanceCount); + @:privateAccess prim.addBuffer("Batch_Start", offsets); + } + } + needUpload = false; + } + + override function draw(ctx:RenderContext) { + var p = dataPasses; + while (true) { + if (p.pass == ctx.drawPass.pass) { + var bufferIndex = ctx.drawPass.index & 0xFFFF; + p.shader.Batch_Buffer = p.buffers[bufferIndex]; + if (p.instanceBuffers == null) { + var count = instanceCount - p.maxInstance * bufferIndex; + instanced.commands.setCommand(count, p.indexCount, p.indexStart); + } else + instanced.commands = p.instanceBuffers[bufferIndex]; + break; + } + p = p.next; + } + ctx.uploadParams(); + var prev = ctx.drawPass.index; + ctx.drawPass.index >>= 16; + super.draw(ctx); + ctx.drawPass.index = prev; + } + + override function emit(ctx:RenderContext) { + if (instanceCount == 0) + return; + var p = dataPasses; + while (p != null) { + var pass = p.pass; + // check that the pass is still enable + var material = materials[p.matIndex]; + if (material != null && material.getPass(pass.name) != null) { + for (i in 0...p.buffers.length) + ctx.emitPass(pass, this).index = i | (p.matIndex << 16); + } + p = p.next; + } + } +} diff --git a/src/Renderer.hx b/src/Renderer.hx index 50267488..a03bedeb 100644 --- a/src/Renderer.hx +++ b/src/Renderer.hx @@ -1,5 +1,6 @@ package src; +import shaders.RendererDefaultPass; import hxd.Window; import src.ResourceLoader; import shaders.GammaRamp; @@ -38,7 +39,7 @@ class Renderer extends h3d.scene.Renderer { public function new() { super(); - defaultPass = new h3d.pass.Default("default"); + defaultPass = new RendererDefaultPass("default"); allPasses = [defaultPass, depth, normal, shadow]; blurShader = new ScreenFx(new Blur()); copyPass = new h3d.pass.Copy(); diff --git a/src/shaders/DefaultCubemapMaterial.hx b/src/shaders/DefaultCubemapMaterial.hx index f8caea43..a894c1eb 100644 --- a/src/shaders/DefaultCubemapMaterial.hx +++ b/src/shaders/DefaultCubemapMaterial.hx @@ -14,6 +14,7 @@ class DefaultCubemapMaterial extends hxsl.Shader { }; @global var global:{ @perObject var modelView:Mat4; + @perObject var modelViewTranspose:Mat4; @perObject var modelViewInverse:Mat4; }; @input var input:{ @@ -58,7 +59,7 @@ class DefaultCubemapMaterial extends hxsl.Shader { outNormal = input.normal; // outNormal.x *= -1; - var inLightVec = vec3(-0.5732, 0.27536, -0.77176) * transposeMat3(mat3(global.modelView)); + var inLightVec = vec3(-0.5732, 0.27536, -0.77176) * mat3(global.modelViewTranspose); // inLightVec.x *= -1; outLightVec.xyz = -inLightVec * objToTangentSpace; // var cubeVertPos = input.position * cubeTrans; diff --git a/src/shaders/DefaultCubemapNormalMaterial.hx b/src/shaders/DefaultCubemapNormalMaterial.hx index b42cf0e7..743c14bf 100644 --- a/src/shaders/DefaultCubemapNormalMaterial.hx +++ b/src/shaders/DefaultCubemapNormalMaterial.hx @@ -14,6 +14,7 @@ class DefaultCubemapNormalMaterial extends hxsl.Shader { @global var global:{ @perObject var modelView:Mat4; @perObject var modelViewInverse:Mat4; + @perObject var modelViewTranspose:Mat4; }; @input var input:{ var position:Vec3; @@ -44,7 +45,7 @@ class DefaultCubemapNormalMaterial extends hxsl.Shader { function vertex() { calculatedUV = input.uv; outLightVec = vec4(0); - var inLightVec = vec3(-0.5732, 0.27536, -0.77176) * transposeMat3(mat3(global.modelView)); + var inLightVec = vec3(-0.5732, 0.27536, -0.77176) * mat3(global.modelViewTranspose); // inLightVec.x *= -1; var eyePos = camera.position * mat3x4(global.modelViewInverse); // eyePos.x *= -1; diff --git a/src/shaders/DefaultCubemapNormalNoSpecMaterial.hx b/src/shaders/DefaultCubemapNormalNoSpecMaterial.hx index bf6f13ff..837cf0c4 100644 --- a/src/shaders/DefaultCubemapNormalNoSpecMaterial.hx +++ b/src/shaders/DefaultCubemapNormalNoSpecMaterial.hx @@ -12,6 +12,7 @@ class DefaultCubemapNormalNoSpecMaterial extends hxsl.Shader { @global var global:{ @perObject var modelView:Mat4; @perObject var modelViewInverse:Mat4; + @perObject var modelViewTranspose:Mat4; }; @input var input:{ var position:Vec3; @@ -38,7 +39,7 @@ class DefaultCubemapNormalNoSpecMaterial extends hxsl.Shader { } function vertex() { calculatedUV = input.uv; - var inLightVec = vec3(-0.5732, 0.27536, -0.77176) * transposeMat3(mat3(global.modelView)); + var inLightVec = vec3(-0.5732, 0.27536, -0.77176) * mat3(global.modelViewTranspose); // inLightVec.x *= -1; var pN = input.normal; // pN.x *= -1; diff --git a/src/shaders/DefaultDiffuseMaterial.hx b/src/shaders/DefaultDiffuseMaterial.hx index e220deba..7d17fe82 100644 --- a/src/shaders/DefaultDiffuseMaterial.hx +++ b/src/shaders/DefaultDiffuseMaterial.hx @@ -10,6 +10,7 @@ class DefaultDiffuseMaterial extends hxsl.Shader { @global var global:{ @perObject var modelView:Mat4; @perObject var modelViewInverse:Mat4; + @perObject var modelViewTranspose:Mat4; }; @input var input:{ var position:Vec3; @@ -28,7 +29,7 @@ class DefaultDiffuseMaterial extends hxsl.Shader { function vertex() { calculatedUV = input.uv; var objToTangentSpace = mat3(input.t, input.b, input.n); - var inLightVec = vec3(-0.5732, 0.27536, -0.77176) * transposeMat3(mat3(global.modelView)); + var inLightVec = vec3(-0.5732, 0.27536, -0.77176) * mat3(global.modelViewTranspose); // inLightVec.x *= -1; var n = input.normal; // n.x *= -1; diff --git a/src/shaders/DefaultMaterial.hx b/src/shaders/DefaultMaterial.hx index 5abd9e61..f63dd4d7 100644 --- a/src/shaders/DefaultMaterial.hx +++ b/src/shaders/DefaultMaterial.hx @@ -14,6 +14,7 @@ class DefaultMaterial extends hxsl.Shader { @global var global:{ @perObject var modelView:Mat4; @perObject var modelViewInverse:Mat4; + @perObject var modelViewTranspose:Mat4; }; @input var input:{ var position:Vec3; @@ -46,7 +47,7 @@ class DefaultMaterial extends hxsl.Shader { } var objToTangentSpace = mat3(input.t, input.b, input.n); outLightVec = vec4(0); - var inLightVec = vec3(-0.5732, 0.27536, -0.77176) * transposeMat3(mat3(global.modelView)); + var inLightVec = vec3(-0.5732, 0.27536, -0.77176) * mat3(global.modelViewTranspose); // inLightVec.x *= -1; var eyePos = camera.position * mat3x4(global.modelViewInverse); // eyePos.x *= -1; diff --git a/src/shaders/DefaultNormalMaterial.hx b/src/shaders/DefaultNormalMaterial.hx index 4b7a9d73..a2cf7708 100644 --- a/src/shaders/DefaultNormalMaterial.hx +++ b/src/shaders/DefaultNormalMaterial.hx @@ -13,6 +13,7 @@ class DefaultNormalMaterial extends hxsl.Shader { @global var global:{ @perObject var modelView:Mat4; @perObject var modelViewInverse:Mat4; + @perObject var modelViewTranspose:Mat4; }; @input var input:{ var position:Vec3; @@ -42,7 +43,7 @@ class DefaultNormalMaterial extends hxsl.Shader { function vertex() { calculatedUV = input.uv; outLightVec = vec4(0); - var inLightVec = vec3(-0.5732, 0.27536, -0.77176) * transposeMat3(mat3(global.modelView)); + var inLightVec = vec3(-0.5732, 0.27536, -0.77176) * mat3(global.modelViewTranspose); // inLightVec.x *= -1; var eyePos = camera.position * mat3x4(global.modelViewInverse); // eyePos.x *= -1; diff --git a/src/shaders/NoiseTileMaterial.hx b/src/shaders/NoiseTileMaterial.hx index 07bd8f91..9432f567 100644 --- a/src/shaders/NoiseTileMaterial.hx +++ b/src/shaders/NoiseTileMaterial.hx @@ -15,6 +15,7 @@ class NoiseTileMaterial extends hxsl.Shader { @global var global:{ @perObject var modelView:Mat4; @perObject var modelViewInverse:Mat4; + @perObject var modelViewTranspose:Mat4; }; @input var input:{ var position:Vec3; @@ -42,7 +43,7 @@ class NoiseTileMaterial extends hxsl.Shader { calculatedUV = input.uv; var objToTangentSpace = mat3(input.t, input.b, input.n); outLightVec = vec4(0); - var inLightVec = vec3(-0.5732, 0.27536, -0.77176) * transposeMat3(mat3(global.modelView)); + var inLightVec = vec3(-0.5732, 0.27536, -0.77176) * mat3(global.modelViewTranspose); // inLightVec.x *= -1; var eyePos = camera.position * mat3x4(global.modelViewInverse); // eyePos.x *= -1; diff --git a/src/shaders/RefractMaterial.hx b/src/shaders/RefractMaterial.hx index 0a3a0d62..5ca2da49 100644 --- a/src/shaders/RefractMaterial.hx +++ b/src/shaders/RefractMaterial.hx @@ -15,6 +15,7 @@ class RefractMaterial extends hxsl.Shader { @global var global:{ @perObject var modelView:Mat4; @perObject var modelViewInverse:Mat4; + @perObject var modelViewTranspose:Mat4; }; @input var input:{ var position:Vec3; @@ -44,7 +45,7 @@ class RefractMaterial extends hxsl.Shader { calculatedUV = input.uv; var objToTangentSpace = mat3(input.t, input.b, input.n); outLightVec = vec4(0); - var inLightVec = vec3(-0.5732, 0.27536, -0.77176) * transposeMat3(mat3(global.modelView)); + var inLightVec = vec3(-0.5732, 0.27536, -0.77176) * mat3(global.modelViewTranspose); // inLightVec.x *= -1; var eyePos = camera.position * mat3x4(global.modelViewInverse); // eyePos.x *= -1; diff --git a/src/shaders/RendererDefaultPass.hx b/src/shaders/RendererDefaultPass.hx new file mode 100644 index 00000000..caa05bbd --- /dev/null +++ b/src/shaders/RendererDefaultPass.hx @@ -0,0 +1,155 @@ +package shaders; + +import h3d.pass.PassObject; +import h3d.pass.ShaderManager; +import h3d.pass.Base; +import h3d.pass.SortByMaterial; + +@:build(hxsl.Macros.buildGlobals()) +@:access(h3d.mat.Pass) +class RendererDefaultPass extends Base { + var manager:ShaderManager; + var globals(get, never):hxsl.Globals; + var defaultSort = new SortByMaterial().sort; + + inline function get_globals() + return manager.globals; + + @global("camera.view") var cameraView:h3d.Matrix = ctx.camera.mcam; + @global("camera.zNear") var cameraNear:Float = ctx.camera.zNear; + @global("camera.zFar") var cameraFar:Float = ctx.camera.zFar; + @global("camera.proj") var cameraProj:h3d.Matrix = ctx.camera.mproj; + @global("camera.position") var cameraPos:h3d.Vector = ctx.camera.pos; + @global("camera.projDiag") var cameraProjDiag:h3d.Vector = new h3d.Vector(ctx.camera.mproj._11, ctx.camera.mproj._22, ctx.camera.mproj._33, + ctx.camera.mproj._44); + @global("camera.projFlip") var cameraProjFlip:Float = ctx.engine.driver.hasFeature(BottomLeftCoords) + && ctx.engine.getCurrentTarget() != null ? -1 : 1; + @global("camera.viewProj") var cameraViewProj:h3d.Matrix = ctx.camera.m; + @global("camera.inverseViewProj") var cameraInverseViewProj:h3d.Matrix = ctx.camera.getInverseViewProj(); + @global("global.time") var globalTime:Float = ctx.time; + @global("global.pixelSize") var pixelSize:h3d.Vector = getCurrentPixelSize(); + @global("global.modelView") var globalModelView:h3d.Matrix; + @global("global.modelViewInverse") var globalModelViewInverse:h3d.Matrix; + @global("global.modelViewTranspose") var globalModelViewTranspose:h3d.Matrix; + + public function new(name) { + super(name); + manager = new ShaderManager(getOutputs()); + initGlobals(); + } + + function getCurrentPixelSize() { + var t = ctx.engine.getCurrentTarget(); + return new h3d.Vector(2 / (t == null ? ctx.engine.width : t.width), 2 / (t == null ? ctx.engine.height : t.height)); + } + + function getOutputs():Array { + return [Value("output.color")]; + } + + override function compileShader(p:h3d.mat.Pass) { + var o = @:privateAccess new h3d.pass.PassObject(); + o.pass = p; + setupShaders(new h3d.pass.PassList(o)); + return manager.compileShaders(o.shaders, p.batchMode); + } + + function processShaders(p:h3d.pass.PassObject, shaders:hxsl.ShaderList) { + var p = ctx.extraShaders; + while (p != null) { + shaders = ctx.allocShaderList(p.s, shaders); + p = p.next; + } + return shaders; + } + + @:access(h3d.scene) + function setupShaders(passes:h3d.pass.PassList) { + var lightInit = false; + for (p in passes) { + var shaders = p.pass.getShadersRec(); + shaders = processShaders(p, shaders); + if (p.pass.enableLights && ctx.lightSystem != null) { + if (!lightInit) { + ctx.lightSystem.initGlobals(globals); + lightInit = true; + } + shaders = ctx.lightSystem.computeLight(p.obj, shaders); + } + p.shader = manager.compileShaders(shaders, p.pass.batchMode); + p.shaders = shaders; + var t = p.shader.fragment.textures; + if (t == null || t.type.match(TArray(_))) + p.texture = 0; + else { + var t:h3d.mat.Texture = manager.getParamValue(t, shaders, true); + p.texture = t == null ? 0 : t.id; + } + } + } + + inline function log(str:String) { + ctx.engine.driver.log(str); + } + + function drawObject(p:h3d.pass.PassObject) { + ctx.drawPass = p; + ctx.engine.selectMaterial(p.pass); + @:privateAccess p.obj.draw(ctx); + } + + static public dynamic function onShaderError(e:Dynamic, p:PassObject) { + throw e; + } + + @:access(h3d.scene) + override function draw(passes:h3d.pass.PassList, ?sort:h3d.pass.PassList->Void) { + if (passes.isEmpty()) + return; + #if sceneprof h3d.impl.SceneProf.begin("draw", ctx.frame); #end + for (g in ctx.sharedGlobals) + globals.fastSet(g.gid, g.value); + setGlobals(); + setupShaders(passes); + if (sort == null) + defaultSort(passes); + else + sort(passes); + ctx.currentManager = manager; + var buf = ctx.shaderBuffers, prevShader = null; + for (p in passes) { + #if sceneprof h3d.impl.SceneProf.mark(p.obj); #end + globalModelView = p.obj.absPos; + if (p.shader.hasGlobal(globalModelViewTranspose_id.toInt())) { + globalModelViewTranspose = globalModelView.clone(); + globalModelViewTranspose.transpose(); + } + if (p.shader.hasGlobal(globalModelViewInverse_id.toInt())) + globalModelViewInverse = p.obj.getInvPos(); + if (prevShader != p.shader) { + prevShader = p.shader; + try { + ctx.engine.selectShader(p.shader); + } catch (e:Dynamic) { + onShaderError(e, p); + continue; + } + if (buf == null) + buf = ctx.shaderBuffers = new h3d.shader.Buffers(p.shader); + else + buf.grow(p.shader); + manager.fillGlobals(buf, p.shader); + ctx.engine.uploadShaderBuffers(buf, Globals); + } + if (!p.pass.dynamicParameters) { + manager.fillParams(buf, p.shader, p.shaders); + ctx.engine.uploadShaderBuffers(buf, Params); + ctx.engine.uploadShaderBuffers(buf, Textures); + ctx.engine.uploadShaderBuffers(buf, Buffers); + } + drawObject(p); + } + #if sceneprof h3d.impl.SceneProf.end(); #end + ctx.nextPass(); + } +} diff --git a/src/shaders/marble/ClassicGlass.hx b/src/shaders/marble/ClassicGlass.hx index 8fb12807..74599bbf 100644 --- a/src/shaders/marble/ClassicGlass.hx +++ b/src/shaders/marble/ClassicGlass.hx @@ -14,6 +14,7 @@ class ClassicGlass extends hxsl.Shader { }; @global var global:{ @perObject var modelView:Mat4; + @perObject var modelViewTranspose:Mat4; @perObject var modelViewInverse:Mat4; }; @input var input:{ diff --git a/src/shaders/marble/ClassicGlassPureSphere.hx b/src/shaders/marble/ClassicGlassPureSphere.hx index e3f7e838..108bc70d 100644 --- a/src/shaders/marble/ClassicGlassPureSphere.hx +++ b/src/shaders/marble/ClassicGlassPureSphere.hx @@ -14,6 +14,7 @@ class ClassicGlassPureSphere extends hxsl.Shader { }; @global var global:{ @perObject var modelView:Mat4; + @perObject var modelViewTranspose:Mat4; @perObject var modelViewInverse:Mat4; }; @input var input:{ diff --git a/src/shaders/marble/ClassicMarb.hx b/src/shaders/marble/ClassicMarb.hx index e588cbd7..1ad9bf8b 100644 --- a/src/shaders/marble/ClassicMarb.hx +++ b/src/shaders/marble/ClassicMarb.hx @@ -13,6 +13,7 @@ class ClassicMarb extends hxsl.Shader { }; @global var global:{ @perObject var modelView:Mat4; + @perObject var modelViewTranspose:Mat4; @perObject var modelViewInverse:Mat4; }; @input var input:{ diff --git a/src/shaders/marble/ClassicMarb2.hx b/src/shaders/marble/ClassicMarb2.hx index 0dc5d1a1..6fe78749 100644 --- a/src/shaders/marble/ClassicMarb2.hx +++ b/src/shaders/marble/ClassicMarb2.hx @@ -13,6 +13,7 @@ class ClassicMarb2 extends hxsl.Shader { }; @global var global:{ @perObject var modelView:Mat4; + @perObject var modelViewTranspose:Mat4; @perObject var modelViewInverse:Mat4; }; @input var input:{ diff --git a/src/shaders/marble/ClassicMarb3.hx b/src/shaders/marble/ClassicMarb3.hx index 6c67e664..f7370df7 100644 --- a/src/shaders/marble/ClassicMarb3.hx +++ b/src/shaders/marble/ClassicMarb3.hx @@ -13,6 +13,7 @@ class ClassicMarb3 extends hxsl.Shader { }; @global var global:{ @perObject var modelView:Mat4; + @perObject var modelViewTranspose:Mat4; @perObject var modelViewInverse:Mat4; }; @input var input:{ diff --git a/src/shaders/marble/ClassicMetal.hx b/src/shaders/marble/ClassicMetal.hx index 16df6741..e04c57ae 100644 --- a/src/shaders/marble/ClassicMetal.hx +++ b/src/shaders/marble/ClassicMetal.hx @@ -14,6 +14,7 @@ class ClassicMetal extends hxsl.Shader { }; @global var global:{ @perObject var modelView:Mat4; + @perObject var modelViewTranspose:Mat4; @perObject var modelViewInverse:Mat4; }; @input var input:{ diff --git a/src/shaders/marble/CrystalMarb.hx b/src/shaders/marble/CrystalMarb.hx index 8cf7b36f..dc60a73f 100644 --- a/src/shaders/marble/CrystalMarb.hx +++ b/src/shaders/marble/CrystalMarb.hx @@ -12,6 +12,7 @@ class CrystalMarb extends hxsl.Shader { }; @global var global:{ @perObject var modelView:Mat4; + @perObject var modelViewTranspose:Mat4; @perObject var modelViewInverse:Mat4; }; @input var input:{