add better shadow renderer

This commit is contained in:
RandomityGuy 2024-06-19 12:16:55 +05:30
parent 9bab55cba5
commit 7bb3969fc7
4 changed files with 145 additions and 12 deletions

View file

@ -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

View file

@ -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();

View file

@ -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;

42
src/Renderer.hx Normal file
View file

@ -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"));
}
}