From 35b353f535730e79fc922d8f553b5da4b2be0be7 Mon Sep 17 00:00:00 2001 From: RandomityGuy <31925790+RandomityGuy@users.noreply.github.com> Date: Wed, 16 Nov 2022 23:41:50 +0530 Subject: [PATCH] marble reflections for future --- src/Marble.hx | 34 ++++++++++++-------- src/MarbleWorld.hx | 16 ++++++--- src/shaders/CubemapRenderer.hx | 57 +++++++++++++++++++++++++++++++++ src/shaders/MarbleReflection.hx | 43 +++++++++++++++++++++++++ src/shapes/EasterEgg.hx | 2 +- 5 files changed, 133 insertions(+), 19 deletions(-) create mode 100644 src/shaders/CubemapRenderer.hx create mode 100644 src/shaders/MarbleReflection.hx diff --git a/src/Marble.hx b/src/Marble.hx index 571df94a..f3829435 100644 --- a/src/Marble.hx +++ b/src/Marble.hx @@ -1,5 +1,7 @@ package src; +import shaders.MarbleReflection; +import shaders.CubemapRenderer; import h3d.shader.AlphaMult; import shaders.DtsTexture; import collision.gjk.GJK; @@ -195,21 +197,10 @@ class Marble extends GameObject { var teleporting:Bool = false; + public var cubemapRenderer:CubemapRenderer; + public function new() { super(); - var geom = Sphere.defaultUnitSphere(); - geom.addUVs(); - var marbleTexture = ResourceLoader.getFileEntry("data/shapes/balls/base.marble.png").toTexture(); - var marbleMaterial = Material.create(marbleTexture); - marbleMaterial.shadows = false; - marbleMaterial.castShadows = true; - // marbleMaterial.mainPass.removeShader(marbleMaterial.textureShader); - // var dtsShader = new DtsTexture(); - // dtsShader.texture = marbleTexture; - // dtsShader.currentOpacity = 1; - // marbleMaterial.mainPass.addShader(dtsShader); - var obj = new Mesh(geom, marbleMaterial, this); - obj.scale(_radius); this.velocity = new Vector(); this.omega = new Vector(); @@ -244,6 +235,23 @@ class Marble extends GameObject { public function init(level:MarbleWorld, onFinish:Void->Void) { this.level = level; + + var geom = Sphere.defaultUnitSphere(); + geom.addUVs(); + var marbleTexture = ResourceLoader.getFileEntry("data/shapes/balls/base.marble.png").toTexture(); + var marbleMaterial = Material.create(marbleTexture); + marbleMaterial.shadows = false; + marbleMaterial.castShadows = true; + // marbleMaterial.mainPass.removeShader(marbleMaterial.textureShader); + // var dtsShader = new DtsTexture(); + // dtsShader.texture = marbleTexture; + // dtsShader.currentOpacity = 1; + // marbleMaterial.mainPass.addShader(dtsShader); + var obj = new Mesh(geom, marbleMaterial, this); + obj.scale(_radius); + this.cubemapRenderer = new CubemapRenderer(level.scene); + marbleMaterial.mainPass.addShader(new MarbleReflection(this.cubemapRenderer.cubemap)); + this.forcefield = new DtsObject(); this.forcefield.dtsPath = "data/shapes/images/glow_bounce.dts"; this.forcefield.useInstancing = true; diff --git a/src/MarbleWorld.hx b/src/MarbleWorld.hx index fe371ee6..490e5909 100644 --- a/src/MarbleWorld.hx +++ b/src/MarbleWorld.hx @@ -9,7 +9,6 @@ import triggers.DestinationTrigger; import shapes.Nuke; import shapes.Magnet; import src.Replay; -import hxd.impl.Air3File.FileSeek; import gui.Canvas; import hxd.snd.Channel; import hxd.res.Sound; @@ -230,6 +229,9 @@ class MarbleWorld extends Scheduler { } public function postInit() { + // Add the sky at the last so that cubemap reflections work + this.scene.addChild(this.sky); + this._ready = true; this.playGui.init(this.scene2d); var musicFileName = 'data/sound/' + this.mission.missionInfo.music; @@ -295,10 +297,10 @@ class MarbleWorld extends Scheduler { sky.dmlPath = ResourceLoader.getProperFilepath(skyElement.materiallist); worker.addTask(fwd -> sky.init(cast this, fwd)); - worker.addTask(fwd -> { - scene.addChild(sky); - return fwd(); - }); + // worker.addTask(fwd -> { + // scene.addChild(sky); + // return fwd(); + // }); worker.run(); } @@ -1014,6 +1016,10 @@ class MarbleWorld extends Scheduler { asyncLoadResources(); if (this.playGui != null && _ready) this.playGui.render(e); + if (this.marble != null && this.marble.cubemapRenderer != null) { + this.marble.cubemapRenderer.position.load(this.marble.getAbsPos().getPosition()); + this.marble.cubemapRenderer.render(e, 0.002); + } } function asyncLoadResources() { diff --git a/src/shaders/CubemapRenderer.hx b/src/shaders/CubemapRenderer.hx new file mode 100644 index 00000000..a1a1eebc --- /dev/null +++ b/src/shaders/CubemapRenderer.hx @@ -0,0 +1,57 @@ +package shaders; + +import h3d.Vector; +import h3d.scene.Scene; +import h3d.Engine; +import h3d.Camera; +import h3d.mat.Texture; + +class CubemapRenderer { + public var cubemap:Texture; + + public var position:Vector; + + var camera:Camera; + + var scene:Scene; + + var nextFaceToRender:Int; + + public function new(scene:Scene) { + this.scene = scene; + this.cubemap = new Texture(128, 128, [Cube, Dynamic, Target]); + this.camera = new Camera(90, 1, 1); + this.position = new Vector(); + this.nextFaceToRender = 0; + } + + public function render(e:Engine, budget:Float = 1e8) { + var scenecam = scene.camera; + scene.camera = camera; + + var start = haxe.Timer.stamp(); + var renderedFaces = 0; + + for (i in 0...6) { + var index = (nextFaceToRender + i) % 6; + + e.pushTarget(cubemap, index); + this.camera.setCubeMap(index, position); + e.clear(0, 1); + scene.render(e); + e.popTarget(); + + renderedFaces++; + var time = haxe.Timer.stamp(); + var elapsed = time - start; + var elapsedPerFace = elapsed / renderedFaces; + + if (elapsedPerFace * (renderedFaces + 1) >= budget) + break; + } + scene.camera = scenecam; + + this.nextFaceToRender += renderedFaces; + this.nextFaceToRender %= 6; + } +} diff --git a/src/shaders/MarbleReflection.hx b/src/shaders/MarbleReflection.hx new file mode 100644 index 00000000..ba151d78 --- /dev/null +++ b/src/shaders/MarbleReflection.hx @@ -0,0 +1,43 @@ +package shaders; + +class MarbleReflection extends hxsl.Shader { + static var SRC = { + var pixelColor:Vec4; + var transformedNormal:Vec3; + @param var texture:SamplerCube; + @global var camera:{ + var position:Vec3; + }; + @input var input:{ + var position:Vec3; + var normal:Vec3; + }; + var pixelTransformedPosition:Vec3; + function fresnel(direction:Vec3, normal:Vec3, invert:Bool):Float { + var nDirection = normalize(direction); + var nNormal = normalize(normal); + var halfDirection = normalize(nNormal + nDirection); + var exponent = 5.0; + var cosine = dot(halfDirection, nDirection); + var product = max(cosine, 0.0); + var factor = invert ? 1.0 - pow(product, exponent) : pow(product, exponent); + return factor; + } + function fragment() { + var viewDir = normalize(camera.position - pixelTransformedPosition); + var fac = fresnel(viewDir, transformedNormal, true); + + var incidentRay = normalize(pixelTransformedPosition - camera.position); + var reflectionRay = reflect(incidentRay, transformedNormal); + + var refl = texture.get(reflectionRay); + + pixelColor = mix(pixelColor, refl, fac * 0.7); + } + } + + public function new(texture) { + super(); + this.texture = texture; + } +} diff --git a/src/shapes/EasterEgg.hx b/src/shapes/EasterEgg.hx index 904c14fc..f26cbadf 100644 --- a/src/shapes/EasterEgg.hx +++ b/src/shapes/EasterEgg.hx @@ -35,7 +35,7 @@ class EasterEgg extends PowerUp { public override function init(level:src.MarbleWorld, onFinish:() -> Void) { super.init(level, () -> { ResourceLoader.load("sound/easter.wav").entry.load(() -> { - ResourceLoader.load("data/sound/easterfound.wav").entry.load(onFinish); + ResourceLoader.load("sound/easterfound.wav").entry.load(onFinish); }); }); }