diff --git a/src/Main.hx b/src/Main.hx index b9c7be5b..0278e428 100644 --- a/src/Main.hx +++ b/src/Main.hx @@ -23,6 +23,7 @@ import src.ProfilerUI; import src.Gamepad; import src.Http; import datachannel.RTC; +import src.Renderer; class Main extends hxd.App { var marbleGame:MarbleGame; @@ -36,6 +37,11 @@ class Main extends hxd.App { override function init() { super.init(); + s3d.renderer = new Renderer(); + #if debug + s3d.checkPasses = false; + #end + #if (hl && !android) hl.UI.closeConsole(); #end diff --git a/src/Marble.hx b/src/Marble.hx index d8f2093d..5daeec3d 100644 --- a/src/Marble.hx +++ b/src/Marble.hx @@ -211,6 +211,7 @@ class Marble extends GameObject { public var _radius = 0.2; var _dtsRadius = 0.2; + var marbleDts:DtsObject; var _prevRadius:Float; @@ -318,6 +319,8 @@ class Marble extends GameObject { public var cubemapRenderer:CubemapRenderer; + var shadowVolume:h3d.scene.Mesh; + var connection:GameConnection; var moveMotionDir:Vector; var lastMove:Move; @@ -473,6 +476,8 @@ class Marble extends GameObject { mat.receiveShadows = false; } } + + mat.mainPass.setPassName("marble"); } // Calculate radius according to marble model (egh) @@ -489,6 +494,7 @@ class Marble extends GameObject { this._radius = 0.2; // For the sake of physics marbleDts.scale(0.2 / avgRadius); } + this.marbleDts = marbleDts; this._prevRadius = this._radius; @@ -504,6 +510,10 @@ class Marble extends GameObject { this.addChild(marbleDts); + buildShadowVolume(); + if (level != null) + level.scene.addChild(this.shadowVolume); + // var geom = Sphere.defaultUnitSphere(); // geom.addUVs(); // var marbleTexture = ResourceLoader.getFileEntry("data/shapes/balls/base.marble.png").toTexture(); @@ -550,6 +560,85 @@ class Marble extends GameObject { worker.run(); } + function buildShadowVolume() { + var idx = new hxd.IndexBuffer(); + // slanted part of cone + var circleVerts = 32; + for (i in 1...circleVerts) { + idx.push(0); + idx.push(i + 1); + idx.push(i); + } + // connect to start + idx.push(0); + idx.push(1); + idx.push(circleVerts); + + // base of cone + for (i in 1...circleVerts - 1) { + idx.push(1); + idx.push(i + 1); + idx.push(i + 2); + } + var pts = []; + pts.push(new h3d.col.Point(0, 0, -40.0)); + + for (i in 0...circleVerts) { + var x = i / (circleVerts - 1) * (2 * Math.PI); + pts.push(new h3d.col.Point(Math.cos(x) * 0.2, -Math.sin(x) * 0.2, 0.0)); + } + var shadowPoly = new h3d.prim.Polygon(pts, idx); + shadowPoly.addUVs(); + shadowPoly.addNormals(); + shadowVolume = new h3d.scene.Mesh(shadowPoly, h3d.mat.Material.create()); + shadowVolume.material.castShadows = false; + shadowVolume.material.receiveShadows = false; + shadowVolume.material.shadows = false; + + var colShader = new h3d.shader.FixedColor(0x000026, 0.35); + + var shadowPass1 = shadowVolume.material.mainPass.clone(); + shadowPass1.setPassName("shadowPass1"); + shadowPass1.stencil = new h3d.mat.Stencil(); + shadowPass1.stencil.setFunc(Always, 1, 0xFF, 0xFF); + shadowPass1.depth(false, Less); + shadowPass1.setColorMask(false, false, false, false); + shadowPass1.culling = Back; + shadowPass1.stencil.setOp(Keep, Increment, Keep); + shadowPass1.addShader(colShader); + + var shadowPass2 = shadowVolume.material.mainPass.clone(); + shadowPass2.setPassName("shadowPass2"); + shadowPass2.stencil = new h3d.mat.Stencil(); + shadowPass2.stencil.setFunc(Always, 1, 0xFF, 0xFF); + shadowPass2.depth(false, Less); + shadowPass2.setColorMask(false, false, false, false); + shadowPass2.culling = Front; + shadowPass2.stencil.setOp(Keep, Decrement, Keep); + shadowPass2.addShader(colShader); + + var shadowPass3 = shadowVolume.material.mainPass.clone(); + shadowPass3.setPassName("shadowPass3"); + shadowPass3.stencil = new h3d.mat.Stencil(); + shadowPass3.stencil.setFunc(LessEqual, 1, 0xFF, 0xFF); + shadowPass3.depth(false, Less); + shadowPass3.culling = Front; + shadowPass3.stencil.setOp(Keep, Keep, Keep); + shadowPass3.blend(SrcAlpha, OneMinusSrcAlpha); + shadowPass3.addShader(colShader); + + shadowVolume.material.addPass(shadowPass1); + shadowVolume.material.addPass(shadowPass2); + shadowVolume.material.addPass(shadowPass3); + + shadowVolume.material.removePass(shadowVolume.material.mainPass); + + var q = new Quat(); + q.initNormal(@:privateAccess this.level.dirLightDir.toPoint()); + + shadowVolume.setRotationQuat(q); + } + function findContacts(collisiomWorld:CollisionWorld, timeState:TimeState) { this.contacts = queuedContacts; CollisionPool.clear(); @@ -1966,12 +2055,10 @@ class Marble extends GameObject { updatePowerupStates(timeState); - var marbledts = cast(this.getChildAt(0), DtsObject); - if (isMegaMarbleEnabled(timeState)) { - marbledts.setScale(0.6666 / _dtsRadius); + marbleDts.setScale(0.6666 / _dtsRadius); } else { - marbledts.setScale(0.2 / _dtsRadius); + marbleDts.setScale(0.2 / _dtsRadius); } // if (isMegaMarbleEnabled(timeState)) { @@ -2149,6 +2236,10 @@ class Marble extends GameObject { } public function updatePowerupStates(timeState:TimeState) { + this.shadowVolume.setPosition(x, y, z); + this.shadowVolume.setScale(marbleDts.scaleX); + if (this.level == null) + return; var shockEnabled = isShockAbsorberEnabled(timeState); var bounceEnabled = isSuperBounceEnabled(timeState); var helicopterEnabled = isHelicopterEnabled(timeState); @@ -2440,6 +2531,7 @@ class Marble extends GameObject { this.slipSound.stop(); if (this.helicopterSound != null) this.helicopterSound.stop(); + this.shadowVolume.remove(); this.helicopter.remove(); super.dispose(); removeChildren(); diff --git a/src/MarbleWorld.hx b/src/MarbleWorld.hx index c758cf7f..91d0a311 100644 --- a/src/MarbleWorld.hx +++ b/src/MarbleWorld.hx @@ -388,7 +388,7 @@ class MarbleWorld extends Scheduler { } var worker = new ResourceLoaderWorker(() -> { - var renderer = cast(this.scene.renderer, h3d.scene.fwd.Renderer); + var renderer = cast(this.scene.renderer, src.Renderer); for (element in mission.root.elements) { if (element._type != MissionElementType.Sun) @@ -414,13 +414,6 @@ class MarbleWorld extends Scheduler { this.ambient = ambientColor; // ls.perPixelLighting = false; - var shadow = scene.renderer.getPass(h3d.pass.DefaultShadowMap); - shadow.power = 0.5; - shadow.mode = Dynamic; - shadow.minDist = 0.1; - shadow.maxDist = 200; - shadow.bias = 0; - var sunlight = new DirLight(sunDirection, scene); sunlight.color = directionalColor; diff --git a/src/Renderer.hx b/src/Renderer.hx new file mode 100644 index 00000000..5a2526f5 --- /dev/null +++ b/src/Renderer.hx @@ -0,0 +1,42 @@ +package src; + +import src.Console; + +class Renderer extends h3d.scene.Renderer { + var def(get, never):h3d.pass.Base; + + public var shadow = new h3d.pass.DefaultShadowMap(1); + + public function new() { + super(); + defaultPass = new h3d.pass.Default("default"); + allPasses = [defaultPass, shadow]; + } + + inline function get_def() + return defaultPass; + + // 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") + return defaultPass; + return super.getPassByName(name); + } + + override function render() { + if (has("shadow")) + renderPass(shadow, get("shadow")); + + renderPass(defaultPass, get("default")); + renderPass(defaultPass, get("shadowPass1")); + renderPass(defaultPass, get("shadowPass2")); + renderPass(defaultPass, get("shadowPass3")); + renderPass(defaultPass, get("marble")); + renderPass(defaultPass, get("alpha"), backToFront); + renderPass(defaultPass, get("additive")); + } +}