206 lines
		
	
	
		
			5.6 KiB
		
	
	
	
		
			Haxe
		
	
	
	
	
	
		
		
			
		
	
	
			206 lines
		
	
	
		
			5.6 KiB
		
	
	
	
		
			Haxe
		
	
	
	
	
	
|  | package iron.object; | ||
|  | 
 | ||
|  | import kha.graphics4.Graphics; | ||
|  | import kha.graphics4.TextureFormat; | ||
|  | import kha.graphics4.DepthStencilFormat; | ||
|  | import kha.graphics4.CubeMap; | ||
|  | import iron.data.ProbeData; | ||
|  | import iron.data.CameraData; | ||
|  | import iron.data.SceneFormat; | ||
|  | import iron.math.Vec4; | ||
|  | import iron.math.Mat4; | ||
|  | 
 | ||
|  | class ProbeObject extends Object { | ||
|  | 
 | ||
|  | #if rp_probes | ||
|  | 
 | ||
|  | 	public var data: ProbeData; | ||
|  | 	public var renderTarget: kha.Image = null; | ||
|  | 	public var camera: CameraObject = null; | ||
|  | 	public var ready = false; | ||
|  | 
 | ||
|  | 	// Cubemap update | ||
|  | 	public var perFrame = false; // Update probe every frame | ||
|  | 	public var redraw = true; // Update probe next frame | ||
|  | 
 | ||
|  | 	var m1: Mat4; | ||
|  | 	var m2: Mat4; | ||
|  | 	var proben: Vec4; | ||
|  | 	var probep: Vec4; | ||
|  | 	// static var v = new Vec4(); | ||
|  | 	static var p = new Vec4(); | ||
|  | 	static var q = new Vec4(); | ||
|  | 
 | ||
|  | 	public function new(data: ProbeData) { | ||
|  | 		super(); | ||
|  | 		this.data = data; | ||
|  | 		Scene.active.probes.push(this); | ||
|  | 		iron.App.notifyOnInit(init); | ||
|  | 	} | ||
|  | 
 | ||
|  | 	public override function remove() { | ||
|  | 		if (Scene.active != null) Scene.active.probes.remove(this); | ||
|  | 		// if (camera != null) camera.remove(); | ||
|  | 		super.remove(); | ||
|  | 	} | ||
|  | 
 | ||
|  | 	function init() { | ||
|  | 		probep = transform.world.getLoc(); | ||
|  | 		proben = transform.up().normalize(); | ||
|  | 		proben.w = -probep.dot(proben); | ||
|  | 
 | ||
|  | 		if (data.raw.type == "planar") { | ||
|  | 			m1 = Mat4.identity(); | ||
|  | 			m2 = Mat4.identity(); | ||
|  | 			reflect(m1, proben, probep); | ||
|  | 			reflect(m2, new Vec4(0, 1, 0), probep); | ||
|  | 
 | ||
|  | 			transform.scale.z = 1.0; // Only take dim.z into account | ||
|  | 			transform.buildMatrix(); | ||
|  | 
 | ||
|  | 			// var aspect = transform.scale.x / transform.scale.y; | ||
|  | 			var aspect = iron.App.w() / iron.App.h(); // TODO | ||
|  | 			var craw: TCameraData = { | ||
|  | 				name: raw.name + "_Camera", | ||
|  | 				near_plane: Scene.active.camera.data.raw.near_plane, | ||
|  | 				far_plane: Scene.active.camera.data.raw.far_plane, | ||
|  | 				fov: Scene.active.camera.data.raw.fov, | ||
|  | 				aspect: aspect | ||
|  | 			}; | ||
|  | 			new CameraData(craw, function(cdata: CameraData) { | ||
|  | 				camera = new CameraObject(cdata); | ||
|  | 				camera.renderTarget = kha.Image.createRenderTarget( | ||
|  | 					iron.App.w(), // TODO | ||
|  | 					iron.App.h(), | ||
|  | 					TextureFormat.RGBA32, | ||
|  | 					DepthStencilFormat.NoDepthAndStencil | ||
|  | 				); | ||
|  | 				camera.name = craw.name; | ||
|  | 				camera.setParent(iron.Scene.active.root); | ||
|  | 				// Make target bindable from render path | ||
|  | 				var rt = new RenderPath.RenderTarget(new RenderPath.RenderTargetRaw()); | ||
|  | 				rt.raw.name = raw.name; | ||
|  | 				rt.image = camera.renderTarget; | ||
|  | 				RenderPath.active.renderTargets.set(rt.raw.name, rt); | ||
|  | 				ready = true; | ||
|  | 			}); | ||
|  | 		} | ||
|  | 		else if (data.raw.type == "cubemap") { | ||
|  | 			transform.scale.x *= transform.dim.x; | ||
|  | 			transform.scale.y *= transform.dim.y; | ||
|  | 			transform.scale.z *= transform.dim.z; | ||
|  | 			transform.buildMatrix(); | ||
|  | 
 | ||
|  | 			var craw: TCameraData = { | ||
|  | 				name: data.raw.name + "_Camera", | ||
|  | 				near_plane: Scene.active.camera.data.raw.near_plane, | ||
|  | 				far_plane: Scene.active.camera.data.raw.far_plane, | ||
|  | 				fov: 1.5708, // pi/2 | ||
|  | 				aspect: 1.0 | ||
|  | 			}; | ||
|  | 			new CameraData(craw, function(cdata: CameraData) { | ||
|  | 				camera = new CameraObject(cdata); | ||
|  | 				camera.renderTargetCube = CubeMap.createRenderTarget( | ||
|  | 					1024, // TODO | ||
|  | 					TextureFormat.RGBA32, | ||
|  | 					DepthStencilFormat.NoDepthAndStencil | ||
|  | 				); | ||
|  | 				camera.name = craw.name; | ||
|  | 				camera.setParent(iron.Scene.active.root); | ||
|  | 				// Make target bindable from render path | ||
|  | 				var rt = new RenderPath.RenderTarget(new RenderPath.RenderTargetRaw()); | ||
|  | 				rt.raw.name = raw.name; | ||
|  | 				rt.raw.is_cubemap = true; | ||
|  | 				rt.isCubeMap = true; | ||
|  | 				rt.cubeMap = camera.renderTargetCube; | ||
|  | 				RenderPath.active.renderTargets.set(rt.raw.name, rt); | ||
|  | 				ready = true; | ||
|  | 			}); | ||
|  | 		} | ||
|  | 	} | ||
|  | 
 | ||
|  | 	static function reflect(m: Mat4, n: Vec4, p: Vec4) { | ||
|  | 		var c = -p.dot(n); | ||
|  | 		m._00 = 1 - 2 * n.x * n.x; | ||
|  | 		m._10 =   - 2 * n.x * n.y; | ||
|  | 		m._20 =   - 2 * n.x * n.z; | ||
|  | 		m._30 =   - 2 * n.x * c; | ||
|  | 		m._01 =   - 2 * n.x * n.y; | ||
|  | 		m._11 = 1 - 2 * n.y * n.y; | ||
|  | 		m._21 =   - 2 * n.y * n.z; | ||
|  | 		m._31 =   - 2 * n.y * c; | ||
|  | 		m._02 =   - 2 * n.x * n.z; | ||
|  | 		m._12 =   - 2 * n.y * n.z; | ||
|  | 		m._22 = 1 - 2 * n.z * n.z; | ||
|  | 		m._32 =   - 2 * n.z * c; | ||
|  | 		m._03 = 0; | ||
|  | 		m._13 = 0; | ||
|  | 		m._23 = 0; | ||
|  | 		m._33 = 1; | ||
|  | 	} | ||
|  | 
 | ||
|  | 	static inline function sign(f: Float): Float { | ||
|  | 		return f > 0.0 ? 1.0 : f < 0.0 ? -1.0 : 0.0; | ||
|  | 	} | ||
|  | 
 | ||
|  | 	static function obliqueProjection(m: Mat4, plane: Vec4) { | ||
|  | 		// http://www.terathon.com/code/oblique.html | ||
|  | 		p.x = (sign(plane.x) + m._20) / m._00; | ||
|  | 		p.y = (sign(plane.y) + m._21) / m._11; | ||
|  | 		p.z = -1.0; | ||
|  | 		p.w = (1.0 + m._22) / m._32; | ||
|  | 		q.setFrom(plane).mult(2.0 / plane.dot(p)); | ||
|  | 		m._02 = q.x; | ||
|  | 		m._12 = q.y; | ||
|  | 		m._22 = q.z + 1.0; | ||
|  | 		m._32 = q.w; | ||
|  | 	} | ||
|  | 
 | ||
|  | 	function cullProbe(camera: CameraObject): Bool { | ||
|  | 		if (camera.data.raw.frustum_culling) { | ||
|  | 			if (!CameraObject.sphereInFrustum(camera.frustumPlanes, transform, 1.0)) { | ||
|  | 				culled = true; | ||
|  | 				return culled; | ||
|  | 			} | ||
|  | 		} | ||
|  | 		culled = false; | ||
|  | 		return culled; | ||
|  | 	} | ||
|  | 
 | ||
|  | 	public function render(g: Graphics, activeCamera: CameraObject) { | ||
|  | 		if (camera == null || !ready || !RenderPath.active.ready || !visible || cullProbe(activeCamera)) return; | ||
|  | 
 | ||
|  | 		if (data.raw.type == "planar") { | ||
|  | 			camera.V.setFrom(m1); | ||
|  | 			camera.V.multmat(activeCamera.V); | ||
|  | 			camera.V.multmat(m2); | ||
|  | 			camera.transform.local.getInverse(camera.V); | ||
|  | 			camera.transform.decompose(); | ||
|  | 			// Skip objects below the reflection plane | ||
|  | 			// v.setFrom(proben).applyproj(camera.V); | ||
|  | 			// obliqueProjection(#if (lnx_taa) camera.noJitterP #else camera.P #end, v); | ||
|  | 			camera.renderFrame(g); | ||
|  | 		} | ||
|  | 		else if (data.raw.type == "cubemap") { | ||
|  | 			if (perFrame || redraw) { | ||
|  | 				for (i in 0...6) { | ||
|  | 					camera.currentFace = i; | ||
|  | 					#if (!kha_opengl && !kha_webgl) | ||
|  | 					var flip = (i == 2 || i == 3) ? true : false; // Flip +Y, -Y | ||
|  | 					#else | ||
|  | 					var flip = false; | ||
|  | 					#end | ||
|  | 					CameraObject.setCubeFace(camera.V, probep, i, flip); | ||
|  | 					camera.transform.local.getInverse(camera.V); | ||
|  | 					camera.transform.decompose(); | ||
|  | 					camera.renderFrame(g); | ||
|  | 				} | ||
|  | 			} | ||
|  | 		} | ||
|  | 
 | ||
|  | 		redraw = false; | ||
|  | 	} | ||
|  | 
 | ||
|  | #end | ||
|  | } |