Selaa lähdekoodia

Merge branch 'master' of https://github.com/HeapsIO/hide

Tom SPIRA 6 vuotta sitten
vanhempi
commit
ab7e4e0a85

+ 1 - 0
bin/app.html

@@ -54,6 +54,7 @@
 			</div>
 			</div>
 		</menu>
 		</menu>
 		<separator></separator>
 		<separator></separator>
+		<menu label="Clear profile" class="clear-local"></menu>
 		<menu label="Exit" class="exit"></menu>
 		<menu label="Exit" class="exit"></menu>
 	</menu>
 	</menu>
 	<menu label="View" class="view">
 	<menu label="View" class="view">

+ 2 - 1
bin/style.css

@@ -220,7 +220,7 @@ input[type=checkbox]:checked:after {
   padding-right: 5px;
   padding-right: 5px;
 }
 }
 .hide-scenetree {
 .hide-scenetree {
-  height: 100%;
+  flex: 1;
   background-color: #111;
   background-color: #111;
   border: 1px solid #444;
   border: 1px solid #444;
   width: 300px;
   width: 300px;
@@ -700,6 +700,7 @@ input[type=checkbox]:checked:after {
 }
 }
 .fx-animpanel .anim-scroll {
 .fx-animpanel .anim-scroll {
   overflow-y: scroll;
   overflow-y: scroll;
+  overflow-x: hidden;
   height: 400px;
   height: 400px;
 }
 }
 .fx-animpanel .top-bar {
 .fx-animpanel .top-bar {

+ 2 - 1
bin/style.less

@@ -234,7 +234,7 @@ input[type=checkbox] {
 }
 }
 
 
 .hide-scenetree {
 .hide-scenetree {
-	height: 100%;
+	flex: 1;
 	background-color : #111;
 	background-color : #111;
 	border : 1px solid #444;
 	border : 1px solid #444;
 	width: 300px;
 	width: 300px;
@@ -773,6 +773,7 @@ input[type=checkbox] {
 
 
 	.anim-scroll {
 	.anim-scroll {
 		overflow-y: scroll;
 		overflow-y: scroll;
+		overflow-x: hidden;
 		height: 400px;
 		height: 400px;
 	}
 	}
 	.top-bar {
 	.top-bar {

+ 6 - 0
hide/Ide.hx

@@ -735,6 +735,12 @@ class Ide {
 		menu.find(".project .exit").click(function(_) {
 		menu.find(".project .exit").click(function(_) {
 			Sys.exit(0);
 			Sys.exit(0);
 		});
 		});
+		menu.find(".project .clear-local").click(function(_) {
+			js.Browser.window.localStorage.clear();
+			nw.App.clearCache();
+			try sys.FileSystem.deleteFile(Ide.inst.appPath + "/props.json") catch( e : Dynamic ) {};
+			untyped chrome.runtime.reload();
+		});
 
 
 		for( r in renderers ) {
 		for( r in renderers ) {
 			new Element("<menu type='checkbox'>").attr("label", r.name).prop("checked",r == h3d.mat.MaterialSetup.current).appendTo(menu.find(".project .renderers")).click(function(_) {
 			new Element("<menu type='checkbox'>").attr("label", r.name).prop("checked",r == h3d.mat.MaterialSetup.current).appendTo(menu.find(".project .renderers")).click(function(_) {

+ 14 - 2
hide/comp/SceneEditor.hx

@@ -241,7 +241,20 @@ class SceneEditor {
 
 
 	function focusSelection() {
 	function focusSelection() {
 		if(curEdit.rootObjects.length > 0) {
 		if(curEdit.rootObjects.length > 0) {
-			cameraController.set(curEdit.rootObjects[0].getAbsPos().getPosition().toPoint());
+			var bnds = new h3d.col.Bounds();
+			var centroid = new h3d.Vector();
+			for(obj in curEdit.rootObjects) {
+				centroid = centroid.add(obj.getAbsPos().getPosition());
+				bnds.add(obj.getBounds());
+			}
+			if(!bnds.isEmpty()) {
+				var s = bnds.toSphere();
+				cameraController.set(s.r * 4.0, null, null, s.getCenter());
+			}
+			else {
+				centroid.scale3(1.0 / curEdit.rootObjects.length);
+				cameraController.set(centroid.toPoint());
+			}
 		}
 		}
 		for(obj in curEdit.rootElements)
 		for(obj in curEdit.rootElements)
 			tree.revealNode(obj);
 			tree.revealNode(obj);
@@ -1551,7 +1564,6 @@ class SceneEditor {
 	}
 	}
 
 
 	function update(dt:Float) {
 	function update(dt:Float) {
-		trace(K.isDown(K.CTRL));
 		var cam = scene.s3d.camera;
 		var cam = scene.s3d.camera;
 		@:privateAccess view.saveDisplayState("Camera", { x : cam.pos.x, y : cam.pos.y, z : cam.pos.z, tx : cam.target.x, ty : cam.target.y, tz : cam.target.z });
 		@:privateAccess view.saveDisplayState("Camera", { x : cam.pos.x, y : cam.pos.y, z : cam.pos.z, tx : cam.target.x, ty : cam.target.y, tz : cam.target.z });
 		if(gizmo != null) {
 		if(gizmo != null) {

+ 4 - 4
hide/prefab/terrain/TerrainEditor.hx

@@ -584,8 +584,8 @@ class TerrainEditor {
 		}
 		}
 
 
 		currentBrush.bitmap.color = new h3d.Vector(1.0);
 		currentBrush.bitmap.color = new h3d.Vector(1.0);
-		var shader : h3d.shader.pbr.Brush = currentBrush.bitmap.getShader(h3d.shader.pbr.Brush);
-		if( shader == null ) shader = currentBrush.bitmap.addShader(new h3d.shader.pbr.Brush());
+		var shader : hrt.shader.Brush = currentBrush.bitmap.getShader(hrt.shader.Brush);
+		if( shader == null ) shader = currentBrush.bitmap.addShader(new hrt.shader.Brush());
 		currentBrush.bitmap.blendMode = currentBrush.brushMode.accumulate ? Add : Max;
 		currentBrush.bitmap.blendMode = currentBrush.brushMode.accumulate ? Add : Max;
 		shader.strength = currentBrush.strength;
 		shader.strength = currentBrush.strength;
 		shader.size = currentBrush.size / terrainPrefab.tileSize;
 		shader.size = currentBrush.size / terrainPrefab.tileSize;
@@ -618,8 +618,8 @@ class TerrainEditor {
 			brushWorldPos = getBrushWorldPosFromTex(pos, ctx);
 			brushWorldPos = getBrushWorldPosFromTex(pos, ctx);
 		}
 		}
 
 
-		var shader : h3d.shader.pbr.Brush = currentBrush.bitmap.getShader(h3d.shader.pbr.Brush);
-		if( shader == null ) shader = currentBrush.bitmap.addShader(new h3d.shader.pbr.Brush());
+		var shader : hrt.shader.Brush = currentBrush.bitmap.getShader(hrt.shader.Brush);
+		if( shader == null ) shader = currentBrush.bitmap.addShader(new hrt.shader.Brush());
 		currentBrush.bitmap.color = new h3d.Vector(1.0);
 		currentBrush.bitmap.color = new h3d.Vector(1.0);
 		shader.size = currentBrush.size / terrainPrefab.tileSize;
 		shader.size = currentBrush.size / terrainPrefab.tileSize;
 
 

+ 1 - 1
hide/view/FXEditor.hx

@@ -213,7 +213,7 @@ class FXEditor extends FileView {
 							<label>Favorites</label>
 							<label>Favorites</label>
 							<div class="favorites-tree"></div>
 							<div class="favorites-tree"></div>
 						</div>
 						</div>
-						<div style="height:80%;">
+						<div style="height:80%;" class="flex vertical">
 							<div class="hide-toolbar" style="zoom: 80%">
 							<div class="hide-toolbar" style="zoom: 80%">
 								<div class="button collapse-btn" title="Collapse all">
 								<div class="button collapse-btn" title="Collapse all">
 									<div class="icon fa fa-reply-all"></div>
 									<div class="icon fa fa-reply-all"></div>

+ 2 - 2
hide/view/l3d/Level3D.hx

@@ -331,7 +331,7 @@ class Level3D extends FileView {
 							<label>Favorites</label>
 							<label>Favorites</label>
 							<div class="favorites-tree"></div>
 							<div class="favorites-tree"></div>
 						</div>
 						</div>
-						<div style="height:80%;">
+						<div style="height:80%;" class="flex vertical">
 							<div class="hide-toolbar" style="zoom: 80%">
 							<div class="hide-toolbar" style="zoom: 80%">
 								<div class="button collapse-btn" title="Collapse all">
 								<div class="button collapse-btn" title="Collapse all">
 									<div class="icon fa fa-reply-all"></div>
 									<div class="icon fa fa-reply-all"></div>
@@ -466,7 +466,7 @@ class Level3D extends FileView {
 	}
 	}
 
 
 	function bakeVolumetricLightmaps(){
 	function bakeVolumetricLightmaps(){
-		var volumetricLightmaps = data.getAll(hrt.prefab.l3d.VolumetricLightmap);
+		var volumetricLightmaps = data.getAll(hrt.prefab.vlm.VolumetricLightmap);
 		var total = 0;
 		var total = 0;
 		for( v in volumetricLightmaps )
 		for( v in volumetricLightmaps )
 			total += v.volumetricLightmap.getProbeCount();
 			total += v.volumetricLightmap.getProbeCount();

+ 10 - 10
hide/view/l3d/LightProbeBaker.hx

@@ -22,7 +22,7 @@ class LightProbeBaker {
 
 
 	function getSwiz(name,comp) : hxsl.Output { return Swiz(Value(name,3),[comp]); }
 	function getSwiz(name,comp) : hxsl.Output { return Swiz(Value(name,3),[comp]); }
 
 
-	var computeSH : h3d.pass.ScreenFx<h3d.shader.pbr.ComputeSH>;
+	var computeSH : h3d.pass.ScreenFx<hrt.shader.ComputeSH>;
 	var output0 : h3d.mat.Texture;
 	var output0 : h3d.mat.Texture;
 	var output1 : h3d.mat.Texture;
 	var output1 : h3d.mat.Texture;
 	var output2 : h3d.mat.Texture;
 	var output2 : h3d.mat.Texture;
@@ -150,7 +150,7 @@ class LightProbeBaker {
 	}
 	}
 
 
 	var pixels : hxd.Pixels.PixelsFloat = null;
 	var pixels : hxd.Pixels.PixelsFloat = null;
-	public function bake( volumetricLightMap : h3d.scene.pbr.VolumetricLightmap, resolution : Int, ?time :Float ) {
+	public function bake( volumetricLightMap : hrt.prefab.vlm.VolumetricMesh, resolution : Int, ?time :Float ) {
 
 
 		var timer = haxe.Timer.stamp();
 		var timer = haxe.Timer.stamp();
 		var timeElapsed = 0.0;
 		var timeElapsed = 0.0;
@@ -198,7 +198,7 @@ class LightProbeBaker {
 			}
 			}
 			else {
 			else {
 				var pbrRenderer = Std.instance(offScreenScene.renderer, h3d.scene.pbr.Renderer);
 				var pbrRenderer = Std.instance(offScreenScene.renderer, h3d.scene.pbr.Renderer);
-				var sh : h3d.scene.pbr.SphericalHarmonic = convertEnvIntoSH_CPU(envMap, volumetricLightMap.shOrder);
+				var sh : hrt.prefab.vlm.SphericalHarmonic = convertEnvIntoSH_CPU(envMap, volumetricLightMap.shOrder);
 				for( coef in 0 ... coefCount ) {
 				for( coef in 0 ... coefCount ) {
 					var u = coords.x + volumetricLightMap.probeCount.x * coef;
 					var u = coords.x + volumetricLightMap.probeCount.x * coef;
 					var v = coords.y + coords.z * volumetricLightMap.probeCount.y;
 					var v = coords.y + coords.z * volumetricLightMap.probeCount.y;
@@ -259,11 +259,11 @@ class LightProbeBaker {
 		switch(order){
 		switch(order){
 			case 1:
 			case 1:
 				textureArray = [output0];
 				textureArray = [output0];
-				computeSH = new h3d.pass.ScreenFx(new h3d.shader.pbr.ComputeSH(),[
+				computeSH = new h3d.pass.ScreenFx(new hrt.shader.ComputeSH(),[
 								Vec4([Value("out.coefL00", 3), Const(0)])]);
 								Vec4([Value("out.coefL00", 3), Const(0)])]);
 			case 2:
 			case 2:
 				textureArray = [output0, output1, output2, output3];
 				textureArray = [output0, output1, output2, output3];
-				computeSH = new h3d.pass.ScreenFx(new h3d.shader.pbr.ComputeSH(),[
+				computeSH = new h3d.pass.ScreenFx(new hrt.shader.ComputeSH(),[
 							Vec4([Value("out.coefL00", 3), Const(0)]),
 							Vec4([Value("out.coefL00", 3), Const(0)]),
 							Vec4([Value("out.coefL1n1", 3), Const(0)]),
 							Vec4([Value("out.coefL1n1", 3), Const(0)]),
 							Vec4([Value("out.coefL10", 3), Const(0)]),
 							Vec4([Value("out.coefL10", 3), Const(0)]),
@@ -271,7 +271,7 @@ class LightProbeBaker {
 
 
 			case 3:
 			case 3:
 				textureArray = [output0, output1, output2, output3, output4, output5, output6, output7];
 				textureArray = [output0, output1, output2, output3, output4, output5, output6, output7];
-				computeSH = new h3d.pass.ScreenFx(new h3d.shader.pbr.ComputeSH(),[
+				computeSH = new h3d.pass.ScreenFx(new hrt.shader.ComputeSH(),[
 							Vec4([Value("out.coefL00", 3), getSwiz("out.coefL22",X) ]),
 							Vec4([Value("out.coefL00", 3), getSwiz("out.coefL22",X) ]),
 							Vec4([Value("out.coefL1n1", 3), getSwiz("out.coefL22",Y) ]),
 							Vec4([Value("out.coefL1n1", 3), getSwiz("out.coefL22",Y) ]),
 							Vec4([Value("out.coefL10", 3), getSwiz("out.coefL22",Z) ]),
 							Vec4([Value("out.coefL10", 3), getSwiz("out.coefL22",Z) ]),
@@ -313,10 +313,10 @@ class LightProbeBaker {
 		@:privateAccess renderer.ctx.engine.flushTarget();
 		@:privateAccess renderer.ctx.engine.flushTarget();
 	}
 	}
 
 
-	function convertOuputTexturesIntoSH( volumetricLightMap : h3d.scene.pbr.VolumetricLightmap, pixelsOut : hxd.Pixels.PixelsFloat ) {
+	function convertOuputTexturesIntoSH( volumetricLightMap : hrt.prefab.vlm.VolumetricMesh, pixelsOut : hxd.Pixels.PixelsFloat ) {
 
 
 		var order = volumetricLightMap.shOrder;
 		var order = volumetricLightMap.shOrder;
-		var sh = new h3d.scene.pbr.SphericalHarmonic(order);
+		var sh = new hrt.prefab.vlm.SphericalHarmonic(order);
 		var coefCount = order * order;
 		var coefCount = order * order;
 		var maxCoef : Int = Std.int(Math.min(8, coefCount));
 		var maxCoef : Int = Std.int(Math.min(8, coefCount));
 
 
@@ -343,9 +343,9 @@ class LightProbeBaker {
 		}
 		}
 	}
 	}
 
 
-	function convertEnvIntoSH_CPU( env : h3d.mat.Texture, order : Int ) : h3d.scene.pbr.SphericalHarmonic {
+	function convertEnvIntoSH_CPU( env : h3d.mat.Texture, order : Int ) : hrt.prefab.vlm.SphericalHarmonic {
 		var coefCount = order * order;
 		var coefCount = order * order;
-		var sphericalHarmonic = new h3d.scene.pbr.SphericalHarmonic(order);
+		var sphericalHarmonic = new hrt.prefab.vlm.SphericalHarmonic(order);
 		var face : hxd.Pixels.PixelsFloat;
 		var face : hxd.Pixels.PixelsFloat;
 		var weightSum = 0.0;
 		var weightSum = 0.0;
 		var invWidth = 1.0 / env.width;
 		var invWidth = 1.0 / env.width;

+ 1 - 1
hide/view/l3d/ProbeBakerProcess.hx

@@ -5,7 +5,7 @@ class ProbeBakerProcess {
 	public var progress : Float = 0.;
 	public var progress : Float = 0.;
 
 
 	var lightProbeBaker : hide.view.l3d.LightProbeBaker;
 	var lightProbeBaker : hide.view.l3d.LightProbeBaker;
-	var volumetricLightmap : hrt.prefab.l3d.VolumetricLightmap;
+	var volumetricLightmap : hrt.prefab.vlm.VolumetricLightmap;
 	var bakeTime : Float;
 	var bakeTime : Float;
 	var resolution : Int;
 	var resolution : Int;
 
 

+ 1 - 1
hrt/prefab/rfx/Bloom.hx

@@ -12,7 +12,7 @@ typedef BloomProps = {
 
 
 class Bloom extends RendererFX {
 class Bloom extends RendererFX {
 
 
-	var bloomPass = new h3d.pass.ScreenFx(new h3d.shader.pbr.Bloom());
+	var bloomPass = new h3d.pass.ScreenFx(new hrt.shader.Bloom());
 	var bloomBlur = new h3d.pass.Blur();
 	var bloomBlur = new h3d.pass.Blur();
 
 
 	public function new(?parent) {
 	public function new(?parent) {

+ 1 - 1
hrt/prefab/rfx/DistanceFog.hx

@@ -14,7 +14,7 @@ typedef DistanceFogProps = {
 
 
 class DistanceFog extends RendererFX {
 class DistanceFog extends RendererFX {
 
 
-	var fogPass = new h3d.pass.ScreenFx(new h3d.shader.DistanceFog());
+	var fogPass = new h3d.pass.ScreenFx(new hrt.shader.DistanceFog());
 
 
 	public function new(?parent) {
 	public function new(?parent) {
 		super(parent);
 		super(parent);

+ 2 - 2
hrt/prefab/terrain/Tile.hx

@@ -17,13 +17,13 @@ class Tile extends h3d.scene.Mesh {
 	public var needNewPixelCapture = false;
 	public var needNewPixelCapture = false;
 	public var insideFrustrum = false;
 	public var insideFrustrum = false;
 	var heightmapPixels : hxd.Pixels.PixelsFloat;
 	var heightmapPixels : hxd.Pixels.PixelsFloat;
-	var shader : Shader;
+	var shader : hrt.shader.Terrain;
 
 
 	public function new( x : Int, y : Int , ?parent ) {
 	public function new( x : Int, y : Int , ?parent ) {
 		super(null, null, parent);
 		super(null, null, parent);
 		this.tileX = x;
 		this.tileX = x;
 		this.tileY = y;
 		this.tileY = y;
-		shader = new Shader();
+		shader = new hrt.shader.Terrain();
 		material.mainPass.addShader(shader);
 		material.mainPass.addShader(shader);
 		material.mainPass.culling = None;
 		material.mainPass.culling = None;
 		material.shadows = false;
 		material.shadows = false;

+ 15 - 0
hrt/prefab/vlm/SphericalHarmonic.hx

@@ -0,0 +1,15 @@
+package hrt.prefab.vlm;
+
+class SphericalHarmonic {
+
+	public var coefR : Array<Float> = [];
+	public var coefG : Array<Float> = [];
+	public var coefB : Array<Float> = [];
+
+	public function new(order:Int) {
+		var coefCount = order * order;
+		coefR = [for (value in 0...coefCount) 0];
+		coefG = [for (value in 0...coefCount) 0];
+		coefB = [for (value in 0...coefCount) 0];
+	}
+}

+ 5 - 5
hrt/prefab/l3d/VolumetricLightmap.hx → hrt/prefab/vlm/VolumetricLightmap.hx

@@ -1,4 +1,4 @@
-package hrt.prefab.l3d;
+package hrt.prefab.vlm;
 
 
 class VolumetricLightmap extends Object3D {
 class VolumetricLightmap extends Object3D {
 
 
@@ -9,7 +9,7 @@ class VolumetricLightmap extends Object3D {
 	var order : Int = 1;
 	var order : Int = 1;
 	var displaySH_field = false;
 	var displaySH_field = false;
 
 
-	public var volumetricLightmap : h3d.scene.pbr.VolumetricLightmap;
+	public var volumetricLightmap : VolumetricMesh;
 	var useWorldAlignedProbe = false;
 	var useWorldAlignedProbe = false;
 	var displaySH = false;
 	var displaySH = false;
 	var resolution : Int = 16;
 	var resolution : Int = 16;
@@ -133,7 +133,7 @@ class VolumetricLightmap extends Object3D {
 			var probePos = volumetricLightmap.getProbePosition(volumetricLightmap.getProbeCoords(i));
 			var probePos = volumetricLightmap.getProbePosition(volumetricLightmap.getProbeCoords(i));
 			volumetricLightmap.globalToLocal(probePos);
 			volumetricLightmap.globalToLocal(probePos);
 			previewSphere.setPosition(probePos.x, probePos.y, probePos.z);
 			previewSphere.setPosition(probePos.x, probePos.y, probePos.z);
-			var shader = new h3d.shader.pbr.SHDisplay();
+			var shader = new hrt.shader.DisplaySH();
 			shader.order = volumetricLightmap.shOrder;
 			shader.order = volumetricLightmap.shOrder;
 			shader.strength = volumetricLightmap.strength;
 			shader.strength = volumetricLightmap.strength;
 			var coefCount = volumetricLightmap.getCoefCount();
 			var coefCount = volumetricLightmap.getCoefCount();
@@ -157,7 +157,7 @@ class VolumetricLightmap extends Object3D {
 			var previewSpheres = volumetricLightmap.findAll(c -> if(c.name == "_previewSphere") c else null);
 			var previewSpheres = volumetricLightmap.findAll(c -> if(c.name == "_previewSphere") c else null);
 			for(ps in previewSpheres){
 			for(ps in previewSpheres){
 				var mesh = Std.instance(ps, h3d.scene.Mesh);
 				var mesh = Std.instance(ps, h3d.scene.Mesh);
-				var shader = mesh.material.mainPass.getShader(h3d.shader.pbr.SHDisplay);
+				var shader = mesh.material.mainPass.getShader(hrt.shader.DisplaySH);
 				if(shader != null) shader.strength = volumetricLightmap.strength;
 				if(shader != null) shader.strength = volumetricLightmap.strength;
 			}
 			}
 		}
 		}
@@ -169,7 +169,7 @@ class VolumetricLightmap extends Object3D {
 
 
 		ctx = ctx.clone(this);
 		ctx = ctx.clone(this);
 		var obj = new h3d.scene.Object(ctx.local3d);
 		var obj = new h3d.scene.Object(ctx.local3d);
-		volumetricLightmap = new h3d.scene.pbr.VolumetricLightmap(obj);
+		volumetricLightmap = new hrt.prefab.vlm.VolumetricMesh(obj);
 		volumetricLightmap.ignoreCollide = true;
 		volumetricLightmap.ignoreCollide = true;
 		volumetricLightmap.setPosition(-0.5, -0.5, 0);
 		volumetricLightmap.setPosition(-0.5, -0.5, 0);
 		ctx.local3d = obj;
 		ctx.local3d = obj;

+ 176 - 0
hrt/prefab/vlm/VolumetricMesh.hx

@@ -0,0 +1,176 @@
+package hrt.prefab.vlm;
+
+class VolumetricMesh extends h3d.scene.Mesh {
+
+	public var lightProbeTexture : h3d.mat.Texture;
+	public var shOrder : Int = 1;
+	public var voxelSize (default, set) : h3d.Vector;
+	public var probeCount : h3d.col.IPoint;
+	public var useAlignedProb : Bool = false;
+	public var strength : Float = 1.;
+
+	public var lastBakedProbeIndex = -1;
+
+	var prim : h3d.prim.Cube;
+
+	var shader : hrt.shader.VolumetricLightmap;
+
+	function set_voxelSize(newSize) :h3d.Vector {
+		voxelSize = newSize;
+		updateProbeCount();
+		return voxelSize;
+	}
+
+	public function new(?parent) {
+		var prim = new h3d.prim.Cube(1,1,1,false);
+		prim.addNormals();
+		super(prim, null, parent);
+		shader = new hrt.shader.VolumetricLightmap();
+		material.mainPass.removeShader(material.mainPass.getShader(h3d.shader.pbr.PropsValues));
+		material.mainPass.addShader(shader);
+		material.mainPass.setPassName("volumetricLightmap");
+		material.mainPass.blend(One, One);
+		material.mainPass.culling = Front;
+		material.mainPass.depth(false, Greater);
+		material.mainPass.enableLights = false;
+		material.castShadows = false;
+		material.shadows = false;
+		material.mainPass.stencil = new h3d.mat.Stencil();
+		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 override function clone( ?o : h3d.scene.Object ) : h3d.scene.Object {
+		var vm = o == null ? new VolumetricMesh(null) : cast o;
+		vm.shOrder = shOrder;
+		vm.strength = strength;
+		vm.useAlignedProb = useAlignedProb;
+		vm.lightProbeTexture = lightProbeTexture != null ? lightProbeTexture.clone() : null;
+		vm.probeCount.load(probeCount);
+		vm.voxelSize.load(voxelSize);
+		return vm;
+	}
+
+	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 inline 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;
+	}
+
+	override function onRemove() {
+		super.onRemove();
+		if( lightProbeTexture != null ) {
+			lightProbeTexture.dispose();
+			lightProbeTexture = null;
+		}
+	}
+
+	public function updateProbeCount(){
+		syncPos();
+		var scale = absPos.getScale();
+		probeCount.set(Std.int(Math.max(1,Math.floor(scale.x/voxelSize.x)) + 1),
+						Std.int(Math.max(1,Math.floor(scale.y/voxelSize.y)) + 1),
+						Std.int(Math.max(1,Math.floor(scale.z/voxelSize.z)) + 1));
+	}
+
+	public function load( bytes : haxe.io.Bytes ) {
+		if( bytes.length == 0 )
+			return false;
+		bytes = try haxe.zip.Uncompress.run(bytes) catch( e : Dynamic ) throw e;
+		var count = getProbeCount();
+		if( bytes.length != count * getCoefCount() * 4 * 4 )
+			return false;
+		lastBakedProbeIndex = count;
+		if( lightProbeTexture != null ) lightProbeTexture.dispose();
+		lightProbeTexture = new h3d.mat.Texture(probeCount.x * getCoefCount(), probeCount.y * probeCount.z, [Dynamic], RGBA32F);
+		lightProbeTexture.filter = Nearest;
+		lightProbeTexture.uploadPixels(new hxd.Pixels(lightProbeTexture.width, lightProbeTexture.height, bytes, RGBA32F));
+		return true;
+	}
+
+	public function save() : haxe.io.Bytes {
+		var data;
+		if( lightProbeTexture == null )
+			data = haxe.io.Bytes.alloc(0);
+		else
+			data = lightProbeTexture.capturePixels().bytes;
+		return haxe.zip.Compress.run(data,9);
+	}
+
+	override function emit(ctx:h3d.scene.RenderContext){
+		if( lightProbeTexture != null ) super.emit(ctx);
+	}
+
+	override function sync(ctx:h3d.scene.RenderContext) {
+		if( lightProbeTexture == null )
+			return;
+		var scale = absPos.getScale();
+		shader.ORDER = shOrder;
+		shader.lightmapInvPos.load(getInvPos());
+		shader.lightmapSize.load(new h3d.Vector(probeCount.x, probeCount.y, probeCount.z));
+		shader.voxelSize.load(new h3d.Vector(scale.x/(probeCount.x - 1), scale.y/(probeCount.y - 1), scale.z/(probeCount.z - 1)));
+		shader.lightProbeTexture = lightProbeTexture;
+		shader.cameraInverseViewProj.load(ctx.camera.getInverseViewProj());
+		shader.cameraPos.load(ctx.camera.pos);
+		shader.strength = strength;
+	}
+
+	public function getWorldAlignment(lightmaps : Array<VolumetricMesh>) : h3d.Vector {
+		var scale = absPos.getScale();
+		var result =  new h3d.Vector(scale.x/(probeCount.x - 1), scale.y/(probeCount.y - 1), scale.z/(probeCount.z - 1));
+		for(i in 0...lightmaps.length){
+			var lsc = lightmaps[i].absPos.getScale();
+			result.x = Math.max(result.x, lsc.x / (lightmaps[i].probeCount.x - 1.0));
+			result.y = Math.max(result.y, lsc.y / (lightmaps[i].probeCount.y - 1.0));
+			result.z = Math.max(result.z, lsc.z / (lightmaps[i].probeCount.z - 1.0));
+		}
+		return result;
+	}
+
+	public function isInsideVolume(worldPos: h3d.Vector) : Bool {
+		var localPos = worldPos.clone();
+		globalToLocal(localPos);
+		return (localPos.x >= 0 && localPos.y >= 0 && localPos.z >= 0 && localPos.x <= 1 && localPos.y <= 1 && localPos.z <= 1);
+	}
+}

+ 22 - 0
hrt/shader/Bloom.hx

@@ -0,0 +1,22 @@
+package hrt.shader;
+
+class Bloom extends h3d.shader.ScreenShader {
+
+	static var SRC = {
+
+		@param var hdr : Sampler2D;
+		@param var threshold : Float;
+		@param var intensity : Float;
+		@param var colorMatrix : Mat4;
+
+		function fragment() {
+			pixelColor = hdr.get(calculatedUV);
+			var lum = pixelColor.rgb.dot(vec3(0.2126, 0.7152, 0.0722));
+			if( lum < threshold ) pixelColor.rgb = vec3(0.) else pixelColor.rgb *= (lum - threshold) / lum;
+			pixelColor.rgb *= intensity;
+			pixelColor.rgb = (vec4(pixelColor.rgb,1.) * colorMatrix).rgb;
+		}
+
+	};
+
+}

+ 17 - 0
hrt/shader/Brush.hx

@@ -0,0 +1,17 @@
+package hrt.shader;
+
+class Brush extends hxsl.Shader {
+
+	static var SRC = {
+
+		@:import h3d.shader.Base2d;
+		@param var strength : Float;
+		@param var size : Float;
+		@param var pos : Vec3;
+
+		function fragment() {
+			var tileUV = pos.xy + calculatedUV * size;
+			pixelColor = vec4((textureColor * strength).rgb, textureColor.r);
+		}
+	}
+}

+ 172 - 0
hrt/shader/ComputeSH.hx

@@ -0,0 +1,172 @@
+package hrt.shader;
+
+class ComputeSH extends h3d.shader.ScreenShader {
+	static var SRC = {
+
+		@param var environment : SamplerCube;
+		@param var width : Int;
+		@param var cubeDir : Array<Mat3, 6>;
+		@const var ORDER : Int;
+
+		@param var PI = 3.1416;
+
+		var shCoefL00 : Float;
+		var shCoefL1n1: Float;
+		var shCoefL10 : Float;
+		var shCoefL11 : Float;
+		var shCoefL2n2 : Float;
+		var shCoefL2n1 : Float;
+		var shCoefL20 : Float;
+		var shCoefL21 : Float;
+		var shCoefL22 : Float;
+
+		var coefL00Final : Vec3;
+		var coefL1n1Final: Vec3;
+		var coefL10Final : Vec3;
+		var coefL11Final : Vec3;
+		var coefL2n2Final : Vec3;
+		var coefL2n1Final : Vec3;
+		var coefL20Final : Vec3;
+		var coefL21Final : Vec3;
+		var coefL22Final : Vec3;
+
+		function vertex(){
+			var position = vec3(input.position.x, input.position.y * flipY, 0);
+			output.position = vec4(position, 1.0);
+		}
+
+		function evalSH(dir:Vec3) {
+
+			if (ORDER >= 1){
+				shCoefL00 = evalCoefL00(dir);
+			}
+			if (ORDER >= 2){
+				shCoefL1n1 = evalCoefL1n1(dir);
+				shCoefL10 = evalCoefL10(dir);
+				shCoefL11 = evalCoefL11(dir);
+			}
+			if (ORDER >= 3){
+				shCoefL2n2 = evalCoefL2n2(dir);
+				shCoefL2n1 = evalCoefL2n1(dir);
+				shCoefL20 = evalCoefL20(dir);
+				shCoefL21 = evalCoefL21(dir);
+				shCoefL22 = evalCoefL22(dir);
+			}
+		}
+
+		function getDir(u: Float, v:Float, face:Int) : Vec3 {
+			var dir = vec3(u, v, 1) * cubeDir[face];
+			dir.normalize();
+			return dir;
+		}
+
+		function evalCoefL00(dir: Vec3) : Float { return 0.282095; }
+		function evalCoefL1n1(dir: Vec3) : Float { return -0.488603 * dir.y; }
+		function evalCoefL10(dir: Vec3) : Float { return 0.488603 * dir.z; }
+		function evalCoefL11(dir: Vec3) : Float { return -0.488603 * dir.x; }
+		function evalCoefL2n2(dir: Vec3) : Float { return 1.092548 * dir.y * dir.x; }
+		function evalCoefL2n1(dir: Vec3) : Float { return -1.092548 * dir.y * dir.z; }
+		function evalCoefL20(dir: Vec3) : Float { return 0.315392 * (-dir.x * dir.x - dir.y * dir.y + 2.0 * dir.z * dir.z); }
+		function evalCoefL21(dir: Vec3) : Float { return -1.092548 * dir.x * dir.z; }
+		function evalCoefL22(dir: Vec3) : Float { return 0.546274 * (dir.x * dir.x - dir.y * dir.y); }
+
+		var out : {
+			position : Vec4,
+			coefL00 : Vec3,
+			coefL1n1: Vec3,
+			coefL10 : Vec3,
+			coefL11 : Vec3,
+			coefL2n2 : Vec3,
+			coefL2n1 : Vec3,
+			coefL20 : Vec3,
+			coefL21 : Vec3,
+			coefL22 : Vec3,
+		};
+
+		function fragment() {
+
+			if (ORDER >= 1){
+				coefL00Final = vec3(0);
+			}
+			if (ORDER >= 2){
+				coefL1n1Final = vec3(0);
+				coefL10Final = vec3(0);
+				coefL11Final = vec3(0);
+			}
+			if (ORDER >= 3){
+				coefL2n2Final = vec3(0);
+				coefL2n1Final = vec3(0);
+				coefL20Final = vec3(0);
+				coefL21Final = vec3(0);
+				coefL22Final = vec3(0);
+			}
+
+			var weightSum = 0.0;
+			var fWidth : Float = width;
+			var invWidth : Float = 1.0 / fWidth;
+
+			for(f in 0...6) {
+				for (u in 0...width) {
+					var fU : Float = (u / fWidth - 0.5) * 2.0;// Texture coordinate U in range [-1 to 1]
+					fU *= fU;
+					var uCoord = 2.0 * u * invWidth + invWidth;
+					for (v in 0...width) {
+						var fV : Float = (v / fWidth - 0.5) * 2.0;// Texture coordinate V in range [-1 to 1]
+						fV *= fV;
+						var vCoord = 2.0 * v * invWidth + invWidth;
+
+						var dir = getDir(uCoord, vCoord, f);// Get direction from center of cube texture to current texel
+
+						var diffSolid = 4.0 / ((1.0 + fU + fV) * sqrt(1.0 + fU + fV));	// Scale factor depending on distance from center of the face
+						weightSum += diffSolid;
+
+						var flippedDir = vec3(dir.x, dir.y, -dir.z);
+						var color : Vec3 = environment.get(-flippedDir).rgb;// Get color from texture
+
+						evalSH(dir);// Calculate coefficients of spherical harmonics for current direction
+
+						if (ORDER >= 1){
+							coefL00Final += shCoefL00 * color * diffSolid;
+						}
+						if (ORDER >= 2){
+							coefL1n1Final += shCoefL1n1 * color * diffSolid;
+							coefL10Final += shCoefL10 * color * diffSolid;
+							coefL11Final += shCoefL11 * color * diffSolid;
+						}
+						if (ORDER >= 3){
+							coefL2n2Final += shCoefL2n2 * color * diffSolid;
+							coefL2n1Final += shCoefL2n1 * color * diffSolid;
+							coefL20Final += shCoefL20 * color * diffSolid;
+							coefL21Final += shCoefL21 * color * diffSolid;
+							coefL22Final += shCoefL22 * color * diffSolid;
+						}
+					}
+				}
+			}
+
+			// Final scale for coefficients
+			var normProj = (4.0 * PI) / weightSum;
+
+			if (ORDER >= 1){
+				out.coefL00 = coefL00Final * normProj;
+			}
+
+			if (ORDER >= 2){
+				out.coefL1n1 = coefL1n1Final * normProj;
+				out.coefL10 = coefL10Final * normProj;
+				out.coefL11 = coefL11Final * normProj;
+			}
+			else{ out.coefL1n1 = vec3(0); out.coefL10 = vec3(0); out.coefL11 = vec3(0); }
+
+			if (ORDER >= 3){
+				out.coefL2n2 = coefL2n2Final * normProj;
+				out.coefL2n1 = coefL2n1Final * normProj;
+				out.coefL20 = coefL20Final * normProj;
+				out.coefL21 = coefL21Final * normProj;
+				out.coefL22 = coefL22Final * normProj;
+			}
+			else{ out.coefL2n2 = vec3(0); out.coefL2n1 = vec3(0); out.coefL20 = vec3(0); out.coefL21 = vec3(0); out.coefL22 = vec3(0); }
+		}
+	}
+
+}

+ 69 - 0
hrt/shader/DisplaySH.hx

@@ -0,0 +1,69 @@
+package hrt.shader;
+
+class DisplaySH extends hxsl.Shader {
+
+	static var SRC = {
+
+		function computeIrradiance(norm : Vec3) : Vec3 {
+			// An Efficient Representation for Irradiance Environment Maps
+			// Ravi Ramamoorthi Pat Hanrahan
+
+			var c1 = 0.429043;
+			var c2 = 0.511664;
+			var c3 = 0.743125;
+			var c4 = 0.886227;
+			var c5 = 0.247708;
+
+			var irradiance = vec3(0,0,0);
+
+			if (order >= 1){
+				var L00 = vec3(shCoefsRed[0], shCoefsGreen[0], shCoefsBlue[0]);
+				irradiance += c4 * L00;
+			}
+
+			if (order >= 2){
+				var L1n1 = vec3(shCoefsRed[1], shCoefsGreen[1], shCoefsBlue[1]);
+				var L10 = vec3(shCoefsRed[2], shCoefsGreen[2], shCoefsBlue[2]);
+				var L11 = vec3(shCoefsRed[3], shCoefsGreen[3], shCoefsBlue[3]);
+				irradiance += 2 * c2 * (L11 * norm.x + L1n1 * norm.y + L10 * norm.z);
+			}
+
+			if(order >= 3){
+				var L2n2 = vec3(shCoefsRed[4], shCoefsGreen[4], shCoefsBlue[4]);
+				var L2n1 = vec3(shCoefsRed[5], shCoefsGreen[5], shCoefsBlue[5]);
+				var L20 = vec3(shCoefsRed[6], shCoefsGreen[6], shCoefsBlue[6]);
+				var L21 = vec3(shCoefsRed[7], shCoefsGreen[7], shCoefsBlue[7]);
+				var L22 = vec3(shCoefsRed[8], shCoefsGreen[8], shCoefsBlue[8]);
+				irradiance += c1 * L22 * (norm.x*norm.x - norm.y*norm.y) + c3 * L20  * (norm.z * norm.z) - c5 * L20 +
+				2 * c1 * (L2n2 * (norm.x*norm.y) + L21 * (norm.x*norm.z) + L2n1 * (norm.y*norm.z));
+			}
+
+			return irradiance;
+		}
+
+		@const var order : Int;
+		@const var SIZE : Int; // Equal to order*order
+
+		@param var shCoefsRed : Array<Float,SIZE>;
+		@param var shCoefsGreen : Array<Float,SIZE>;
+		@param var shCoefsBlue : Array<Float,SIZE>;
+		@param var strength : Float;
+
+		var transformedNormal : Vec3;
+
+		var output : {
+			color : Vec4
+		};
+
+		function fragment() {
+			var normal = vec4(transformedNormal.x, transformedNormal.y, transformedNormal.z, 1.0);
+			output.color = vec4(computeIrradiance(normal.xyz) / 3.14 * strength, 1.0);
+		}
+	}
+
+	public function new(){
+		super();
+		strength = 1.0;
+	}
+
+}

+ 48 - 0
hrt/shader/DistanceFog.hx

@@ -0,0 +1,48 @@
+package hrt.shader;
+
+class DistanceFog extends h3d.shader.ScreenShader {
+
+	static var SRC = {
+
+		@param var startDistance : Float;
+		@param var endDistance : Float;
+		@param var startOpacity : Float;
+		@param var endOpacity: Float;
+		@param var startColorDistance : Float;
+		@param var endColorDistance : Float;
+		@param var startColor : Vec3;
+		@param var endColor : Vec3;
+
+		@ignore @param var depthTexture : Channel;
+		@ignore @param var cameraPos : Vec3;
+		@ignore @param var cameraInverseViewProj : Mat4;
+
+		function getPosition( uv: Vec2 ) : Vec3 {
+			var depth = depthTexture.get(uv);
+			var uv2 = uvToScreen(calculatedUV);
+			var isSky = 1 - ceil(depth);
+			depth = mix(depth, 1, isSky);
+			var temp = vec4(uv2, depth, 1) * cameraInverseViewProj;
+			var originWS = temp.xyz / temp.w;
+			return originWS;
+		}
+
+		function fragment() {
+			var calculatedUV = input.uv;
+			var origin = getPosition(calculatedUV);
+			var distance = (origin - cameraPos).length();
+			if( startDistance > distance ) discard;
+			var opacityFactor = clamp((distance - startDistance) / (endDistance - startDistance), 0, 1);
+			var colorFactor = clamp((distance - startColorDistance) / (endColorDistance - startColorDistance), 0, 1);
+			var fogColor = mix(startColor, endColor, colorFactor);
+			var fogOpacity = mix(startOpacity, endOpacity, opacityFactor);
+			if( fogOpacity <= 0 ) discard;
+			pixelColor = vec4(fogColor, fogOpacity);
+		}
+	};
+
+	public function new() {
+		super();
+	}
+
+}

+ 2 - 2
hrt/prefab/terrain/Shader.hx → hrt/shader/Terrain.hx

@@ -1,6 +1,6 @@
-package hrt.prefab.terrain;
+package hrt.shader;
 
 
-class Shader extends hxsl.Shader {
+class Terrain extends hxsl.Shader {
 
 
 	static var SRC = {
 	static var SRC = {
 
 

+ 159 - 0
hrt/shader/VolumetricLightmap.hx

@@ -0,0 +1,159 @@
+package hrt.shader;
+
+class VolumetricLightmap extends hxsl.Shader {
+
+	static var SRC =
+	{
+		function getCoef(shCoords : Vec3, band : Int) : Vec3 {
+			var u = (shCoords.x + band * lightmapSize.x ) * texelSize.x + texelSize.x / 2.0;
+			var v = (shCoords.y + shCoords.z * lightmapSize.y)  * texelSize.y  + texelSize.y / 2.0;
+			return lightProbeTexture.get(vec2(u, v)).rgb;
+		}
+
+		function getCoefFinal(band : Int) : Vec3 {
+			var p00 = mix(getCoef(p000, band), getCoef(p100, band), dist.x);
+			var p01 = mix(getCoef(p001, band), getCoef(p101, band), dist.x);
+			var p10 = mix(getCoef(p010, band), getCoef(p110, band), dist.x);
+			var p11 = mix(getCoef(p011, band), getCoef(p111, band), dist.x);
+			var p0 = mix(p00, p10 , dist.y);
+			var p1 = mix(p01, p11 , dist.y);
+			var p = mix(p0, p1 , dist.z);
+			return p;
+		}
+
+		function computeIrradiance(norm : Vec3) : Vec3 {
+		// An Efficient Representation for Irradiance Environment Maps
+		// Ravi Ramamoorthi Pat Hanrahan
+
+			var c1 = 0.429043;
+			var c2 = 0.511664;
+			var c3 = 0.743125;
+			var c4 = 0.886227;
+			var c5 = 0.247708;
+
+			var irradiance = vec3(0,0,0);
+
+			if (ORDER >= 1){
+				var L00 = getCoefFinal(0);
+				irradiance += c4 * L00;
+			}
+			if (ORDER >= 2){
+				var L1n1 = getCoefFinal(1);
+				var L10 = getCoefFinal(2);
+				var L11 = getCoefFinal(3);
+				irradiance += 2 * c2 * (L11 * norm.x + L1n1 * norm.y + L10 * norm.z);
+			}
+			if(ORDER >= 3){
+				var L2n2 = getCoefFinal(4);
+				var L2n1 = getCoefFinal(5);
+				var L20 = getCoefFinal(6);
+				var L21 = getCoefFinal(7);
+				var L22 = getCoefFinal(8);
+				irradiance += c1 * L22 * (norm.x*norm.x - norm.y*norm.y) + c3 * L20  * (norm.z * norm.z) - c5 * L20 +
+				2 * c1 * (L2n2 * (norm.x*norm.y) + L21 * (norm.x*norm.z) + L2n1 * (norm.y*norm.z));
+			}
+			return irradiance / 3.14;
+		}
+
+		function getLightProbeIndex( coords : Vec3 ) : Int {
+			return int(floor(coords.x + lightmapSize.x * coords.y + lightmapSize.y * lightmapSize.x * coords.z));
+		}
+
+		function getVoxelCoords(pos : Vec3 ) : Vec3 {
+			posLightmapSpace = (vec4(pos, 1) * lightmapInvPos).xyz;
+			return floor(posLightmapSpace * (lightmapSize - vec3(1,1,1)));
+		}
+
+		function getLightProbePosition( coords : Vec3 ) : Vec3 {
+			return coords * voxelSize;
+		}
+
+		function getPixelPosition() : Vec3 {
+			var uv2 = (screenUV - 0.5) * vec2(2, -2);
+			var temp = vec4(uv2, depth, 1) * cameraInverseViewProj;
+			var originWS = temp.xyz / temp.w;
+			return originWS;
+		}
+
+		function getClampedCoords(coords : Vec3) : Vec3{
+			return min(lightmapSize - vec3(1,1,1), max( vec3(0,0,0), coords));
+		}
+
+		@const var ORDER : Int;
+		@param var lightProbeTexture : Sampler2D;
+		@param var lightmapInvPos : Mat4;
+		@param var lightmapSize : Vec3;
+		@param var voxelSize : Vec3;
+		@param var strength : Float;
+
+		@param var cameraInverseViewProj : Mat4;
+		@param var cameraPos : Vec3;
+
+		var transformedPosition : Vec3;
+		var screenUV : Vec2;
+
+		var depth : Float;
+		var normal : Vec3;
+		var position : Vec3;
+		var posLightmapSpace : Vec3;
+		var voxelCoords : Vec3;
+		var albedo : Vec3;
+		var occlusion : Float;
+		var roughness : Float;
+		var metalness : Float;
+
+		var probeCount : Float;
+		var coefCount : Float;
+		var texelSize : Vec2;
+		var dist : Vec3;
+
+		var p000 : Vec3;
+		var p100 : Vec3;
+		var p010 : Vec3;
+		var p001 : Vec3;
+		var p110 : Vec3;
+		var p101 : Vec3;
+		var p011 : Vec3;
+		var p111 : Vec3;
+
+		var output : {
+			color : Vec4
+		};
+
+
+		function fragment(){
+
+			position = getPixelPosition();
+			voxelCoords = getVoxelCoords(position);
+			probeCount = lightmapSize.x * lightmapSize.y * lightmapSize.z;
+			coefCount = float(ORDER * ORDER);
+
+			texelSize = vec2(1/(lightmapSize.x * coefCount), 1/(lightmapSize.y * lightmapSize.z));
+
+			if(posLightmapSpace.x < 0 || posLightmapSpace.y < 0 || posLightmapSpace.z < 0 ||
+			posLightmapSpace.x > 1 || posLightmapSpace.y > 1 || posLightmapSpace.z > 1)
+				discard;
+
+			p000 = getClampedCoords(voxelCoords + vec3(0,0,0));
+			p100 = getClampedCoords(voxelCoords + vec3(1,0,0));
+			p010 = getClampedCoords(voxelCoords + vec3(0,1,0));
+			p001 = getClampedCoords(voxelCoords + vec3(0,0,1));
+			p110 = getClampedCoords(voxelCoords + vec3(1,1,0));
+			p101 = getClampedCoords(voxelCoords + vec3(1,0,1));
+			p011 = getClampedCoords(voxelCoords + vec3(0,1,1));
+			p111 = getClampedCoords(voxelCoords + vec3(1,1,1));
+
+			var voxelPos = (voxelCoords) / (lightmapSize - vec3(1,1,1));
+			dist = (posLightmapSpace - voxelPos) * (lightmapSize - vec3(1,1,1));
+
+			var irradiance : Vec3 = computeIrradiance(normal) * min(vec3(1),albedo) * occlusion;
+
+			var NdV = dot(normal, normalize(cameraPos - position));
+			var F0 = mix(vec3(0.04), albedo, metalness);
+			var F = F0 + (max(vec3(1 - roughness), F0) - F0) * exp2( ( -5.55473 * NdV - 6.98316) * NdV );
+			var indirect = (irradiance * (1 - metalness) * (1 - F) ) * strength;
+
+			output.color.rgb += indirect;
+		}
+	}
+}

+ 1 - 0
libs/nw/App.hx

@@ -5,5 +5,6 @@ extern class App {
 	public static var argv(default, never) : Array<String>;
 	public static var argv(default, never) : Array<String>;
 	public static var dataPath(default, never) : String;
 	public static var dataPath(default, never) : String;
 	public static function on( event : String, callb : String -> Void ) : Void;
 	public static function on( event : String, callb : String -> Void ) : Void;
+	public static function clearCache( ) : Void;
 
 
 }
 }