Преглед изворни кода

- Volumetric Lightmaps refacto

ShiroSmith пре 7 година
родитељ
комит
c2bd803eb6
3 измењених фајлова са 77 додато и 127 уклоњено
  1. 0 11
      h3d/scene/pbr/LightProbe.hx
  2. 26 44
      h3d/scene/pbr/LightProbeBaker.hx
  3. 51 72
      h3d/scene/pbr/VolumetricLightmap.hx

+ 0 - 11
h3d/scene/pbr/LightProbe.hx

@@ -1,11 +0,0 @@
-package h3d.scene.pbr;
-
-class LightProbe {
-
-	public var position = new h3d.Vector(0,0,0);
-	public var sh : h3d.scene.pbr.SphericalHarmonic;
-
-	public function new() {
-	}
-
-}

+ 26 - 44
h3d/scene/pbr/LightProbeBaker.hx

@@ -32,13 +32,13 @@ class LightProbeBaker {
 	public function new(){
 	}
 
-	public function bakePartial(renderer : h3d.scene.Renderer, s3d : Scene, volumetricLightMap : VolumetricLightmap, resolution : Int, time :Float) {
+	public function bake(renderer : h3d.scene.Renderer, s3d : Scene, volumetricLightMap : VolumetricLightmap, resolution : Int, ?time :Float) {
 
 		var timer = haxe.Timer.stamp();
 		var timeElapsed = 0.0;
 
 		var index = volumetricLightMap.lastBakedProbeIndex + 1;
-		if(index > volumetricLightMap.lightProbes.length - 1) return time;
+		if(index > volumetricLightMap.getProbeCount() - 1) return time;
 
 		setupEnvMap(resolution);
 		setupShaderOutput(volumetricLightMap.shOrder);
@@ -52,71 +52,53 @@ class LightProbeBaker {
 		s3d.camera = customCamera;
 		var engine = h3d.Engine.getCurrent();
 
-		while(timeElapsed < time){
+		var coefCount = volumetricLightMap.getCoefCount();
+		var sizeX = volumetricLightMap.probeCount.x * coefCount;
+		var sizeY = volumetricLightMap.probeCount.y * volumetricLightMap.probeCount.z;
+		if(volumetricLightMap.lightProbeTexture == null || volumetricLightMap.lightProbeTexture.width != sizeX || volumetricLightMap.lightProbeTexture.height != sizeY){
+			if( volumetricLightMap.lightProbeTexture != null ) volumetricLightMap.lightProbeTexture.dispose();
+			volumetricLightMap.lightProbeTexture = new h3d.mat.Texture(sizeX, sizeY, [Dynamic], RGBA32F);
+			volumetricLightMap.lightProbeTexture.filter = Nearest;
+		}
+
+		var pixels : hxd.Pixels.PixelsFloat = volumetricLightMap.lightProbeTexture.capturePixels();
+
+		while( (time != null && timeElapsed < time) || time == null){
+			var coords = volumetricLightMap.getProbeCoords(index);
 
 			// Bake a Probe
 			for( f in 0...6 ) {
 				engine.begin();
-				customCamera.setCubeMap(f, volumetricLightMap.lightProbes[index].position);
+				customCamera.setCubeMap(f, volumetricLightMap.getProbePosition(coords));
 				customCamera.update();
 				engine.pushTarget(envMap, f);
 				engine.clear(0,1,0);
 				s3d.render(engine);
 				engine.popTarget();
 			}
-			volumetricLightMap.lightProbes[index].sh = useGPU ? convertEnvIntoSH_GPU(renderer, envMap, volumetricLightMap.shOrder) : convertEnvIntoSH_CPU(envMap, volumetricLightMap.shOrder);
 			volumetricLightMap.lastBakedProbeIndex = index;
 
+			var sh : SphericalHarmonic = useGPU ? convertEnvIntoSH_GPU(renderer, envMap, volumetricLightMap.shOrder) : convertEnvIntoSH_CPU(envMap, volumetricLightMap.shOrder);
+			for(coef in 0... coefCount){
+				var u = coords.x + volumetricLightMap.probeCount.x * coef;
+				var v = coords.y + coords.z * volumetricLightMap.probeCount.y;
+				pixels.setPixelF(u, v, new h3d.Vector(sh.coefR[coef], sh.coefG[coef], sh.coefB[coef], 0));
+			}
+
 			index = volumetricLightMap.lastBakedProbeIndex + 1;
-			if(index > volumetricLightMap.lightProbes.length - 1) break;
+			if(index > volumetricLightMap.getProbeCount() - 1) break;
 
 			timeElapsed = haxe.Timer.stamp() - timer;
 		}
 
-		// Restore Scene Config
-		s3d.camera = oldCamera;
-		s3d.renderer = oldRenderer;
-		s3d.renderer.renderMode = oldRenderMode;
-
-
-		return time - timeElapsed;
-	}
-
-
-	public function bake(renderer : h3d.scene.Renderer, s3d : Scene, volumetricLightMap : VolumetricLightmap, resolution : Int) {
-
-		setupEnvMap(resolution);
-		setupShaderOutput(volumetricLightMap.shOrder);
-
-		// Save Scene Config
-		var oldRenderer = s3d.renderer;
-		var oldCamera = s3d.camera;
-		var oldRenderMode = renderer.renderMode;
-		s3d.renderer = renderer;
-		s3d.renderer.renderMode = LightProbe;
-		s3d.camera = customCamera;
-		var engine = h3d.Engine.getCurrent();
-
-		for( i in 0 ... volumetricLightMap.lightProbes.length){
-			// Render the 6 faces
-			for( f in 0...6 ) {
-				engine.begin();
-				customCamera.setCubeMap(f, volumetricLightMap.lightProbes[i].position);
-				customCamera.update();
-				engine.pushTarget(envMap, f);
-				engine.clear(0,1,0);
-				s3d.render(engine);
-				engine.popTarget();
-			}
-			volumetricLightMap.lightProbes[i].sh = useGPU ? convertEnvIntoSH_GPU(renderer, envMap, volumetricLightMap.shOrder) : convertEnvIntoSH_CPU(envMap, volumetricLightMap.shOrder);
-			volumetricLightMap.lastBakedProbeIndex = i;
-		}
+		volumetricLightMap.lightProbeTexture.uploadPixels(pixels, 0, 0);
 
 		// Restore Scene Config
 		s3d.camera = oldCamera;
 		s3d.renderer = oldRenderer;
 		s3d.renderer.renderMode = oldRenderMode;
 
+		return time - timeElapsed;
 	}
 
 	function setupEnvMap(resolution : Int){

+ 51 - 72
h3d/scene/pbr/VolumetricLightmap.hx

@@ -2,7 +2,6 @@ package h3d.scene.pbr;
 
 class VolumetricLightmap extends h3d.scene.Mesh {
 
-	public var lightProbes:Array<LightProbe> = [];
 	public var lightProbeTexture : h3d.mat.Texture;
 	public var shOrder : Int = 1;
 	public var voxelSize (default, set) : h3d.Vector;
@@ -27,12 +26,53 @@ class VolumetricLightmap extends h3d.scene.Mesh {
 		material.castShadows = false;
 		material.shadows = false;
 		material.mainPass.stencil = new h3d.mat.Stencil();
-		material.mainPass.stencil.setFunc(Equal, 0, 0xFF, 0xFF);
-		material.mainPass.stencil.setOp(Keep, Keep, Increment);
+		material.mainPass.stencil.setFunc(NotEqual, 0x80, 0x80, 0x80);
+		material.mainPass.stencil.setOp(Keep, Keep, Replace);
 		probeCount = new h3d.col.IPoint();
 		voxelSize = new h3d.Vector(1,1,1);
 	}
 
+	public function getProbeSH(coords : h3d.col.IPoint, ?pixels : hxd.Pixels.PixelsFloat ) : SphericalHarmonic {
+
+		if(lightProbeTexture == null)
+			return new SphericalHarmonic(shOrder);
+
+		if(pixels == null)
+			pixels = lightProbeTexture.capturePixels();
+
+		var sh = new SphericalHarmonic(shOrder);
+
+		var coefCount = getCoefCount();
+		for(c in 0...coefCount){
+			var u = coords.x + probeCount.x * c;
+			var v = coords.y + coords.z * probeCount.y;
+			var color = pixels.getPixelF(u, v);
+			sh.coefR[c] = color.r;
+			sh.coefG[c] = color.g;
+			sh.coefB[c] = color.b;
+		}
+
+		return sh;
+	}
+
+	public function getCoefCount() : Int{
+		return shOrder * shOrder;
+	}
+
+	public function getProbePosition(coords : h3d.col.IPoint){
+		var probePos : h3d.Vector = new h3d.Vector( coords.x/(probeCount.x - 1),  coords.y/(probeCount.y - 1), coords.z/(probeCount.z - 1));
+		localToGlobal(probePos);
+		return probePos;
+	}
+
+	public function getProbeCoords(i : Int) : h3d.col.IPoint {
+		var coords = new h3d.col.IPoint();
+		coords.z = Std.int(i / (probeCount.x * probeCount.y));
+		coords.y = Std.int((i - coords.z * probeCount.y * probeCount.x) / (probeCount.x));
+		coords.x = Std.int((i - coords.z * probeCount.y * probeCount.x - coords.y * probeCount.x));
+		return coords;
+	}
+
 	public function getProbeCount() {
 		return probeCount.x * probeCount.y * probeCount.z;
 	}
@@ -58,11 +98,14 @@ class VolumetricLightmap extends h3d.scene.Mesh {
 	}
 
 	public function load( bytes : haxe.io.Bytes ) {
+		return true;
 		bytes = haxe.zip.Uncompress.run(bytes);
 		var count = getProbeCount();
 		if( bytes.length != count * shOrder * shOrder * 4 * 4 )
 			return false;
 		lastBakedProbeIndex = count;
+		lightProbeTexture = new h3d.mat.Texture(probeCount.x * shOrder * shOrder, probeCount.y * probeCount.z, [Dynamic], RGBA32F);
+		lightProbeTexture.filter = Nearest;
 		lightProbeTexture.uploadPixels(new hxd.Pixels(lightProbeTexture.width, lightProbeTexture.height, bytes, RGBA32F));
 		return true;
 	}
@@ -76,9 +119,13 @@ class VolumetricLightmap extends h3d.scene.Mesh {
 		return haxe.zip.Compress.run(data,9);
 	}
 
+	override function emit(ctx:RenderContext){
+		if(lightProbeTexture != null) ctx.emit(this.material, this);
+	}
+
 	override function sync(ctx:RenderContext) {
 		shader.ORDER = shOrder;
-		shader.SIZE = lightProbes.length * shader.ORDER * shader.ORDER;
+		shader.SIZE = getProbeCount() * shader.ORDER * shader.ORDER;
 		shader.lightmapInvPos.load(getInvPos());
 		shader.lightmapSize.load(new h3d.Vector(probeCount.x, probeCount.y, probeCount.z));
 		shader.voxelSize.load(new h3d.Vector(scaleX/(probeCount.x - 1), scaleY/(probeCount.y - 1), scaleZ/(probeCount.z - 1)));
@@ -88,39 +135,6 @@ class VolumetricLightmap extends h3d.scene.Mesh {
 		shader.strength = strength;
 	}
 
-	public function generateProbes() {
-		var totalProbeCount : Int = probeCount.x * probeCount.y * probeCount.z ;
-		lightProbes = [];
-		lastBakedProbeIndex = -1;
-
-		for(i in 0 ... probeCount.x){
-			for(j in 0 ... probeCount.y){
-				for(k in 0 ... probeCount.z){
-					var index : Int = i + j * probeCount.x + k * probeCount.x * probeCount.y;
-					var probePos : h3d.Vector = new h3d.Vector( i/(probeCount.x - 1),  j/(probeCount.y - 1), k/(probeCount.z - 1));
-					localToGlobal(probePos);
-
-					if(useAlignedProb){
-						var overlappedLightmaps : Array<VolumetricLightmap> = [];
-						// Check if a probe is inside an other lightmap
-						/*for(i in 0 ... volumetricLightmaps.length){
-							if(volumetricLightmaps[i] != this && volumetricLightmaps[i].isInsideVolume(probePos)){
-								overlappedLightmaps.push(volumetricLightmaps[i]);
-							}
-						}*/
-						if(overlappedLightmaps.length > 0){
-							var alignment = getWorldAlignment(overlappedLightmaps);
-							probePos.set(probePos.x - probePos.x % alignment.x, probePos.y - probePos.y % alignment.y, probePos.z - probePos.z % alignment.z);
-						}
-					}
-
-					lightProbes[index] = new h3d.scene.pbr.LightProbe();
-					lightProbes[index].position.set(probePos.x, probePos.y, probePos.z);
-				}
-			}
-		}
-	}
-
 	public function getWorldAlignment(lightmaps : Array<VolumetricLightmap>) : h3d.Vector {
 		var result =  new h3d.Vector(scaleX/(probeCount.x - 1), scaleY/(probeCount.y - 1), scaleZ/(probeCount.z - 1));
 		for(i in 0...lightmaps.length){
@@ -136,39 +150,4 @@ class VolumetricLightmap extends h3d.scene.Mesh {
 		globalToLocal(localPos);
 		return (localPos.x >= 0 && localPos.y >= 0 && localPos.z >= 0 && localPos.x <= 1 && localPos.y <= 1 && localPos.z <= 1);
 	}
-
-	// Pack data inside a 2D texture
-	public function packDataInsideTexture(){
-		var coefCount : Int = shOrder * shOrder;
-		var sizeX = probeCount.x * coefCount;
-		var sizeY = probeCount.y * probeCount.z;
-
-		if(lightProbeTexture == null || lightProbeTexture.width != sizeX || lightProbeTexture.height != sizeY){
-			if( lightProbeTexture != null ) lightProbeTexture.dispose();
-			lightProbeTexture = new h3d.mat.Texture(sizeX, sizeY, [Dynamic], RGBA32F);
-			lightProbeTexture.filter = Nearest;
-		}
-		var pixels : hxd.Pixels.PixelsFloat = hxd.Pixels.alloc(sizeX, sizeY, RGBA32F);
-
-		for(k in 0 ... probeCount.z){
-			for(j in 0 ... probeCount.y){
-				for(i in 0 ... probeCount.x){
-					var probeIndex : Int = i + j * probeCount.x + k * probeCount.x * probeCount.y;
-					if(probeIndex > lastBakedProbeIndex) {
-						lightProbeTexture.uploadPixels(pixels,0,0);
-						return;
-					}
-					for(coef in 0... coefCount){
-						var u = i + probeCount.x * coef;
-						var v = j + k * probeCount.y;
-						var sh = lightProbes[probeIndex].sh;
-						var	color = new h3d.Vector(lightProbes[probeIndex].sh.coefR[coef], lightProbes[probeIndex].sh.coefG[coef], lightProbes[probeIndex].sh.coefB[coef], 0);
-						pixels.setPixelF(u, v, color);
-					}
-				}
-			}
-		}
-
-		lightProbeTexture.uploadPixels(pixels,0,0);
-	}
 }