Browse Source

- Add Fog

ShiroSmith 7 years ago
parent
commit
cdfd49db3f
3 changed files with 363 additions and 0 deletions
  1. 42 0
      h3d/scene/FogOccluder.hx
  2. 124 0
      h3d/shader/pbr/Fog.hx
  3. 197 0
      hxd/prefab/rfx/Fog.hx

+ 42 - 0
h3d/scene/FogOccluder.hx

@@ -0,0 +1,42 @@
+package h3d.scene;
+
+class FogOccluder extends Mesh {
+
+	public var strength = 1.0;
+	public var fresnelIntensity = 0.0;
+	public var fresnelPower = 1.0;
+	var shader : h3d.shader.pbr.FogOccluder;
+
+	public function new( ?parent ) {
+		super(h3d.prim.Sphere.defaultUnitSphere(), null, parent);
+		material.mainPass.setPassName("fogOccluder");
+		material.mainPass.removeShader(material.mainPass.getShader(h3d.shader.pbr.PropsValues));
+		material.texture = null;
+		material.shadows = false;
+		material.mainPass.depthTest = Less;
+		material.mainPass.culling = Back;
+		material.mainPass.blend(One, One);
+		material.mainPass.blendOp = Max;
+		shader = new h3d.shader.pbr.FogOccluder();
+		material.mainPass.addShader(shader);
+	}
+
+	override function draw( ctx : RenderContext ) {
+		primitive.render(ctx.engine);
+	}
+
+	override function emit( ctx : RenderContext ) {
+		ctx.emit(material, this);
+	}
+
+	override function sync(ctx:RenderContext) {
+		shader.spherePos = new h3d.Vector(x, y, z);
+		shader.fresnelIntensity = fresnelIntensity;
+		shader.fresnelPower = fresnelPower;
+		shader.sphereRadius = scaleX;
+		shader.cameraPos = ctx.camera.pos;
+		shader.cameraMatrix = ctx.camera.m;
+		shader.strength = strength;
+	}
+
+}

+ 124 - 0
h3d/shader/pbr/Fog.hx

@@ -0,0 +1,124 @@
+package h3d.shader.pbr;
+
+class FogClear extends h3d.shader.ScreenShader {
+
+	static var SRC = {
+
+		@param var fadingSpeed : Float;
+		@param var dt : Float;
+
+		@param var prevCamMat : Mat4;
+		@param var cameraInverseViewProj : Mat4;
+		@param var prevfogOcclusion : Sampler2D;
+		@ignore @param var depthTexture : Channel;
+
+		function getPixelPosition() : Vec3 {
+			var uv2 = uvToScreen(calculatedUV);
+			var depth = depthTexture.get(calculatedUV);
+			var temp = vec4(uv2, depthTexture.get(calculatedUV), 1) * cameraInverseViewProj;
+			var originWS = temp.xyz / temp.w;
+			return originWS;
+		}
+
+		function fragment() {
+			var pixelPos = getPixelPosition();
+			var prevPos =  vec4(pixelPos, 1.0) * prevCamMat;
+			prevPos.xyz /= prevPos.w;
+			var prevUV = screenToUv(prevPos.xy);
+			var uvOffset = calculatedUV - prevUV;
+			var prevOcclusion = prevfogOcclusion.get(calculatedUV - uvOffset).r;
+			if(prevUV.x < 0 || prevUV.x > 1 || prevUV.y < 0 || prevUV.y > 1) prevOcclusion = 0.0;
+			pixelColor = vec4(prevOcclusion - (dt * fadingSpeed), 0, 0, 0);
+		}
+	}
+
+	public function new() {
+		super();
+	}
+}
+
+class Fog extends h3d.shader.ScreenShader {
+
+	static var SRC = {
+
+		@ignore @param var depthTexture : Channel;
+		@param var fogOcclusion : Sampler2D;
+		@const var maxStepCount : Int;
+		@param var cameraPos : Vec3;
+		@param var cameraInverseViewProj : Mat4;
+		@param var time : Float;
+		@param var color : Vec3;
+		@param var tilling : Vec2;
+		@param var speed : Vec2;
+		@param var fadeStrength : Float;
+		@param var density : Float;
+		@global var fogHeight : Float;
+		@global var fogRange : Float;
+		@param var texture : Sampler2D;
+
+		@param var turbulenceText : Sampler2D;
+		@param var turbulenceScale : Float;
+		@param var turbulenceTilling : Vec2;
+		@param var turbulenceSpeed : Vec2;
+		@param var turbulenceIntensity : Float;
+
+		function getPixelPosition() : Vec3 {
+			var uv2 = uvToScreen(calculatedUV);
+			var depth = depthTexture.get(calculatedUV);
+			var temp = vec4(uv2, depthTexture.get(calculatedUV), 1) * cameraInverseViewProj;
+			var originWS = temp.xyz / temp.w;
+			return originWS;
+		}
+
+		function getFogDensity(pos: Vec3) : Float{
+			var fadeFactor = 1 - (abs((pos.z - fogHeight) / (fogRange)));
+			fadeFactor *= fadeFactor;
+			fadeFactor = mix(1, fadeFactor, fadeStrength);
+			var turbulenceUV = ((pos.xy / turbulenceTilling) -(pos.z * 0.5)) + time * turbulenceSpeed + time * speed;
+			var turbulence = textureLod(turbulenceText, turbulenceUV * turbulenceScale, 0).rg;
+			var textureOffset = turbulenceIntensity * turbulence;
+			var uv = (pos.xy / tilling) + textureOffset + time * speed;
+			var fog = textureLod(texture, uv, 0).r;
+			return fog * density * fadeFactor;
+		}
+
+		function fragment() {
+
+			var pixelPos = getPixelPosition();
+
+			var posToCam = normalize(cameraPos - pixelPos);
+			var camToPos = -posToCam;
+			var up = vec3(0,0,1);
+			var maxZ = fogHeight + fogRange - pixelPos.z;
+			var minZ = fogHeight - fogRange - pixelPos.z;
+
+			var UdC = dot(posToCam, up);
+			var distCamUpFog = ((cameraPos.z - (fogHeight + fogRange)) / UdC);
+			var distCamDownFog = ((cameraPos.z - (fogHeight - fogRange))  / UdC);
+			var fogStart = camToPos * distCamUpFog + cameraPos;
+			var fogEnd = camToPos * distCamDownFog + cameraPos;
+
+			if(fogRange <= 0) discard;
+			if(cameraPos.z < fogStart.z) discard;
+
+			var stepSize = length(fogEnd - fogStart) / maxStepCount;
+			var step = camToPos * stepSize;
+			var densitySum = 0.0;
+			var curPos = fogStart;
+			while(curPos.z > pixelPos.z && curPos.z > (fogHeight - fogRange)){
+				densitySum += getFogDensity(curPos);
+				curPos += step;
+			}
+
+			densitySum /= maxStepCount;
+			densitySum = clamp(densitySum, 0, 1);
+
+			var occlusion = 1 - fogOcclusion.get(calculatedUV).r;
+			pixelColor = vec4( color, densitySum * occlusion);
+		}
+	}
+
+	public function new() {
+		super();
+	}
+}

+ 197 - 0
hxd/prefab/rfx/Fog.hx

@@ -0,0 +1,197 @@
+package hxd.prefab.rfx;
+
+typedef FogProps = {
+	var density : Float;
+	var fadeStrength : Float;
+	var height : Float;
+	var range : Float;
+	var stepCount : Int;
+	var color : Int;
+	var tilling : Float;
+	var speed : Float;
+	var direction : Float;
+
+	var turbulenceText : String;
+	var turbulenceScale : Float;
+	var turbulenceTilling : Float;
+	var turbulenceIntensity : Float;
+	var turbulenceSpeed  : Float;
+
+	var fadingSpeed  : Float;
+}
+
+class Fog extends RendererFX {
+
+	var fogPass = new h3d.pass.ScreenFx(new h3d.shader.pbr.Fog());
+	var fogClear = new h3d.pass.ScreenFx(new h3d.shader.pbr.Fog.FogClear());
+	var fogTurbulence : h3d.mat.Texture;
+	var fogTexture : h3d.mat.Texture;
+	var fogOcclusion : h3d.mat.Texture;
+	var prevfogOcclusion : h3d.mat.Texture;
+	var prevCamMat : h3d.Matrix;
+
+	public function new(?parent) {
+		super(parent);
+
+		fogPass.pass.setBlendMode(Alpha);
+
+		props = ({
+				density : 1.0,
+				fadeStrength : 1.0,
+				height : 0,
+				range : 10,
+				stepCount : 10,
+				tilling : 1.0,
+				speed : 0.0,
+				direction : 0.0,
+
+				turbulenceText : null,
+				turbulenceScale: 0.0,
+				turbulenceTilling : 1.0,
+				turbulenceIntensity : 0.0,
+				turbulenceSpeed : 0.0,
+
+				fadingSpeed : 1.0,
+
+				color : 0xFFFFFF,
+			} : FogProps);
+	}
+
+	override function apply( r : h3d.scene.Renderer, step : RendererFX.Step ) {
+		var ctx = r.ctx;
+		var props : FogProps = props;
+
+		if( fogOcclusion == null ) fogOcclusion = new h3d.mat.Texture(ctx.engine.width, ctx.engine.height, [Target], RGBA);
+		if( prevfogOcclusion == null ) prevfogOcclusion = new h3d.mat.Texture(ctx.engine.width, ctx.engine.height, [Target], RGBA);
+
+		if(fogOcclusion.width != ctx.engine.width || fogOcclusion.height != ctx.engine.height){
+			fogOcclusion.dispose();
+			fogOcclusion = new h3d.mat.Texture(ctx.engine.width, ctx.engine.height, [Target], RGBA);
+		}
+
+		if(prevfogOcclusion.width != ctx.engine.width || prevfogOcclusion.height != ctx.engine.height){
+			prevfogOcclusion.dispose();
+			prevfogOcclusion = new h3d.mat.Texture(ctx.engine.width, ctx.engine.height, [Target], RGBA);
+		}
+
+		if( fogTexture == null ) syncFogTexture();
+
+		if( props.turbulenceText != null && (fogTurbulence == null || props.turbulenceText != fogTurbulence.name)) {
+			var prev = fogTurbulence;
+			fogTurbulence = hxd.res.Loader.currentInstance.load(props.turbulenceText).toTexture();
+			fogTurbulence.wrap = Repeat;
+			if(prev != null) prev.dispose();
+		}
+
+		if( step == AfterHdr ) {
+
+			var depth : hxsl.ChannelTexture = ctx.getGlobal("depthMap");
+
+			// Draw Fog Occluders
+			ctx.setGlobal("fogHeight", props.height);
+			ctx.setGlobal("fogRange", props.range);
+			fogPass.setGlobals(ctx);
+			fogOcclusion.depthBuffer = ctx.engine.driver.getDefaultDepthBuffer();
+			ctx.engine.pushTarget(fogOcclusion);
+			fogClear.shader.dt = ctx.elapsedTime;
+			fogClear.shader.fadingSpeed = props.fadingSpeed;
+			fogClear.shader.prevCamMat = prevCamMat == null ? ctx.camera.m : prevCamMat;
+			fogClear.shader.cameraInverseViewProj = ctx.camera.getInverseViewProj();
+			fogClear.shader.prevfogOcclusion = prevfogOcclusion;
+			fogClear.shader.depthTexture = depth.texture;
+			fogClear.shader.depthTextureChannel = depth.channel;
+			fogClear.render();
+			r.draw("fogOccluder");
+			ctx.engine.popTarget();
+
+			// Draw Fog
+			fogPass.shader.fogOcclusion = fogOcclusion;
+			fogPass.shader.depthTexture = depth.texture;
+			fogPass.shader.depthTextureChannel = depth.channel;
+			fogPass.shader.cameraPos = ctx.camera.pos;
+			fogPass.shader.cameraInverseViewProj.load(ctx.camera.getInverseViewProj());
+			fogPass.shader.density = props.density;
+			fogPass.shader.fadeStrength = props.fadeStrength;
+			fogPass.shader.maxStepCount = props.stepCount;
+			fogPass.shader.tilling = new h3d.Vector(props.tilling, props.tilling);
+			fogPass.shader.speed = new h3d.Vector(Math.cos(Math.degToRad(props.direction)) * props.speed, Math.sin(Math.degToRad(props.direction)) * props.speed);
+			fogPass.shader.turbulenceSpeed = new h3d.Vector(props.turbulenceSpeed, props.turbulenceSpeed);
+			fogPass.shader.time = ctx.time;
+			fogPass.shader.texture = fogTexture == null ? h3d.mat.Texture.fromColor(0xFFFFFF) : fogTexture;
+			fogPass.shader.turbulenceText = fogTurbulence == null ? h3d.mat.Texture.fromColor(0xFFFFFF) : fogTurbulence;
+			fogPass.shader.turbulenceScale = props.turbulenceScale;
+			fogPass.shader.turbulenceTilling = new h3d.Vector(props.turbulenceTilling, props.turbulenceTilling);
+			fogPass.shader.turbulenceIntensity = props.turbulenceIntensity;
+			fogPass.shader.color = h3d.Vector.fromColor(props.color);
+			fogPass.render();
+
+			var temp = prevfogOcclusion;
+			prevfogOcclusion = fogOcclusion;
+			fogOcclusion = temp;
+			prevCamMat = ctx.camera.m.clone();
+		}
+	}
+
+
+	function syncFogTexture() {
+		if( fogTexture != null ) fogTexture.dispose();
+		var c = Std.instance(this.children[0], hide.prefab.Noise);
+		fogTexture = c == null ? h3d.mat.Texture.fromColor(0x808080,0.5) : c.toTexture();
+		fogTexture.wrap = Repeat;
+	}
+
+	#if editor
+
+	override function getHideProps() {
+		var p = super.getHideProps();
+		p.allowChildren = function(name) return name == "noise";
+		//p.onChildUpdate = function(p) syncFogTexture();
+		return p;
+	}
+
+	override function edit( ctx : hide.prefab.EditContext ) {
+		var props : FogProps = props;
+		ctx.properties.add(new hide.Element('
+			<dl>
+
+			<div class="group" name="Fog">
+				<dt>Color</dt><dd><input type="color" field="color"></dd>
+				<dt>Tilling</dt><dd><input type="range" min="1" max="100" field="tilling"></dd>
+				<dt>Density</dt><dd><input type="range" min="0" max="100" field="density"></dd>
+				<dt>Height</dt><dd><input type="range" min="-20" max="20" field="height"></dd>
+				<dt>Range</dt><dd><input type="range" min="1" max="10" field="range"></dd>
+				<dt>Fade Strength</dt><dd><input type="range" min="0" max="1" field="fadeStrength"></dd>
+				<dt>Speed</dt><dd><input type="range" min="0" max="10" field="speed"></dd>
+				<dt>Direction</dt><dd><input type="range" min="0" max="360" step ="0.1" field="direction"></dd>
+			</div>
+
+			<div class="group" name="Quality">
+				<dt>Step Count</dt><dd><input type="range" min="1" max="100" step="1" field="stepCount"></dd>
+			</div>
+
+			<div class="group" name="Turbulence">
+				<dt>Texture</dt><input type="texturepath" field="turbulenceText"/>
+				<dt>Scale</dt><dd><input type="range" min="0" max="1" field="turbulenceScale"></dd>
+				<dt>Tilling</dt><dd><input type="range" min="0" max="2" field="turbulenceTilling"></dd>
+				<dt>Speed</dt><dd><input type="range" min="0" max="10" field="turbulenceSpeed"></dd>
+				<dt>Intensity</dt><dd><input type="range" min="0" max="1" field="turbulenceIntensity"></dd>
+			</div>
+
+			<div class="group" name="Trail">
+				<dt>Fading Speed</dt><dd><input type="range" min="0" max="2" field="fadingSpeed"></dd>
+			</div>
+
+			</dt>
+		'),props, function(pname) {
+			if(pname == "turbulenceText") {
+				if(fogTurbulence != null) fogTurbulence.dispose();
+				fogTurbulence = ctx.rootContext.loadTexture(props.turbulenceText);
+				fogTurbulence.wrap = Repeat;
+			}
+		});
+	}
+	#end
+
+	static var _ = Library.register("rfx.fog", Fog);
+
+}