diff --git a/src/InstanceManager.hx b/src/InstanceManager.hx index a0358825..80250ea0 100644 --- a/src/InstanceManager.hx +++ b/src/InstanceManager.hx @@ -81,6 +81,14 @@ class InstanceManager { minfo.meshbatch.material.mainPass.enableLights = minfo.mesh.material.mainPass.enableLights; minfo.meshbatch.worldPosition = transform; minfo.meshbatch.material.mainPass.culling = minfo.mesh.material.mainPass.culling; + + minfo.meshbatch.material.mainPass.blendSrc = minfo.mesh.material.mainPass.blendSrc; + minfo.meshbatch.material.mainPass.blendDst = minfo.mesh.material.mainPass.blendDst; + minfo.meshbatch.material.mainPass.blendOp = minfo.mesh.material.mainPass.blendOp; + minfo.meshbatch.material.mainPass.blendAlphaSrc = minfo.mesh.material.mainPass.blendAlphaSrc; + minfo.meshbatch.material.mainPass.blendAlphaDst = minfo.mesh.material.mainPass.blendAlphaDst; + minfo.meshbatch.material.mainPass.blendAlphaOp = minfo.mesh.material.mainPass.blendAlphaOp; + minfo.meshbatch.emitInstance(); } } @@ -178,6 +186,34 @@ class InstanceManager { minfo.meshbatch.material.addPass(gpass); } + var refractPass = mat.getPass("refract"); + if (refractPass != null) { + var gpass = refractPass.clone(); + gpass.enableLights = false; + gpass.depthTest = refractPass.depthTest; + gpass.blendSrc = refractPass.blendSrc; + gpass.blendDst = refractPass.blendDst; + gpass.blendOp = refractPass.blendOp; + gpass.blendAlphaSrc = refractPass.blendAlphaSrc; + gpass.blendAlphaDst = refractPass.blendAlphaDst; + gpass.blendAlphaOp = refractPass.blendAlphaOp; + if (refractPass.culling == None) { + gpass.culling = refractPass.culling; + } + + minfoshaders = []; + + for (shader in gpass.getShaders()) { + minfoshaders.push(shader); + } + for (shader in minfoshaders) + gpass.removeShader(shader); + for (shader in refractPass.getShaders()) { + gpass.addShader(shader); + } + + minfo.meshbatch.material.addPass(gpass); + } // var dtsshader = mat.mainPass.getShader(DtsTexture); // if (dtsshader != null) { // minfo.meshbatch.material.mainPass.removeShader(minfo.meshbatch.material.textureShader); diff --git a/src/Renderer.hx b/src/Renderer.hx index 863bca31..96e25e3d 100644 --- a/src/Renderer.hx +++ b/src/Renderer.hx @@ -1,5 +1,6 @@ package src; +import h3d.mat.Texture; import h3d.Vector; import shaders.Blur; import h3d.pass.ScreenFx; @@ -13,7 +14,9 @@ class Renderer extends h3d.scene.Renderer { public var shadow = new h3d.pass.DefaultShadowMap(1024); var glowBuffer:h3d.mat.Texture; - var backBuffers:Array; + + static var sfxBuffer:h3d.mat.Texture; + var curentBackBuffer = 0; var blurShader:ScreenFx; var growBufferTemps:Array; @@ -26,22 +29,23 @@ class Renderer extends h3d.scene.Renderer { allPasses = [defaultPass, depth, normal, shadow]; blurShader = new ScreenFx(new Blur()); copyPass = new h3d.pass.Copy(); + sfxBuffer = new Texture(512, 512, [Target]); + } + + public inline static function getSfxBuffer() { + return sfxBuffer; } inline function get_def() return defaultPass; - public inline function getBackBuffer():h3d.mat.Texture { - return backBuffers[1]; - } - // can be overriden for benchmark purposes function renderPass(p:h3d.pass.Base, passes, ?sort) { p.draw(passes, sort); } override function getPassByName(name:String):h3d.pass.Base { - if (name == "alpha" || name == "additive" || name == "glowPre" || name == "glow") + if (name == "alpha" || name == "additive" || name == "glowPre" || name == "glow" || name == "refract") return defaultPass; return super.getPassByName(name); } @@ -62,17 +66,6 @@ class Renderer extends h3d.scene.Renderer { if (has("normal")) renderPass(normal, get("normal")); - if (backBuffers == null) { - var commonDepth = new DepthBuffer(ctx.engine.width, ctx.engine.height); - backBuffers = [ - ctx.textures.allocTarget("backbuffer1", 320, 320, false), - ctx.textures.allocTarget("backbuffer2", 320, 320, false), - ]; - backBuffers[0].depthBuffer = commonDepth; - // backBuffers[1].depthBuffer = commonDepth; - // new h3d.mat.Texture(ctx.engine.width, ctx.engine.height, [Target]); - // refractTexture.depthBuffer = new DepthBuffer(ctx.engine.width, ctx.engine.height); - } if (growBufferTemps == null) { glowBuffer = ctx.textures.allocTarget("glowBuffer", ctx.engine.width, ctx.engine.height); growBufferTemps = [ @@ -88,6 +81,7 @@ class Renderer extends h3d.scene.Renderer { renderPass(defaultPass, get("default")); renderPass(defaultPass, get("glowPre")); + // Glow pass ctx.engine.pushTarget(glowBuffer); ctx.engine.clear(0); renderPass(defaultPass, get("glow")); @@ -97,6 +91,9 @@ class Renderer extends h3d.scene.Renderer { copyPass.pass.blend(One, One); copyPass.pass.depth(false, Always); copyPass.render(); + // Refraction pass + h3d.pass.Copy.run(backBuffer, sfxBuffer); + renderPass(defaultPass, get("refract")); renderPass(defaultPass, get("alpha"), backToFront); renderPass(defaultPass, get("additive")); diff --git a/src/shaders/RefractMaterial.hx b/src/shaders/RefractMaterial.hx new file mode 100644 index 00000000..7d890ea2 --- /dev/null +++ b/src/shaders/RefractMaterial.hx @@ -0,0 +1,97 @@ +package shaders; + +class RefractMaterial extends hxsl.Shader { + static var SRC = { + @param var diffuseMap:Sampler2D; + @param var refractMap:Sampler2D; + @param var specularColor:Vec4; + @param var normalMap:Sampler2D; + @param var shininess:Float; + @param var secondaryMapUvFactor:Float; + @global var camera:{ + var position:Vec3; + @var var dir:Vec3; + }; + @global var global:{ + @perObject var modelView:Mat4; + @perObject var modelViewInverse:Mat4; + }; + @input var input:{ + var position:Vec3; + var normal:Vec3; + var uv:Vec2; + var t:Vec3; + var b:Vec3; + var n:Vec3; + }; + var calculatedUV:Vec2; + var pixelColor:Vec4; + var specColor:Vec3; + var specPower:Float; + var projectedPosition:Vec4; + @var var outLightVec:Vec4; + @var var outPos:Vec3; + @var var outEyePos:Vec3; + @const var doGammaRamp:Bool; + function lambert(normal:Vec3, lightPosition:Vec3):Float { + var result = dot(normal, lightPosition); + return saturate(result); + } + function vertex() { + calculatedUV = input.uv; + var objToTangentSpace = mat3(input.t, input.b, input.n); + outLightVec = vec4(0); + var inLightVec = vec3(-0.5732, 0.27536, -0.77176) * mat3(global.modelViewInverse); + var eyePos = camera.position * mat3x4(global.modelViewInverse); + // eyePos /= vec3(global.modelViewInverse[0].x, global.modelViewInverse[1].y, global.modelViewInverse[2].z); + outLightVec.xyz = -inLightVec * objToTangentSpace; + outPos = (input.position / 100.0) * objToTangentSpace; + outEyePos = (eyePos / 100.0) * objToTangentSpace; + outLightVec.w = step(-0.5, dot(input.normal, -inLightVec)); + } + function fragment() { + var bumpNormal = unpackNormal(normalMap.get(calculatedUV * secondaryMapUvFactor)); + + // Refract + var distortion = 0.3; + var off = projectedPosition; + off.xy += bumpNormal.xy * distortion; + + var refractColor = refractMap.get(screenToUv(off.xy / off.w)); + // Diffuse part + var diffuse = diffuseMap.get(calculatedUV); + var ambient = vec4(0.472, 0.424, 0.475, 1.00); + + var outCol = refractColor * diffuse; + + var eyeVec = (outEyePos - outPos).normalize(); + var halfAng = (eyeVec + outLightVec.xyz).normalize(); + var specValue = saturate(bumpNormal.dot(halfAng)) * outLightVec.w; + var specular = specularColor * pow(specValue, shininess); + + outCol += specular * diffuse.a; + outCol = refractColor; + + // Gamma correction using our regression model + if (doGammaRamp) { + var a = 1.00759; + var b = 1.18764; + outCol.x = a * pow(outCol.x, b); + outCol.y = a * pow(outCol.y, b); + outCol.z = a * pow(outCol.z, b); + } + + pixelColor = outCol; + } + } + + public function new(diffuse, normal, shininess, specularColor, secondaryMapUvFactor) { + super(); + this.diffuseMap = diffuse; + this.normalMap = normal; + this.shininess = shininess; + this.specularColor = specularColor; + this.secondaryMapUvFactor = secondaryMapUvFactor; + this.doGammaRamp = true; + } +} diff --git a/src/shaders/UVRotAnim.hx b/src/shaders/UVRotAnim.hx new file mode 100644 index 00000000..f7ef0d00 --- /dev/null +++ b/src/shaders/UVRotAnim.hx @@ -0,0 +1,27 @@ +package shaders; + +class UVRotAnim extends hxsl.Shader { + static var SRC = { + @global var global:{ + var time:Float; + }; + @param var offset:Vec2; + @param var uvRotSpeed:Float; + var calculatedUV:Vec2; + function vertex() { + var s = sin(global.time * uvRotSpeed); + var c = cos(global.time * uvRotSpeed); + var v = calculatedUV - offset; + var vx = v.x * c - v.y * s; + var vy = v.x * s + v.y * c; + + calculatedUV += vec2(offset.x + vx, offset.y + vy); + } + }; + + public function new(vx = 0., vy = 0., speed = 1.) { + super(); + offset.set(vx, vy); + uvRotSpeed = speed; + } +} diff --git a/src/shapes/EndPad.hx b/src/shapes/EndPad.hx index 187fa909..978243c1 100644 --- a/src/shapes/EndPad.hx +++ b/src/shapes/EndPad.hx @@ -36,7 +36,7 @@ class EndPad extends DtsObject { this.dtsPath = "data/shapes/pads/endarea.dts"; this.isCollideable = true; this.identifier = "EndPad"; - this.useInstancing = true; + this.useInstancing = false; } public override function init(level:MarbleWorld, onFinish:Void->Void) { @@ -132,6 +132,9 @@ class EndPad extends DtsObject { material.mainPass.setPassName("glowPre"); material.mainPass.enableLights = false; + var rotshader = new shaders.UVRotAnim(-0.5, -0.5, 1); + material.mainPass.addShader(rotshader); + var thisprops:Dynamic = material.getDefaultProps(); thisprops.light = false; // We will calculate our own lighting material.props = thisprops; @@ -144,8 +147,11 @@ class EndPad extends DtsObject { diffuseTex.mipMap = Nearest; var shader = new shaders.DefaultNormalMaterial(diffuseTex, 14, new h3d.Vector(0.3, 0.3, 0.3, 7), 1); shader.doGammaRamp = false; - var dtsTex = material.mainPass.getShader(shaders.DtsTexture); - dtsTex.passThrough = true; + var dtsshader = material.mainPass.getShader(shaders.DtsTexture); + if (dtsshader != null) + material.mainPass.removeShader(dtsshader); + // var dtsTex = material.mainPass.getShader(shaders.DtsTexture); + // dtsTex.passThrough = true; material.mainPass.removeShader(material.textureShader); material.mainPass.addShader(shader); var thisprops:Dynamic = material.getDefaultProps(); @@ -161,9 +167,11 @@ class EndPad extends DtsObject { diffuseTex.mipMap = Nearest; var trivialShader = new shaders.TrivialMaterial(diffuseTex); + var scrollShader = new h3d.shader.UVScroll(0, 0.25); var glowpass = material.mainPass.clone(); glowpass.addShader(trivialShader); + glowpass.addShader(scrollShader); var dtsshader = glowpass.getShader(shaders.DtsTexture); if (dtsshader != null) glowpass.removeShader(dtsshader); diff --git a/src/shapes/Glass.hx b/src/shapes/Glass.hx index 16274e20..c214b1f2 100644 --- a/src/shapes/Glass.hx +++ b/src/shapes/Glass.hx @@ -9,6 +9,8 @@ import src.DtsObject; import src.ResourceLoader; class Glass extends DtsObject { + var shader:shaders.RefractMaterial; + public function new(element:MissionElementStaticShape) { super(); @@ -29,8 +31,61 @@ class Glass extends DtsObject { } this.isCollideable = true; - this.useInstancing = false; + this.useInstancing = true; this.identifier = datablockLowercase; } + + override function postProcessMaterial(matName:String, material:Material) { + var refractTex = ResourceLoader.getTexture('data/shapes/structures/glass.png').resource; + refractTex.wrap = Repeat; + refractTex.mipMap = Nearest; + var diffuseTex = ResourceLoader.getTexture('data/shapes/structures/glass2.png').resource; + diffuseTex.wrap = Repeat; + diffuseTex.mipMap = Nearest; + var normalTex = ResourceLoader.getTexture("data/shapes/structures/glass.normal.png").resource; + normalTex.wrap = Repeat; + normalTex.mipMap = Nearest; + + var trivialShader = new shaders.TrivialMaterial(diffuseTex); + + shader = new shaders.RefractMaterial(refractTex, normalTex, 12, new h3d.Vector(1, 1, 1, 1), 1); + shader.refractMap = src.Renderer.getSfxBuffer(); + + // var phonshader = new shaders.PhongMaterial(diffuseTex, normalTex2, 12, new h3d.Vector(1, 1, 1, 1), src.MarbleGame.instance.world.ambient, + // src.MarbleGame.instance.world.dirLight, src.MarbleGame.instance.world.dirLightDir, 1); + + var refractPass = material.mainPass.clone(); + + material.texture = diffuseTex; + var dtsshader = material.mainPass.getShader(shaders.DtsTexture); + if (dtsshader != null) + material.mainPass.removeShader(dtsshader); + material.mainPass.removeShader(material.textureShader); + material.mainPass.addShader(trivialShader); + material.mainPass.setBlendMode(Alpha); + material.mainPass.enableLights = false; + material.mainPass.depthWrite = false; + material.shadows = false; + material.mainPass.setPassName("glowPre"); + + refractPass.setPassName("refract"); + refractPass.addShader(shader); + dtsshader = refractPass.getShader(shaders.DtsTexture); + if (dtsshader != null) + material.mainPass.removeShader(dtsshader); + refractPass.removeShader(material.textureShader); + refractPass.enableLights = false; + + // refractPass.blendSrc = One; + // refractPass.blendDst = One; + // refractPass.blendAlphaSrc = One; + // refractPass.blendAlphaDst = One; + // refractPass.blendOp = Add; + // refractPass.blendAlphaOp = Add; + refractPass.blend(One, Zero); // disable blend + refractPass.depthWrite = true; + refractPass.depthTest = LessEqual; + material.addPass(refractPass); + } } diff --git a/src/shapes/StartPad.hx b/src/shapes/StartPad.hx index 9e706cfa..a3e699b7 100644 --- a/src/shapes/StartPad.hx +++ b/src/shapes/StartPad.hx @@ -1,5 +1,7 @@ package shapes; +import h3d.shader.UVScroll; +import h3d.shader.UVAnim; import src.DtsObject; import src.ResourceLoader; @@ -9,7 +11,7 @@ class StartPad extends DtsObject { dtsPath = "data/shapes/pads/startarea.dts"; isCollideable = true; identifier = "StartPad"; - useInstancing = true; + useInstancing = false; } override function postProcessMaterial(matName:String, material:h3d.mat.Material) { @@ -37,8 +39,11 @@ class StartPad extends DtsObject { var shader = new shaders.DefaultCubemapMaterial(diffuseTex, normalTex, 12, new h3d.Vector(0.8, 0.8, 0.8, 1), 1, cubemapTex); shader.doGammaRamp = false; - var dtsTex = material.mainPass.getShader(shaders.DtsTexture); - dtsTex.passThrough = true; + var dtsshader = material.mainPass.getShader(shaders.DtsTexture); + if (dtsshader != null) + material.mainPass.removeShader(dtsshader); + // var dtsTex = material.mainPass.getShader(shaders.DtsTexture); + // dtsTex.passThrough = true; material.mainPass.removeShader(material.textureShader); material.mainPass.addShader(shader); var thisprops:Dynamic = material.getDefaultProps(); @@ -57,8 +62,11 @@ class StartPad extends DtsObject { diffuseTex.mipMap = Nearest; var shader = new shaders.DefaultNormalMaterial(diffuseTex, 14, new h3d.Vector(0.3, 0.3, 0.3, 7), 1); shader.doGammaRamp = false; - var dtsTex = material.mainPass.getShader(shaders.DtsTexture); - dtsTex.passThrough = true; + var dtsshader = material.mainPass.getShader(shaders.DtsTexture); + if (dtsshader != null) + material.mainPass.removeShader(dtsshader); + // var dtsTex = material.mainPass.getShader(shaders.DtsTexture); + // dtsTex.passThrough = true; material.mainPass.removeShader(material.textureShader); material.mainPass.addShader(shader); var thisprops:Dynamic = material.getDefaultProps(); @@ -74,6 +82,8 @@ class StartPad extends DtsObject { material.props = thisprops; material.shadows = false; material.receiveShadows = true; + var rotshader = new shaders.UVRotAnim(-0.5, -0.5, 1); + material.mainPass.addShader(rotshader); } if (matName == "abyss2") { @@ -86,6 +96,9 @@ class StartPad extends DtsObject { material.mainPass.setPassName("glowPre"); material.mainPass.enableLights = false; + var rotshader = new shaders.UVRotAnim(-0.5, -0.5, 1); + material.mainPass.addShader(rotshader); + var thisprops:Dynamic = material.getDefaultProps(); thisprops.light = false; // We will calculate our own lighting material.props = thisprops; @@ -98,9 +111,11 @@ class StartPad extends DtsObject { diffuseTex.mipMap = Nearest; var trivialShader = new shaders.TrivialMaterial(diffuseTex); + var scrollShader = new h3d.shader.UVScroll(0, 0.5); var glowpass = material.mainPass.clone(); glowpass.addShader(trivialShader); + glowpass.addShader(scrollShader); var dtsshader = glowpass.getShader(shaders.DtsTexture); if (dtsshader != null) glowpass.removeShader(dtsshader); diff --git a/src/shapes/TimeTravel.hx b/src/shapes/TimeTravel.hx index 7609e7e6..be9b38d0 100644 --- a/src/shapes/TimeTravel.hx +++ b/src/shapes/TimeTravel.hx @@ -8,6 +8,7 @@ import src.MarbleWorld; class TimeTravel extends PowerUp { var timeBonus:Float = 5; + var shader:shaders.RefractMaterial; public function new(element:MissionElementItem) { super(element); @@ -65,7 +66,29 @@ class TimeTravel extends PowerUp { material.receiveShadows = true; } if (matName == "timeTravel_glass") { - // TODO + var thisprops:Dynamic = material.getDefaultProps(); + thisprops.light = false; // We will calculate our own lighting + material.props = thisprops; + material.shadows = false; + material.receiveShadows = true; + material.mainPass.depthWrite = false; + material.blendMode = Alpha; + + var refractTex = ResourceLoader.getTexture('data/shapes/structures/glass.png').resource; + refractTex.wrap = Repeat; + refractTex.mipMap = Nearest; + var normalTex = ResourceLoader.getTexture("data/shapes/structures/time.normal.jpg").resource; + normalTex.wrap = Repeat; + normalTex.mipMap = Nearest; + shader = new shaders.RefractMaterial(refractTex, normalTex, 10, new h3d.Vector(1, 1, 1, 1), 1); + shader.refractMap = src.Renderer.getSfxBuffer(); + + var dtsshader = material.mainPass.getShader(shaders.DtsTexture); + if (dtsshader != null) + material.mainPass.removeShader(dtsshader); + material.mainPass.removeShader(material.textureShader); + material.mainPass.addShader(shader); + material.mainPass.setPassName("refract"); } } }