ShiroSmith пре 5 година
родитељ
комит
8b07c209e2
2 измењених фајлова са 475 додато и 0 уклоњено
  1. 238 0
      hrt/prefab/rfx/FrustumJitter.hx
  2. 237 0
      hrt/prefab/rfx/TemporalFiltering.hx

+ 238 - 0
hrt/prefab/rfx/FrustumJitter.hx

@@ -0,0 +1,238 @@
+package hrt.prefab.rfx;
+
+@:enum abstract Pattern(String) {
+	var Still = "Still";
+	var Uniform2 = "Uniform2";
+	var Uniform4 = "Uniform4";
+	var Uniform4_Helix = "Uniform4_Helix";
+	var Uniform4_DoubleHelix = "Uniform4_DoubleHelix";
+	var SkewButterfly = "SkewButterfly";
+	var Rotated4 = "Rotated4";
+	var Rotated4_Helix = "Rotated4_Helix";
+	var Rotated4_Helix2 = "Rotated4_Helix2";
+	var Poisson10 = "Poisson10";
+	var Pentagram = "Pentagram";
+	var Halton_2_3_x8 = "Halton_2_3_x8";
+	var Halton_2_3_x16 = "Halton_2_3_x16";
+	var Halton_2_3_x32 = "Halton_2_3_x32";
+	var Halton_2_3_x256 = "Halton_2_3_x256";
+	var MotionPerp2 = "MotionPerp2";
+	var MotionVPerp2 = "MotionVPerp2";
+}
+
+class FrustumJitter {
+	
+	public var points_Still : Array<Float> = [
+		0.0, 0.0,
+	];
+
+   	public var points_Uniform2 : Array<Float> = [
+		-0.2, -0.2,//ll
+		0.2,  0.2,//ur
+	];
+
+	public var points_Uniform4 : Array<Float> = [
+		-0.2, -0.2,//ll
+		0.2, -0.2,//lr
+		0.2,  0.2,//ur
+		-0.2,  0.2,//ul
+	];
+
+	public var points_Uniform4_Helix : Array<Float> = [
+		-0.2, -0.2,//ll  3  1
+		0.2,  0.2,//ur   \/|
+		0.2, -0.2,//lr   /\|
+		-0.2,  0.2,//ul  0  2
+	];
+
+	public var points_Uniform4_DoubleHelix : Array<Float> = [
+		-0.2, -0.2,//ll  3  1
+		0.2,  0.2,//ur   \/|
+		0.2, -0.2,//lr   /\|
+		-0.2,  0.2,//ul  0  2
+		-0.2, -0.2,//ll  6--7
+		0.2, -0.2,//lr   \
+		-0.2,  0.2,//ul    \
+		0.2,  0.2,//ur  4--5
+	];
+
+	public var points_SkewButterfly : Array<Float> = [
+		-0.250, -0.250,
+		0.250,  0.250,
+		0.12, -0.12,
+		-0.12,  0.12,
+	];
+
+	public var points_Rotated4 : Array<Float> = [
+		-0.12, -0.37,//ll
+		0.37, -0.12,//lr
+		0.12,  0.37,//ur
+		-0.37,  0.12,//ul
+	];
+
+	public var points_Rotated4_Helix : Array<Float> = [
+		-0.12, -0.37,//ll  3  1
+		0.12,  0.37,//ur   \/|
+		0.37, -0.12,//lr   /\|
+		-0.37,  0.12,//ul  0  2
+	];
+
+	public var points_Rotated4_Helix2 : Array<Float> = [
+		-0.12, -0.37,//ll  2--1
+		0.12,  0.37,//ur   \/
+		-0.37,  0.12,//ul   /\
+		0.37, -0.12,//lr  0  3
+	];
+
+	public var points_Poisson10 : Array<Float> = [
+		-0.16795960*0.2,  0.65544910*0.2,
+		-0.69096030*0.2,  0.59015970*0.2,
+		0.49843820*0.2,  0.83099720*0.2,
+		0.17230150*0.2, -0.03882703*0.2,
+		-0.60772670*0.2, -0.06013587*0.2,
+		0.65606390*0.2,  0.24007600*0.2,
+		0.80348370*0.2, -0.48096900*0.2,
+		0.33436540*0.2, -0.73007030*0.2,
+		-0.47839520*0.2, -0.56005300*0.2,
+		-0.12388120*0.2, -0.96633990*0.2,
+	];
+
+	public var points_Pentagram : Array<Float> = [
+		0.000000*0.,  0.525731*0.,// head
+		-0.309017*0., -0.42532*0.,// lleg
+		0.500000*0.,  0.162460*0.,// rarm
+		-0.500000*0.,  0.162460*0.,// larm
+		0.309017*0., -0.42532*0.,// rleg
+	];
+
+	public var points_Halton_2_3_x8 : Array<Float> = [];
+	public var points_Halton_2_3_x16 : Array<Float> = [];
+	public var points_Halton_2_3_x32 : Array<Float> = [];
+	public var points_Halton_2_3_x256 : Array<Float> = [];
+	public var points_MotionPerp2 : Array<Float> = [
+		0.00, -0.2,
+		0.00,  0.2,
+	];
+
+	public var points_MotionVPerp2 : Array<Float> = [
+		-0.20, -0.0,
+		0.20,  0.0,
+	];
+
+
+	
+    private inline function getSeq( pattern : Pattern ) : Array<Float> {
+       return switch (pattern) {
+			case Still: points_Still;
+			case Uniform2 : points_Uniform2;
+			case Uniform4 : points_Uniform4;
+			case Uniform4_Helix : points_Uniform4_Helix;
+			case Uniform4_DoubleHelix : points_Uniform4_DoubleHelix;
+			case SkewButterfly : points_SkewButterfly;
+			case Rotated4 : points_Rotated4;
+			case Rotated4_Helix : points_Rotated4_Helix;
+			case Rotated4_Helix2 : points_Rotated4_Helix2;
+			case Poisson10 : points_Poisson10;
+			case Pentagram : points_Pentagram;
+			case Halton_2_3_x8 : points_Halton_2_3_x8;
+			case Halton_2_3_x16 : points_Halton_2_3_x16;
+			case Halton_2_3_x32 : points_Halton_2_3_x32;
+			case Halton_2_3_x256 : points_Halton_2_3_x256;
+			case MotionPerp2 : points_MotionPerp2;
+			case MotionVPerp2 : points_MotionVPerp2;
+			default : null;
+		}
+    }
+
+	public var patternScale = 1.0;
+	public var activeIndex = 0;
+	public var curSample = new h2d.col.Point(0,0);
+	public var prevSample = new h2d.col.Point(0,0);
+	public var curPattern : Pattern = Still;
+
+	public function new() {
+		
+		// points_Pentagram
+		var vh = new h3d.Vector(points_Pentagram[0] - points_Pentagram[2], points_Pentagram[1] - points_Pentagram[3]);
+		var vu = new h3d.Vector(0.0, 1.0);
+		transformPattern(points_Pentagram, hxd.Math.degToRad(0.5 * hxd.Math.atan2(vh.y - vu.y, vh.x - vu.x)), 1.0);
+
+		// points_Halton_2_3_xN
+		points_Halton_2_3_x8.resize(8);
+		initializeHalton_2_3(points_Halton_2_3_x8);
+		points_Halton_2_3_x16.resize(16);
+		initializeHalton_2_3(points_Halton_2_3_x16);
+		points_Halton_2_3_x32.resize(32);
+		initializeHalton_2_3(points_Halton_2_3_x32);
+		points_Halton_2_3_x256.resize(256);
+		initializeHalton_2_3(points_Halton_2_3_x256);
+	}
+
+	public function update() {
+
+		var seq = getSeq(curPattern);
+		if( seq == null )
+			return;
+
+		activeIndex += 1;
+		activeIndex %= seq.length;
+
+		var newSample = sample(seq, activeIndex);
+		prevSample.load(curSample);
+		curSample.load(newSample);
+	}
+
+	private function sample( pattern : Array<Float>, index : Int ) : h2d.col.Point
+    {
+        var n = Std.int(pattern.length / 2.0);
+        var i = index % n;
+
+        var x = patternScale * pattern[2 * i + 0];
+		var y = patternScale * pattern[2 * i + 1];
+		
+		return new h2d.col.Point(x, y);
+
+        /*if (pattern != Pattern.MotionPerp2)
+            return new Vector2(x, y);
+        else
+            return new Vector2(x, y).Rotate(Vector2.right.SignedAngle(focalMotionDir));*/
+    }
+
+	private function transformPattern( seq : Array<Float>, theta : Float, scale : Float) {
+        var cs = hxd.Math.cos(theta);
+		var sn = hxd.Math.sin(theta);
+		var i = 0;
+		var j = 1;
+		while( i != seq.length ) {
+			var x = scale * seq[i];
+            var y = scale * seq[j];
+            seq[i] = x * cs - y * sn;
+            seq[j] = x * sn + y * cs;
+			i += 2;
+			j += 2;
+		}
+    }
+
+	// http://en.wikipedia.org/wiki/Halton_sequence
+	private function haltonSeq(prime : Int, index : Int = 1/* NOT! zero-based */) : Float {
+		var r = 0.0;
+		var f = 1.0;
+		var i = index;
+		while( i > 0 ) {
+			f /= prime;
+			r += f * (i % prime);
+			i = hxd.Math.floor(i / prime);
+		}
+		return r;
+	}
+
+	private function initializeHalton_2_3( seq : Array<Float> ) {
+		var sampleCount = Std.int(seq.length / 2.0);
+		for( i in 0 ... sampleCount ) {
+			var u = haltonSeq(2, i + 1) - 0.5;
+			var v = haltonSeq(3, i + 1) - 0.5;
+			seq[2 * i + 0] = u;
+			seq[2 * i + 1] = v;
+		}
+	}
+}

+ 237 - 0
hrt/prefab/rfx/TemporalFiltering.hx

@@ -0,0 +1,237 @@
+package hrt.prefab.rfx;
+
+typedef TemporalFilteringProps = {
+	var amount : Float;
+	var varianceClipping : Bool;
+	var ycocg : Bool;
+	var unjitter : Bool;
+	var jitterPattern : FrustumJitter.Pattern;
+	var jitterScale : Float;
+	var renderMode : String;
+}
+
+class TemporalFilteringShader extends h3d.shader.ScreenShader {
+
+	static var SRC = {
+
+		@const var VARIANCE_CLIPPING : Bool;
+		@const var YCOCG : Bool;
+		@const var UNJITTER : Bool;
+
+		@param var prevFrame : Sampler2D;
+		@param var curFrame : Sampler2D;
+		@param var resolution : Vec2;
+		@param var amount : Float;
+		@param var jitterUV : Vec2;
+		@param var prevJitterUV : Vec2;
+
+		@param var prevCamMat : Mat4;
+		@param var cameraInverseViewProj : Mat4;
+		@param var depthTexture : Channel;
+
+		function rgb2ycocg( rgb : Vec3 ) : Vec3 {
+			if( YCOCG ) {
+				var co = rgb.r - rgb.b;
+				var t = rgb.b + co / 2.0;
+				var cg = rgb.g - t;
+				var y = t + cg / 2.0;
+				return vec3(y, co, cg);
+			}
+			else
+				return rgb;
+		}
+
+		function ycocg2rgb( ycocg : Vec3 ) : Vec3 {
+			if( YCOCG ) {
+				var t = ycocg.r - ycocg.b / 2.0;
+				var g = ycocg.b + t;
+				var b = t - ycocg.g / 2.0;
+				var r = ycocg.g + b;
+				return vec3(r, g, b);
+			}
+			else
+				return ycocg;
+		}
+
+		function clipToAABB( cOld : Vec3, cNew : Vec3, centre : Vec3, halfSize : Vec3 ) : Vec3 {
+			var a = abs(cOld - centre);
+			if( a.r <= halfSize.r && a.g <= halfSize.g && a.b <= halfSize.b ) {
+				return cOld;
+			}
+			else {
+				var dir = (cNew - cOld);
+				var near = centre - sign(dir) * halfSize;
+				var tAll = (near - cOld) / dir;
+				var t = 1.0;
+				if( tAll.x >= 0.0 && tAll.x < t ) t = tAll.x;
+				if( tAll.y >= 0.0 && tAll.y < t ) t = tAll.y;
+				if( tAll.z >= 0.0 && tAll.z < t ) t = tAll.z;
+
+				if( t >= 1.0 ) {
+					return cOld;
+				}
+				else
+					return cOld + dir * t;
+			}
+		}
+
+		function getPixelPosition( uv : Vec2 ) : Vec3 {
+			var tmp = vec4(uvToScreen(uv), depthTexture.get(uv).r, 1) * cameraInverseViewProj;
+			tmp.xyz /= tmp.w;
+			return tmp.xyz;
+		}
+
+		function fragment() {
+			var unJitteredUV = calculatedUV;
+			if( UNJITTER )
+				unJitteredUV -= jitterUV * 0.5;
+
+			var curPos = getPixelPosition(calculatedUV);
+			var prevPos = vec4(curPos, 1.0) * prevCamMat;
+			prevPos.xyz /= prevPos.w;
+
+			// Discard Pixels outside bounds
+			if( abs(prevPos.x) > 1.0 || abs(prevPos.y) > 1.0 )
+				discard;
+
+			var prevUV = screenToUv(prevPos.xy);
+			var prevColor = prevFrame.get(prevUV).rgb;
+			var curColor = curFrame.get(unJitteredUV).rgb;
+
+			// Neighborhood clipping [MALAN 2012][KARIS 2014]
+			if( VARIANCE_CLIPPING ) {
+				var offsets : Array<Vec2, 4> = [ vec2(-1.0,0.0), vec2(1.0,0.0), vec2(0.0,-1.0), vec2(0.0, 1.0) ];
+				var m1 = rgb2ycocg(curColor);
+				var m2 = m1 * m1;
+				for( i in 0 ... 4 ) {
+					var c = rgb2ycocg(curFrame.getLod(unJitteredUV + (offsets[i] / resolution), 0).rgb);
+					m1 += c;
+					m2 += c * c;
+				}
+				m1 /= 5.0;
+				m2 = sqrt(m2 / 5.0 - m1 * m1);
+				prevColor = ycocg2rgb(clipToAABB(rgb2ycocg(prevColor), rgb2ycocg(curColor), m1, m2));
+			}
+
+			pixelColor.rgb = mix(curColor, prevColor, amount);
+			pixelColor.a = 1.0;
+		}
+	}
+}
+
+class TemporalFiltering extends hrt.prefab.rfx.RendererFX {
+
+	var frustumJitter = new FrustumJitter();
+	var pass = new h3d.pass.ScreenFx(new TemporalFilteringShader());
+	var curMatNoJitter = new h3d.Matrix();
+	var jitterMat = new h3d.Matrix();
+
+	public function new(?parent) {
+		super(parent);
+		props = ({
+			amount : 0.0,
+			varianceClipping : true,
+			ycocg : true,
+			unjitter : true,
+			jitterPattern : Still,
+			jitterScale : 1.0,
+			renderMode : "AfterTonemapping",
+		} : TemporalFilteringProps);
+	}
+
+	override function begin( r:h3d.scene.Renderer, step:h3d.impl.RendererFX.Step ) {
+		if( step == MainDraw ) {
+			var ctx = r.ctx;
+			var p : TemporalFilteringProps = props;
+			var s = pass.shader;
+			s.prevJitterUV.set(-frustumJitter.prevSample.x / ctx.engine.width, frustumJitter.prevSample.y / ctx.engine.height);
+			frustumJitter.curPattern = p.jitterPattern;
+			frustumJitter.patternScale = p.jitterScale;
+			frustumJitter.update();
+			jitterMat.identity();
+			jitterMat.translate(frustumJitter.curSample.x / ctx.engine.width, frustumJitter.curSample.y / ctx.engine.height);
+			s.jitterUV.set(-frustumJitter.curSample.x / ctx.engine.width, frustumJitter.curSample.y / ctx.engine.height);
+			ctx.camera.update();
+			curMatNoJitter.load(ctx.camera.m);
+			ctx.camera.mproj.multiply(ctx.camera.mproj, jitterMat);
+			ctx.camera.m.multiply(ctx.camera.mcam, ctx.camera.mproj);
+			s.cameraInverseViewProj.initInverse(curMatNoJitter);
+			@:privateAccess ctx.camera.needInv = true;
+		}
+	}
+
+	override function end( r:h3d.scene.Renderer, step:h3d.impl.RendererFX.Step ) {
+		var p : TemporalFilteringProps = props;
+		if( ( step == AfterTonemapping && p.renderMode == "AfterTonemapping") || (step == BeforeTonemapping && p.renderMode == "BeforeTonemapping" ) ) {
+			r.mark("TemporalFiltering");
+			var ctx = r.ctx;
+			var s = pass.shader;
+			var output : h3d.mat.Texture = ctx.engine.getCurrentTarget();
+			var depthMap = ctx.getGlobal("depthMap");
+			var prevFrame = r.allocTarget("prevFrame", false, 1.0, output.format);
+			var curFrame = r.allocTarget("curFrame", false, 1.0, output.format);
+			h3d.pass.Copy.run(output, curFrame);
+			s.curFrame = curFrame;
+			s.prevFrame = prevFrame;
+			s.amount = p.amount;
+			s.depthTexture = depthMap.texture;
+			s.depthTextureChannel = depthMap.channel;
+			s.resolution.set(output.width, output.height);
+			s.VARIANCE_CLIPPING = p.varianceClipping;
+			s.YCOCG = p.ycocg;
+			s.UNJITTER = p.unjitter;
+			r.setTarget(output);
+			pass.render();
+			h3d.pass.Copy.run(output, prevFrame);
+			s.prevCamMat.load(curMatNoJitter);
+		}
+	}
+
+	#if editor
+	override function edit( ctx : hide.prefab.EditContext ) {
+		ctx.properties.add(new hide.Element('
+			<dl>
+				<dt>Amount</dt><dd><input type="range" min="0" max="1" field="amount"/></dd>
+				<dt>Variance Clipping</dt><dd><input type="checkbox" field="varianceClipping"/></dd>
+				<dt>Ycocg</dt><dd><input type="checkbox" field="ycocg"/></dd>
+				<dt>Unjitter</dt><dd><input type="checkbox" field="unjitter"/></dd>
+				<div class="group" name="Jitter">
+					<dt>Pattern</dt>
+						<dd>
+							<select field="jitterPattern">
+								<option value="Still">Still</option>
+								<option value="Uniform2">Uniform2</option>
+								<option value="Uniform4">Uniform4</option>
+								<option value="Uniform4_Helix">Uniform4 Helix</option>
+								<option value="Uniform4_DoubleHelix">Uniform4 DoubleHelix</option>
+								<option value="SkewButterfly">SkewButterfly</option>
+								<option value="Rotated4">Rotated4</option>
+								<option value="Rotated4_Helix">Rotated4 Helix</option>
+								<option value="Rotated4_Helix2">Rotated4 Helix2</option>
+								<option value="Poisson10">Poisson10</option>
+								<option value="Pentagram">Pentagram</option>
+								<option value="Halton_2_3_x8">Halton_2_3_x8</option>
+								<option value="Halton_2_3_x16">Halton_2_3_x16</option>
+								<option value="Halton_2_3_x32">Halton_2_3_x32</option>
+								<option value="Halton_2_3_x256">Halton_2_3_x256</option>
+								<option value="MotionPerp2">MotionPerp2</option>
+								<option value="MotionVPerp2">MotionVPerp2</option>
+							</select>
+						</dd>
+					<dt>Scale</dt><dd><input type="range" min="0" max="2" field="jitterScale"/></dd>
+				</div>
+				<div class="group" name="Rendering">
+					<dt>Render Mode</dt>
+						<dd><select field="renderMode">
+							<option value="BeforeTonemapping">Before Tonemapping</option>
+							<option value="AfterTonemapping">After Tonemapping</option>
+						</select></dd>
+				</div>
+			</dl>
+		'),props);
+	}
+	#end
+
+	static var _ = hrt.prefab.Library.register("rfx.temporalFiltering", TemporalFiltering);
+
+}