Browse Source

refactor pbr renderer and RendererFX

Nicolas Cannasse 5 years ago
parent
commit
85a03df1b3
4 changed files with 135 additions and 215 deletions
  1. 6 4
      h3d/impl/RendererFX.hx
  2. 6 0
      h3d/scene/Renderer.hx
  3. 118 166
      h3d/scene/pbr/Renderer.hx
  4. 5 45
      h3d/shader/pbr/ToneMapping.hx

+ 6 - 4
h3d/impl/RendererFX.hx

@@ -1,15 +1,17 @@
 package h3d.impl;
 
 enum Step {
-	BeforeLighting;
-	BeforeTonemappingFX;
+	MainDraw;
+	Decals;
+	Lighting;
 	BeforeTonemapping;
 	AfterTonemapping;
-	AfterUI;
+	Overlay;
 }
 
 interface RendererFX {
 	public var enabled : Bool;
-	public function apply( r : h3d.scene.Renderer, step : Step ) : Void;
+	public function begin( r : h3d.scene.Renderer, step : Step ) : Void;
+	public function end( r : h3d.scene.Renderer, step : Step ) : Void;
 	public function dispose() : Void;
 }

+ 6 - 0
h3d/scene/Renderer.hx

@@ -53,6 +53,12 @@ class Renderer extends hxd.impl.AnyProps {
 	function mark(id: String) {
 	}
 
+	/**
+		Inject a post process shader for the current frame. Shaders are reset after each render.
+	**/
+	public function addShader( s : hxsl.Shader ) {
+	}
+
 	public function getPass<T:h3d.pass.Base>( c : Class<T> ) : T {
 		for( p in allPasses )
 			if( Std.is(p, c) )

+ 118 - 166
h3d/scene/pbr/Renderer.hx

@@ -17,10 +17,6 @@ package h3d.scene.pbr;
 		Debug slides
 	*/
 	var Debug = "Debug";
-	/*
-		Distortion
-	*/
-	var Distortion = "Distortion";
 }
 
 @:enum abstract SkyMode(String) {
@@ -38,9 +34,6 @@ package h3d.scene.pbr;
 
 typedef RenderProps = {
 	var mode : DisplayMode;
-	var colorGradingLUT : String;
-	var colorGradingLUTSize : Int;
-	var enableColorGrading : Bool;
 	var exposure : Float;
 	var sky : SkyMode;
 	var tone : TonemapMap;
@@ -72,12 +65,19 @@ class Renderer extends h3d.scene.Renderer {
 	var pbrProps = new h3d.shader.pbr.PropsImport();
 	var hasDebugEvent = false;
 	var enableFXAA = true;
+	var currentStep : h3d.impl.RendererFX.Step;
+
+	var textures = {
+		albedo : null,
+		normal : null,
+		pbr : null,
+		other : null,
+		hdr : null,
+		ldr : null,
+	};
 
 	public var skyMode : SkyMode = Hide;
 	public var toneMode : TonemapMap = Reinhard;
-	public var colorGradingLUT : h3d.mat.Texture;
-	public var colorGradingLUTSize : Int;
-	public var enableColorGrading : Bool;
 	public var displayMode : DisplayMode = Pbr;
 	public var env : Environment;
 	public var exposure(get,set) : Float;
@@ -97,7 +97,6 @@ class Renderer extends h3d.scene.Renderer {
 		Vec4([Value("output.metalness"), Value("output.roughness"), Value("output.occlusion"), Value("output.pbrStrength")])
 	]);
 
-
 	public function new(?env) {
 		super();
 		this.env = env;
@@ -120,6 +119,10 @@ class Renderer extends h3d.scene.Renderer {
 		super.dispose();
 	}
 
+	override function addShader(s:hxsl.Shader) {
+		tonemap.addShader(s);
+	}
+
 	inline function get_exposure() return tonemap.shader.exposure;
 	inline function set_exposure(v:Float) return tonemap.shader.exposure = v;
 
@@ -130,9 +133,9 @@ class Renderer extends h3d.scene.Renderer {
 
 	override function getPassByName(name:String):h3d.pass.Base {
 		switch( name ) {
-		case "overlay", "beforeTonemapping", "albedo", "distortion", "afterTonemapping":
+		case "overlay", "beforeTonemapping", "albedo", "afterTonemapping":
 			return defaultPass;
-		case "alpha", "additive":
+		case "default", "alpha", "additive":
 			return output;
 		case "decal":
 			return decalsOutput;
@@ -187,14 +190,6 @@ class Renderer extends h3d.scene.Renderer {
 		passes.reset();
 	}
 
-	function mainDraw() {
-		mark("MainDraw");
-		renderPass(output, get("default"), frontToBack);
-		renderPass(output, get("terrain"));
-		renderPass(output, get("alpha"), backToFront);
-		renderPass(output, get("additive"));
-	}
-
 	function lighting() {
 
 		var ls = hxd.impl.Api.downcast(getLightSystem(), LightSystem);
@@ -227,21 +222,12 @@ class Renderer extends h3d.scene.Renderer {
 			pbrProps.isScreen = true;
 			pbrOut.render();
 			resetTarget();
-			copy(ctx.getGlobal("hdr"), null);
+			copy(textures.hdr, null);
 			// no warnings
 			for( p in passObjects ) if( p != null ) p.rendered = true;
 			return;
 		}
 
-		// Indirect Lighting - Diffuse with volumetricLightmap
-		mark("VolumetricLightmap");
-		pbrProps.isScreen = false;
-		pbrIndirect.drawIndirectDiffuse = false;
-		pbrIndirect.drawIndirectSpecular = env != null ? true : false;
-		ctx.extraShaders = new hxsl.ShaderList(pbrProps, new hxsl.ShaderList(pbrIndirect, null));
-		draw("volumetricLightmap");
-		ctx.extraShaders = null;
-
 		// Indirect Lighting - Diffuse and Specular
  		if( env != null ) {
 			mark("Indirect Lighting");
@@ -252,50 +238,6 @@ class Renderer extends h3d.scene.Renderer {
 		}
 	}
 
-	function drawBeforeTonemapping() {
-		mark("BeforeTonemapping");
-		draw("beforeTonemappingDecal");
-		draw("beforeTonemapping");
-	}
-
-	function drawAfterTonemapping() {
-		mark("AfterTonemapping");
-		draw("afterTonemappingDecal");
-		draw("afterTonemapping");
-	}
-
-	function applyTonemapping() {
-		mark("ToneMapping");
-		// Bloom Params
-		var bloom = ctx.getGlobal("bloom");
-		tonemap.shader.bloom = bloom;
-		tonemap.shader.hasBloom = bloom != null;
-		// Distortion Params
-		var distortion = ctx.getGlobal("distortion");
-		tonemap.shader.distortion = distortion;
-		tonemap.shader.hasDistortion = distortion != null;
-		// Color Grading Params
-		tonemap.shader.pixelSize = new Vector(1.0/ctx.engine.width, 1.0/ctx.engine.height);
-		tonemap.shader.hasColorGrading = enableColorGrading && colorGradingLUT != null;
-		if( colorGradingLUT != null ) {
-			tonemap.shader.colorGradingLUT = colorGradingLUT;
-			tonemap.shader.lutSize = colorGradingLUTSize;
-		}
-		tonemap.shader.mode =	switch( toneMode ) {
-									case Linear: 0;
-									case Reinhard: 1;
-									default: 0;
-								};
-		var hdr = ctx.getGlobal("hdr");
-		tonemap.shader.hdrTexture = hdr;
-		tonemap.render();
-	}
-
-	function postDraw() {
-		mark("PostDraw");
-		draw("overlay");
-	}
-
 	function drawShadows( ls : LightSystem ) {
 		var light = @:privateAccess ctx.lights;
 		var passes = get("shadow");
@@ -308,10 +250,36 @@ class Renderer extends h3d.scene.Renderer {
 		}
 	}
 
-	function apply( step : h3d.impl.RendererFX.Step ) {
+	function begin( step : h3d.impl.RendererFX.Step ) {
+		mark(step.getName());
+
+		for( f in effects )
+			if( f.enabled )
+				f.begin(this, step);
+		currentStep = step;
+
+		if(step == Lighting && renderMode == Default) {
+			if( displayMode == Env ) {
+				ctx.engine.pushTarget(textures.albedo);
+				clear(0xFF404040);
+				ctx.engine.popTarget();
+			}
+			if( displayMode == MatCap ) {
+				ctx.engine.pushTarget(textures.albedo);
+				clear(0xFF808080);
+				ctx.engine.popTarget();
+				ctx.engine.pushTarget(textures.pbr);
+				clear(0x00FF80FF);
+				ctx.engine.popTarget();
+			}
+		}
+	}
+
+	function end() {
 		for( f in effects )
 			if( f.enabled )
-				f.apply(this, step);
+				f.end(this, currentStep);
+		currentStep = null;
 	}
 
 	override function computeStatic() {
@@ -328,53 +296,37 @@ class Renderer extends h3d.scene.Renderer {
 		}
 	}
 
-	override function render() {
-		var props : RenderProps = props;
-
-		var albedo = allocTarget("albedo", true, 1.);
-		var normal = allocTarget("normal", true, 1., RGBA16F);
-		var pbr = allocTarget("pbr", true, 1.);
-		var other = allocTarget("other", true, 1., RGBA32F);
-
-		ctx.setGlobal("albedoMap", { texture : albedo, channel : hxsl.Channel.R });
-		ctx.setGlobal("depthMap", { texture : other, channel : hxsl.Channel.G });
-		ctx.setGlobal("normalMap", { texture : normal, channel : hxsl.Channel.R });
-		ctx.setGlobal("occlusionMap", { texture : pbr, channel : hxsl.Channel.B });
-		ctx.setGlobal("bloom", null);
-
-		setTargets([albedo,normal,pbr,other]);
-		clear(0, 1, 0);
-		mainDraw();
-
-		mark("Decal");
-		setTargets([albedo,normal,pbr]);
-		renderPass(decalsOutput, get("terrainBlend"));
-		renderPass(decalsOutput, get("decal"));
+	function initTextures() {
+		textures.albedo = allocTarget("albedo", true, 1.);
+		textures.normal = allocTarget("normal", true, 1., RGBA16F);
+		textures.pbr = allocTarget("pbr", true, 1.);
+		textures.other = allocTarget("other", true, 1., RGBA32F);
+		textures.hdr = allocTarget("hdrOutput", true, 1, RGBA16F);
+		textures.ldr = allocTarget("ldrOutput");
+		ctx.setGlobal("albedoMap", { texture : textures.albedo, channel : hxsl.Channel.R });
+		ctx.setGlobal("depthMap", { texture : textures.other, channel : hxsl.Channel.G });
+		ctx.setGlobal("normalMap", { texture : textures.normal, channel : hxsl.Channel.R });
+		ctx.setGlobal("occlusionMap", { texture : textures.pbr, channel : hxsl.Channel.B });
+		ctx.setGlobal("hdrMap", textures.hdr);
+		ctx.setGlobal("ldrMap", textures.ldr);
+	}
 
-		if(renderMode == Default) {
-			if( displayMode == Env ) {
-				setTarget(albedo);
-				clear(0xFF404040);
-			}
+	function beginPbr() {
+		var props : RenderProps = props;
 
-			if( displayMode == MatCap ) {
-				setTarget(albedo);
-				clear(0xFF808080);
-				setTarget(pbr);
-				clear(0x00FF80FF);
-			}
+		// reset tonemap shaders
+		var s = @:privateAccess tonemap.shaders;
+		while( s != null ) {
+			if( s.s != tonemap.shader ) tonemap.removeShader(s.s);
+			s = s.next;
 		}
-		apply(BeforeLighting);
 
-		var hdr = allocTarget("hdrOutput", true, 1, RGBA16F);
-		ctx.setGlobal("hdr", hdr);
-		setTarget(hdr);
-		clear(0);
+		initTextures();
 
-		pbrProps.albedoTex = albedo;
-		pbrProps.normalTex = normal;
-		pbrProps.pbrTex = pbr;
-		pbrProps.otherTex = other;
+		pbrProps.albedoTex = textures.albedo;
+		pbrProps.normalTex = textures.normal;
+		pbrProps.pbrTex = textures.pbr;
+		pbrProps.otherTex = textures.other;
 		pbrProps.cameraInverseViewProj = ctx.camera.getInverseViewProj();
 		pbrProps.occlusionPower = props.occlusion * props.occlusion;
 
@@ -429,49 +381,70 @@ class Renderer extends h3d.scene.Renderer {
 			pbrDirect.doDiscard = true;
 		}
 
-		lighting();
+		tonemap.shader.mode = switch( toneMode ) {
+			case Linear: 0;
+			case Reinhard: 1;
+			default: 0;
+		};
+		tonemap.shader.hdrTexture = textures.hdr;
+	}
+
+	override function render() {
+		beginPbr();
 
-		apply(BeforeTonemappingFX);
-		drawBeforeTonemapping();
-		apply(BeforeTonemapping);
+		setTargets([textures.albedo,textures.normal,textures.pbr,textures.other]);
+		clear(0, 1, 0);
+
+		begin(MainDraw);
+		renderPass(output, get("default"), frontToBack);
+		renderPass(output, get("terrain"));
+		renderPass(output, get("alpha"), backToFront);
+		renderPass(output, get("additive"));
+		end();
 
-		mark("Distortion");
-		var distortion = allocTarget("distortion", true, 1.0, RG16F);
-		ctx.setGlobal("distortion", distortion);
-		setTarget(distortion);
+		setTargets([textures.albedo,textures.normal,textures.pbr]);
+		begin(Decals);
+		renderPass(decalsOutput, get("decal"));
+		end();
+
+		setTarget(textures.hdr);
 		clear(0);
-		draw("distortion");
+		begin(Lighting);
+		lighting();
+		end();
+		if( renderMode == LightProbe ) return;
 
-		var ldr = allocTarget("ldrOutput");
-		setTarget(ldr);
-		ctx.setGlobal("ldr", ldr);
+		begin(BeforeTonemapping);
+		draw("beforeTonemappingDecal");
+		draw("beforeTonemapping");
+		end();
 
-		applyTonemapping();
+		setTarget(textures.ldr);
+		tonemap.render();
 
-		drawAfterTonemapping();
-		apply(AfterTonemapping);
+		begin(AfterTonemapping);
+		draw("afterTonemappingDecal");
+		draw("afterTonemapping");
+		end();
 
-		postDraw();
+		begin(Overlay);
+		draw("overlay");
+		end();
 
-		apply(AfterUI);
+		endPbr();
+	}
 
+	function endPbr() {
 		resetTarget();
-
 		switch( displayMode ) {
-
 		case Pbr, Env, MatCap:
 			if( enableFXAA ) {
 				mark("FXAA");
-				fxaa.apply(ldr);
+				fxaa.apply(textures.ldr);
 			}
 			else {
-				copy(ldr, null);
+				copy(textures.ldr, null);
 			}
-
-		case Distortion:
-			resetTarget();
-			copy( distortion, null);
-
 		case Debug:
 			var shadowMap = ctx.textures.getNamed("shadowMap");
 			if( shadowMap == null )
@@ -480,13 +453,11 @@ class Renderer extends h3d.scene.Renderer {
 			slides.shader.shadowMapChannel = R;
 			pbrProps.isScreen = true;
 			slides.render();
-
 			if( !hasDebugEvent ) {
 				hasDebugEvent = true;
 				hxd.Window.getInstance().addEventTarget(onEvent);
 			}
 		}
-
 		if( hasDebugEvent && displayMode != Debug ) {
 			hasDebugEvent = false;
 			hxd.Window.getInstance().removeEventTarget(onEvent);
@@ -494,7 +465,6 @@ class Renderer extends h3d.scene.Renderer {
 	}
 
 	var debugPushPos : { x : Float, y : Float }
-
 	function onEvent(e:hxd.Event) {
 		if( e.kind == EPush && e.button == 2 )
 			debugPushPos = { x : e.relX, y : e.relY };
@@ -520,9 +490,6 @@ class Renderer extends h3d.scene.Renderer {
 	override function getDefaultProps( ?kind : String ):Any {
 		var props : RenderProps = {
 			mode : Pbr,
-			colorGradingLUT : null,
-			colorGradingLUTSize : 1,
-			enableColorGrading: true,
 			emissive : 1.,
 			exposure : 0.,
 			sky : Irrad,
@@ -538,21 +505,12 @@ class Renderer extends h3d.scene.Renderer {
 	}
 
 	override function refreshProps() {
-
 		var props : RenderProps = props;
-
 		displayMode = props.mode;
 		skyMode = props.sky;
 		toneMode = props.tone;
 		exposure = props.exposure;
 		shadows = props.shadows;
-
-		if( props.colorGradingLUT != null )
-			colorGradingLUT = hxd.res.Loader.currentInstance.load(props.colorGradingLUT).toTexture();
-		else
-			colorGradingLUT = null;
-		colorGradingLUTSize = props.colorGradingLUTSize;
-		enableColorGrading = props.enableColorGrading;
 	}
 
 	#if editor
@@ -583,12 +541,6 @@ class Renderer extends h3d.scene.Renderer {
 					</dd>
 				</div>
 
-				<div class="group" name="Color Grading">
-					<dt>LUT</dt><dd><input type="texturepath" field="colorGradingLUT" style="width:165px"/></dd>
-					<dt>LUT Size</dt><dd><input step="1" type="range" min="0" max="32" field="colorGradingLUTSize"></dd>
-					<dt>Enable</dt><dd><input type="checkbox" field="enableColorGrading"></dd>
-				</div>
-
 				<div class="group" name="Environment">
 					<dt>Env</dt>
 						<dd>

+ 5 - 45
h3d/shader/pbr/ToneMapping.hx

@@ -10,32 +10,15 @@ class ToneMapping extends ScreenShader {
 		@const var isSRBG : Bool;
 		@const var mode : Int;
 
-		@const var hasBloom : Bool;
-		@param var bloom : Sampler2D;
+		var hdrColor : Vec4;
 
-		@const var hasDistortion : Bool;
-		@param var distortion : Sampler2D;
-
-		@const var hasColorGrading : Bool;
-		@param var colorGradingLUT : Sampler2D;
-		@param var lutSize : Float;
-
-		@param var pixelSize : Vec2;
+		function __init__fragment() {
+			hdrColor = hdrTexture.get(calculatedUV);
+		}
 
 		function fragment() {
-
-			if( hasDistortion)  {
-				var baseUV = calculatedUV;
-				var distortionVal = distortion.get(baseUV).rg;
-				calculatedUV = baseUV + distortionVal ;
-			}
-
-			var color = hdrTexture.get(calculatedUV);
-			if( hasBloom )
-				color += bloom.get(calculatedUV);
-
+			var color = hdrColor;
 			color.rgb *= exposureExp;
-
 			switch( mode ) {
 			case 0:
 				// linear
@@ -43,30 +26,9 @@ class ToneMapping extends ScreenShader {
 				// reinhard
 				color.rgb = color.rgb / (color.rgb + vec3(1.));
 			}
-
 			// gamma correct
 			if( !isSRBG )
 				color.rgb = color.rgb.sqrt();
-
-			if( hasColorGrading ) {
-				var uv = min(color.rgb, vec3(1,1,1));
-				var innerWidth = lutSize - 1.0;
-				var sliceSize = 1.0 / lutSize;
-				var slicePixelSize = sliceSize / lutSize;
-				var sliceInnerSize = slicePixelSize * innerWidth;
-				var blueSlice0 = min(floor(uv.b * innerWidth), innerWidth);
-				var blueSlice1 = min(blueSlice0 + 1.0, innerWidth);
-				var xOffset = slicePixelSize * 0.5 + uv.r * sliceInnerSize;
-				var yOffset = sliceSize * 0.5 + uv.g * (1.0 - sliceSize);
-				var s0 = vec2(xOffset + (blueSlice0 * sliceSize), yOffset);
-				var s1 = vec2(xOffset + (blueSlice1 * sliceSize), yOffset);
-				var slice0Color = texture(colorGradingLUT, s0).rgb;
-				var slice1Color = texture(colorGradingLUT, s1).rgb;
-				var bOffset = mod(uv.b * innerWidth, 1.0);
-				var result = mix(slice0Color, slice1Color, bOffset);
- 				color.rgb = result;
-			}
-
 			pixelColor = color;
 		}
 	}
@@ -76,8 +38,6 @@ class ToneMapping extends ScreenShader {
 	public function new() {
 		super();
 		exposure = 0;
-		hasDistortion = false;
-		hasBloom = false;
 	}
 
 	function set_exposure(v) {