2
0
ShiroSmith 7 жил өмнө
parent
commit
5896230009

+ 1 - 0
h3d/mat/Texture.hx

@@ -106,6 +106,7 @@ class Texture {
 			if( this.flags.has(f) )
 				flags.push(f);
 		var t = new Texture(width, height, flags, format, allocPos);
+		t.name = this.name;
 		if(this.flags.has(Cube)) h3d.pass.CubeCopy.run(this, t);
 		else h3d.pass.Copy.run(this, t);
 		lastFrame = old;

+ 2 - 2
h3d/pass/Copy.hx

@@ -16,9 +16,9 @@ class Copy extends ScreenFx<CopyShader> {
 		super(new CopyShader());
 	}
 
-	public function apply( from, to, ?blend : h3d.mat.BlendMode, ?customPass : h3d.mat.Pass ) {
+	public function apply( from, to, ?blend : h3d.mat.BlendMode, ?customPass : h3d.mat.Pass, ?layer :Int) {
 		if( to != null )
-			engine.pushTarget(to);
+			engine.pushTarget(to, layer != null ? layer : 0);
 		shader.texture = from;
 		if( customPass != null ) {
 			var old = pass;

+ 212 - 36
h3d/scene/pbr/Terrain.hx

@@ -5,22 +5,22 @@ class Tile extends h3d.scene.Mesh {
 	public var tileX (default, null) : Int;
 	public var tileY (default, null) : Int;
 	public var heightMap(default, set) : h3d.mat.Texture;
-	public var surfaceIndex : h3d.mat.Texture;
+	public var surfaceIndexMap : h3d.mat.Texture;
 	public var surfaceCount = 0;
 	public var surfaceWeights : Array<h3d.mat.Texture> = [];
 	var shader : h3d.shader.pbr.Terrain;
+	public var surfaceWeightArray (default, null) : h3d.mat.TextureArray;
 
-	public function new(x : Int, y : Int , surfaceCount, prim, ?parent){
-		super(prim, null, parent);
+	public function new(x : Int, y : Int , ?parent){
+		super(Std.instance(parent, Terrain).grid, null, parent);
 		this.tileX = x;
 		this.tileY = y;
 		shader = new h3d.shader.pbr.Terrain();
 		material.mainPass.addShader(shader);
 		material.mainPass.culling = None;
-		shader.usePreview = false;
 		this.x = x * getTerrain().tileSize;
 		this.y = y * getTerrain().tileSize;
-		this.surfaceCount = surfaceCount;
+		this.surfaceCount = getTerrain().surfaces.length;
 	}
 
 	function set_heightMap(v){
@@ -28,24 +28,72 @@ class Tile extends h3d.scene.Mesh {
 		return heightMap = v;
 	}
 
-	public function initTex(){
-		if(heightMap != null) heightMap.dispose();
-		heightMap = new h3d.mat.Texture(getTerrain().heightMapResolution + 2, getTerrain().heightMapResolution + 2, [Target], R16F);
-		heightMap.wrap = Clamp;
-		if(surfaceIndex != null) surfaceIndex.dispose();
-		surfaceIndex = new h3d.mat.Texture(getTerrain().weightMapResolution, getTerrain().weightMapResolution, [Target], RGBA);
-		surfaceIndex.filter = Nearest;
-		for(i in 0 ... surfaceWeights.length) surfaceWeights[i].dispose();
-		surfaceWeights = [for (value in 0...surfaceCount) new h3d.mat.Texture(getTerrain().weightMapResolution, getTerrain().weightMapResolution, [Target], RGBA)];
+	public function uploadWeightMap(tex : h3d.mat.Texture, i : Int){
+		if(i < surfaceWeights.length && surfaceWeights[i] != null){
+			getTerrain().copyPass.apply(tex, surfaceWeights[i]);
+			generateWeightArray();
+		}
+	}
+
+	public function refresh(){
+
+		if(heightMap == null || heightMap.width != getTerrain().heightMapResolution + 2){
+			var oldHeightMap = heightMap;
+			heightMap = new h3d.mat.Texture(getTerrain().heightMapResolution + 2, getTerrain().heightMapResolution + 2, [Target], RGBA32F );
+			heightMap.wrap = Clamp;
+			heightMap.filter = Nearest;
+			if(oldHeightMap != null){
+				getTerrain().copyPass.apply(oldHeightMap, heightMap);
+				oldHeightMap.dispose();
+			}
+		}
+
+		if(surfaceIndexMap == null || surfaceIndexMap.width != getTerrain().weightMapResolution){
+			var oldSurfaceIndexMap = surfaceIndexMap;
+			surfaceIndexMap = new h3d.mat.Texture(getTerrain().weightMapResolution, getTerrain().weightMapResolution, [Target], RGBA);
+			surfaceIndexMap.filter = Nearest;
+			if(oldSurfaceIndexMap != null){
+				getTerrain().copyPass.apply(oldSurfaceIndexMap, surfaceIndexMap);
+				oldSurfaceIndexMap.dispose();
+			}
+		}
+
+		if(surfaceWeights.length != surfaceCount || surfaceWeights[0].width != getTerrain().weightMapResolution){
+			var oldArray = surfaceWeights;
+			surfaceWeights = new Array<h3d.mat.Texture>();
+			surfaceWeights.resize(surfaceCount);
+			for(i in 0 ... surfaceWeights.length){
+				surfaceWeights[i] = new h3d.mat.Texture(getTerrain().weightMapResolution, getTerrain().weightMapResolution, [Target], RGBA);
+				surfaceWeights[i].wrap = Clamp;
+				if(i < oldArray.length && oldArray[i] != null)
+					getTerrain().copyPass.apply(oldArray[i], surfaceWeights[i]);
+			}
+			for(i in 0 ... oldArray.length)
+				if( oldArray[i] != null) oldArray[i].dispose();
+
+			generateWeightArray();
+		}
+	}
+
+	public function generateWeightArray(){
+		if(surfaceWeightArray == null || surfaceWeightArray.width != getTerrain().weightMapResolution || surfaceWeightArray.get_layerCount() != surfaceWeights.length){
+			if(surfaceWeightArray != null) surfaceWeightArray.dispose();
+			surfaceWeightArray = new h3d.mat.TextureArray(getTerrain().weightMapResolution, getTerrain().weightMapResolution, surfaceWeights.length, [Target]);
+			surfaceWeightArray.wrap = Clamp;
+		}
+		for(i in 0 ... surfaceWeights.length)
+			if(surfaceWeights[i] != null) getTerrain().copyPass.apply(surfaceWeights[i], surfaceWeightArray, None, null, i);
 	}
 
 	public override function dispose() {
 		if(heightMap != null) heightMap.dispose();
-		if(surfaceIndex != null) surfaceIndex.dispose();
-		for(i in 0 ... surfaceWeights.length) surfaceWeights[i].dispose();
+		if(surfaceIndexMap != null) surfaceIndexMap.dispose();
+		for(i in 0 ... surfaceWeights.length)
+			if( surfaceWeights[i] != null) surfaceWeights[i].dispose();
 	}
 
 	override function emit(ctx:RenderContext){
+		if( getTerrain().surfaceArray == null) return;
 		var bounds = getBounds();
 		if(bounds != null){
 			if(ctx.camera.getFrustum().hasBounds(bounds))
@@ -55,11 +103,23 @@ class Tile extends h3d.scene.Mesh {
 	}
 
 	override function sync(ctx:RenderContext) {
+		if( getTerrain().surfaceArray == null) return;
 		shader.heightMap = heightMap;
-		shader.heightMapSize = getTerrain().heightMapResolution ;
+		shader.heightMapSize = getTerrain().heightMapResolution;
 		shader.primSize = getTerrain().tileSize;
 		shader.cellSize = getTerrain().cellSize;
 		shader.showGrid = getTerrain().showGrid;
+		shader.surfaceIndexMap = surfaceIndexMap;
+		shader.albedoTextures = getTerrain().surfaceArray.albedo;
+		shader.normalTextures = getTerrain().surfaceArray.normal;
+		shader.pbrTextures = getTerrain().surfaceArray.pbr;
+		shader.weightTextures = surfaceWeightArray;
+		shader.weightCount = surfaceCount;
+		shader.surfaceParams = getTerrain().surfaceArray.params;
+		shader.secondSurfaceParams = getTerrain().surfaceArray.secondParams;
+		shader.tileIndex = new h3d.Vector(tileX, tileY);
+		shader.useHeightBlend = getTerrain().useHeightBlend;
+		shader.parallaxAmount = getTerrain().parallaxAmount / 10.0;
 	}
 
 	inline function getTerrain(){
@@ -68,34 +128,150 @@ class Tile extends h3d.scene.Mesh {
 }
 
 class Surface {
-	public var index : Int;
-	public var albedo : h3d.mat.Texture;
-	public var normal : h3d.mat.Texture;
-	public var pbrTex : h3d.mat.Texture;
+	public var albedo (default, set) : h3d.mat.Texture;
+	public var normal (default, set) : h3d.mat.Texture;
+	public var pbr (default, set) : h3d.mat.Texture;
+	public var tilling = 1.0;
+	public var offset : h3d.Vector;
+	public var angle = 0.0;
+
+	public function new(?albedo : h3d.mat.Texture, ?normal : h3d.mat.Texture, ?pbr : h3d.mat.Texture){
+		this.albedo = albedo;
+		this.normal = normal;
+		this.pbr = pbr;
+		this.offset = new h3d.Vector(0);
+	}
+
+	public function dispose() {
+		if(albedo != null) albedo.dispose();
+		if(normal != null) normal.dispose();
+		if(pbr != null) pbr.dispose();
+	}
+
+	function set_albedo(t : h3d.mat.Texture){
+		return albedo = swap(albedo, t);
+	}
+
+	function set_normal(t : h3d.mat.Texture){
+		return normal = swap(normal, t);
+	}
+
+	function set_pbr(t : h3d.mat.Texture){
+		return pbr = swap(pbr, t);
+	}
+
+	function swap(a : h3d.mat.Texture, b : h3d.mat.Texture) : h3d.mat.Texture {
+		if(a != null) a.dispose();
+		if(b != null){
+			var r = b.clone();
+			r.wrap = Repeat;
+			return r;
+		}
+		return null;
+	}
+}
+
+class SurfaceArray {
+	public var albedo : h3d.mat.TextureArray;
+	public var normal : h3d.mat.TextureArray;
+	public var pbr : h3d.mat.TextureArray;
+	public var params : Array<h3d.Vector> = [];
+	public var secondParams : Array<h3d.Vector> = [];
+
+	public function new(count, res){
+		albedo = new h3d.mat.TextureArray(res, res, count, [Target]);
+		normal = new h3d.mat.TextureArray(res, res, count, [Target]);
+		pbr = new h3d.mat.TextureArray(res, res, count, [Target]);
+		albedo.wrap = Repeat;
+		normal.wrap = Repeat;
+		pbr.wrap = Repeat;
+	}
+
+	public function dispose() {
+		if(albedo != null) albedo.dispose();
+		if(normal != null) normal.dispose();
+		if(pbr != null) pbr.dispose();
+	}
 }
 
 class Terrain extends Object {
 
 	public var tileSize = 1.0;
 	public var cellSize = 1.0;
+	public var cellCount = 1;
 	public var heightMapResolution = 1;
 	public var weightMapResolution = 1;
-	public var showGrid = false;
-	var grid : h3d.prim.Grid;
-
-	var tiles : Array<Tile> = [];
-	var surfaces : Array<Surface> = [];
+	public var showGrid : Bool;
+	public var useHeightBlend : Bool;
+	public var parallaxAmount : Float = 0;
+	public var grid (default, null) : h3d.prim.Grid;
+	public var copyPass (default, null): h3d.pass.Copy;
+	public var tiles (default, null) : Array<Tile> = [];
+	public var surfaces (default, null) : Array<Surface> = [];
+	public var surfaceArray (default, null) : SurfaceArray;
 
 	public function new(?parent){
 		super(parent);
-		grid = new h3d.prim.Grid( Math.floor(tileSize/cellSize), Math.floor(tileSize/cellSize), cellSize, cellSize);
+		grid = new h3d.prim.Grid( cellCount, cellCount, cellSize, cellSize);
 		grid.addUVs();
 		grid.addNormals();
+		copyPass = new h3d.pass.Copy();
+	}
+
+	public function getSurface(i : Int) : Surface{
+		if(i < surfaces.length)
+				return surfaces[i];
+		return null;
+	}
+
+	public function getSurfaceFromTex(albedo, ?normal, ?pbr) : Surface{
+		for(s in surfaces){
+			var valid = false;
+			valid = s.albedo.name == albedo;
+			valid = valid && !(normal != null && s.normal.name != normal);
+			valid = valid && !(pbr != null && s.pbr.name != pbr);
+			if(valid) return s;
+		}
+		return null;
+	}
+
+	public function addSurface(albedo, normal, pbr) : Surface {
+		surfaces.push(new Surface(albedo, normal, pbr));
+		return surfaces[surfaces.length - 1];
+	}
+
+	public function addEmptySurface() : Surface {
+		surfaces.push(new Surface());
+		return surfaces[surfaces.length - 1];
+	}
+
+	public function generateSurfaceArray(){
+		var surfaceSize = 1;
+		for(i in 0 ... surfaces.length)
+			if(surfaces[i].albedo != null) surfaceSize = hxd.Math.ceil(hxd.Math.max(surfaces[i].albedo.width, surfaceSize));
+
+		if(surfaceArray != null) surfaceArray.dispose();
+		surfaceArray = new SurfaceArray(surfaces.length, surfaceSize);
+		for(i in 0 ... surfaces.length){
+			if(surfaces[i].albedo != null) copyPass.apply(surfaces[i].albedo, surfaceArray.albedo, null, null, i);
+			if(surfaces[i].normal != null) copyPass.apply(surfaces[i].normal, surfaceArray.normal, null, null, i);
+			if(surfaces[i].pbr != null) copyPass.apply(surfaces[i].pbr, surfaceArray.pbr, null, null, i);
+		}
+
+		updateSurfaceParams();
+		refreshTex();
+	}
+
+	public function updateSurfaceParams(){
+		for(i in 0 ... surfaces.length){
+			surfaceArray.params[i] = new h3d.Vector(surfaces[i].tilling, surfaces[i].offset.x, surfaces[i].offset.y, hxd.Math.degToRad(surfaces[i].angle));
+			surfaceArray.secondParams[i] = new h3d.Vector(0, 0, 0, 0);
+		}
 	}
 
 	public function refreshMesh(){
 		if(grid != null) grid.dispose();
-		grid = new h3d.prim.Grid( Math.floor(tileSize/cellSize), Math.floor(tileSize/cellSize), cellSize, cellSize);
+		grid = new h3d.prim.Grid( cellCount, cellCount, cellSize, cellSize);
 		grid.addUVs();
 		grid.addNormals();
 
@@ -109,7 +285,7 @@ class Terrain extends Object {
 	public function refreshTex(){
 		for(tile in tiles){
 			tile.surfaceCount = surfaces.length;
-			tile.initTex();
+			tile.refresh();
 		}
 	}
 
@@ -118,24 +294,24 @@ class Terrain extends Object {
 		refreshTex();
 	}
 
-	public function createTile(x : Int, y : Int){
+	public function createTile(x : Int, y : Int) : Tile {
 		var tile = getTile(x,y);
 		if(tile == null){
-			tile = new Tile(x, y, surfaces.length, grid, this);
-			tile.initTex();
+			tile = new Tile(x, y, this);
+			tile.refresh();
 			tiles.push(tile);
 		}
 		return tile;
 	}
 
-	public function getTile(x : Int, y : Int){
+	public function getTile(x : Int, y : Int) : Tile {
 		var result : Tile = null;
 		for(tile in tiles)
 			if(tile.tileX == x && tile.tileY == y) result = tile;
 		return result;
 	}
 
-	public function getTileAtWorldPos(pos : h3d.Vector){
+	public function getTileAtWorldPos(pos : h3d.Vector) : Tile {
 		var result : Tile = null;
 		var tileX = Math.floor(pos.x / tileSize);
 		var tileY = Math.floor(pos.y / tileSize);
@@ -144,14 +320,14 @@ class Terrain extends Object {
 		return result;
 	}
 
-	public function createTileAtWorldPos(pos : h3d.Vector){
+	public function createTileAtWorldPos(pos : h3d.Vector) : Tile {
 		var tileX = Math.floor(pos.x / tileSize);
 		var tileY = Math.floor(pos.y / tileSize);
 		var result = getTile(tileX, tileY);
 		return result == null ? createTile(tileX, tileY) : result;
 	}
 
-	public function getTiles(pos : h3d.Vector, range : Float, ?create = false){
+	public function getTiles(pos : h3d.Vector, range : Float, ?create = false) : Array<Tile> {
 		if(create){
 			var maxTileX = Math.floor((pos.x + range)/ tileSize);
 			var minTileX = Math.floor((pos.x - range)/ tileSize);

+ 34 - 0
h3d/shader/pbr/Brush.hx

@@ -0,0 +1,34 @@
+package h3d.shader.pbr;
+
+class Brush extends hxsl.Shader {
+
+	static var SRC = {
+
+		@:import h3d.shader.Base2d;
+		@const var normalize : Bool;
+
+		@param var strength : Float;
+		@param var weightTextures : Sampler2DArray;
+		@param var weightCount : Int;
+		@param var refIndex : Int;
+		@param var targetIndex : Int;
+		@param var size : Float;
+		@param var pos : Vec3;
+
+		function fragment() {
+			if(normalize){
+				var tileUV = pos.xy + calculatedUV * size ;
+				var refValue = weightTextures.get(vec3(tileUV, refIndex)).r;
+				var sum = 0.0;
+				for(i in 0 ... weightCount)
+					if(i != refIndex) sum += weightTextures.get(vec3(tileUV, i)).r;
+				var targetSum = min(1 - refValue, sum);
+
+				pixelColor = vec4(vec3((weightTextures.get(vec3(tileUV, targetIndex)).rgb / sum) * targetSum), 1.0);
+			}
+			else{
+				pixelColor = vec4(textureColor * strength);
+			}
+		}
+	}
+}

+ 146 - 18
h3d/shader/pbr/Terrain.hx

@@ -9,52 +9,180 @@ class Terrain extends hxsl.Shader {
 		@param var previewTex : Sampler2D;
 		@param var heightMap : Sampler2D;
 		@param var heightMapSize : Float;
+		@param var surfaceIndexMap : Sampler2D;
 		@param var primSize : Float;
 		@param var cellSize : Float;
 
-		@const var usePreview : Bool;
+		@param var albedoTextures : Sampler2DArray;
+		@param var normalTextures : Sampler2DArray;
+		@param var pbrTextures : Sampler2DArray;
+		@param var weightTextures : Sampler2DArray;
+		@param var parallaxAmount : Float;
+		@param var weightCount : Int;
+		@param var surfaceParams : Array<Vec4, 8>;
+		@param var secondSurfaceParams : Array<Vec4, 8>;
+		@param var tileIndex : Vec2;
+
 		@const var showGrid : Bool;
+		@const var useHeightBlend : Bool;
 
 		var calculatedUV : Vec2;
+		var terrainUV : Vec2;
+		var TBN : Mat3;
+		var worldNormal : Vec3;
 
-		function getNormal(uv: Vec2) : Vec3 {
-			var offset = vec2(1.0/heightMapSize, 0);
+		function computeNormal(uv: Vec2) : Vec3 {
+			var offset = vec2(1.0/heightMapSize, 0) * heightMapSize / (primSize / cellSize);
 			var base = heightMap.get(uv).r;
 			var ddx = heightMap.get(uv + offset.xy).r;
 			var ddy = heightMap.get(uv + offset.yx).r;
-			var normal = normalize(vec3(base - ddx, base - ddy, 0.5));
+			var normal = normalize(vec3(base - ddx, base - ddy, 0.1));
 			normal = (normal * global.modelView.mat3()).normalize();
+			worldNormal = normal;
 			return normal;
 		}
 
 		function vertex() {
 			calculatedUV = input.position.xy / primSize;
-			calculatedUV = (calculatedUV * (heightMapSize - 2)) / heightMapSize;
-			calculatedUV += 0.5 / heightMapSize;
-			transformedPosition += (vec3(0,0, heightMap.get(calculatedUV).r) * global.modelView.mat3());
-			transformedNormal = getNormal(calculatedUV);
+			terrainUV = (calculatedUV * (heightMapSize - 2)) / heightMapSize;
+			terrainUV += 0.5 / heightMapSize;
+			transformedPosition += (vec3(0,0, heightMap.get(terrainUV).r) * global.modelView.mat3());
+			transformedNormal = computeNormal(terrainUV);
+			var tangent = normalize(cross(transformedNormal, vec3(0,1,0)));
+			var bitangent = normalize(cross(transformedNormal,vec3(1,0,0)));
+			TBN = mat3(tangent, bitangent, transformedNormal);
+		}
+
+		function getPOMUV( uv : Vec2, surfaceIndex : Int, minLayers : Int, maxLayers : Int, amount: Float) : Vec2 {
+			var viewWS = (camera.position - transformedPosition).normalize();
+			var viewNS : Vec3;
+			{
+				var n = transformedNormal.normalize();
+				var transformedTangent = normalize(cross(transformedNormal, vec3(0,1,0)));
+				var tanX = transformedTangent.xyz.normalize();
+				var tanY = n.cross(tanX);
+				viewNS = vec3(viewWS.dot(tanX), viewWS.dot(tanY), viewWS.dot(n)).normalize();
+			}
+
+			var numLayers = mix(float(maxLayers), float(minLayers), abs(viewNS.z));
+			var layerDepth = 1 / numLayers;
+			var curLayerDepth = 0.;
+			var delta = (viewNS.xy / viewNS.z) * amount / numLayers;
+			var curUV = uv;
+			var curDepth = 1 - pbrTextures.get(vec3(curUV, surfaceIndex)).a;
+			while( curLayerDepth < curDepth ) {
+				curUV += delta;
+				curDepth =  1 - pbrTextures.get(vec3(curUV, surfaceIndex)).a;
+				curLayerDepth += layerDepth;
+			}
+			var prevUV = curUV - delta;
+			var after = curDepth - curLayerDepth;
+			var before =  (1 - pbrTextures.get(vec3(prevUV, surfaceIndex)).a) - curLayerDepth + layerDepth;
+			return mix(curUV, prevUV, after / (after - before));
+		}
+
+		function getsurfaceUV(i : Int, uv : Vec2) : Vec3 {
+			var angle = surfaceParams[i].w;
+			var offset = vec2(surfaceParams[i].y, surfaceParams[i].z);
+			var tilling = surfaceParams[i].x;
+			var worldUV = vec2((uv + tileIndex) * tilling) + offset;
+			var res = vec2( worldUV.x * cos(angle) - worldUV.y * sin(angle) , worldUV.y * cos(angle) + worldUV.x * sin(angle));
+			var surfaceUV = vec3(res, i);
+			return surfaceUV;
 		}
 
 		var emissiveValue : Float;
 		var metalnessValue : Float;
 		var roughnessValue : Float;
+		var occlusionValue : Float;
 		function fragment() {
-			if(usePreview) emissiveValue = previewTex.get(calculatedUV).r * 0.5;
-			else emissiveValue = 0;
 
-			metalnessValue = 0.0;
-			roughnessValue = 0.5;
+			if(useHeightBlend){
+				var curTexIndex = 0;
+				var curWeight = 0.0;
+				var curUV = vec2(0);
+				for(i in 0...weightCount){
+					var uv = getPOMUV(calculatedUV, i, 64, 128, parallaxAmount);
+					var h = pbrTextures.get(getsurfaceUV(i, uv)).a;
+					var a = weightTextures.get(vec3(uv, i)).r;
+					if(h * a > curWeight){
+						curTexIndex = i;
+						curWeight = h * a;
+						curUV = getsurfaceUV(i, uv).xy;
+					}
+				}
+				var albedo = albedoTextures.get(vec3(curUV, curTexIndex)).rgb;
+				var normal = unpackNormal(normalTextures.get(vec3(curUV, curTexIndex)).rgba);
+				var pbr = pbrTextures.get(vec3(curUV, curTexIndex)).rgba;
+
+				/*var albedo = albedoTextures.get(getsurfaceUV(curTexIndex)).rgb;
+				var normal = unpackNormal(normalTextures.get(getsurfaceUV(curTexIndex)).rgba);
+				var pbr = pbrTextures.get(getsurfaceUV(curTexIndex)).rgba;*/
 
-			//emissiveValue = heightMap.get(calculatedUV).r;
-			//pixelColor = vec4(calculatedUV.xy, 0,0);
+				var index : Int = int(surfaceIndexMap.get(calculatedUV).r * 255);
+				pixelColor = vec4(albedo, 1.0);
+				transformedNormal = normalize(normal) * TBN;
+				roughnessValue = 1 - pbr.g * pbr.g;
+				metalnessValue = pbr.r;
+				occlusionValue = pbr.b;
+				emissiveValue = 0;
+
+				if(curWeight <= 0) {
+					pixelColor = vec4(0,0,0, 1.0);
+					transformedNormal = vec3(0,0,1) * TBN;
+					roughnessValue = 1;
+					metalnessValue = 0;
+					occlusionValue = 1;
+					emissiveValue = 0;
+				}
+			}
+			else{
+				var albedo = vec3(0);
+				var normal = vec4(0);
+				var pbr = vec4(0);
+				for(i in 0...weightCount){
+					var a = weightTextures.get(vec3(calculatedUV, i)).r;
+					albedo += albedoTextures.get(getsurfaceUV(i, calculatedUV)).rgb * a;
+					pbr += pbrTextures.get(getsurfaceUV(i, calculatedUV)).rgba * a;
+					normal += normalTextures.get(getsurfaceUV(i, calculatedUV)).rgba * a;
+				}
+				normal = vec4(unpackNormal(normal), 0.0);
+				pixelColor = vec4(albedo, 0.0);
+				transformedNormal = normalize(normal.xyz) * TBN;
+				roughnessValue = 1 - pbr.g * pbr.g;
+				metalnessValue = pbr.r;
+				occlusionValue = pbr.b;
+				emissiveValue = 0;
+			}
+
+			// Tri-planar Mapping
+			/*var coords = vec3(input.position.xy / primSize, heightMap.get(terrainUV).r / primSize);
+			var blending = abs( worldNormal );
+			blending = normalize(max(blending, 0.00001)); // Force weights to sum to 1.0
+			var b = (blending.x + blending.y + blending.z);
+			blending /= vec3(b, b, b);
+			var xaxis = texture( albedoTextures, vec3(coords.yz, index));
+			var yaxis = texture( albedoTextures, vec3(coords.xz, index));
+			var zaxis = texture( albedoTextures, vec3(coords.xy, index));
+			// blend the results of the 3 planar projections.
+			var tex = xaxis * blending.x + yaxis * blending.y + zaxis * blending.z;
+			pixelColor = tex;*/
 
 			if(showGrid){
-				var edge = ((input.position.xy.mod(cellSize) / cellSize ) - 0.5) * 2.0;
-				edge = ceil(max(vec2(0), abs(edge) - 0.9));
-				emissiveValue = max(edge.x, edge.y);
+				var gridColor = vec4(1,0,0,1);
+				var tileEdgeColor = vec4(1,1,0,1);
+				var grid = ((input.position.xy.mod(cellSize) / cellSize ) - 0.5) * 2.0;
+				grid = ceil(max(vec2(0), abs(grid) - 0.9));
+				var tileEdge = max( (1 - ceil(input.position.xy / primSize - 0.1 / (primSize / cellSize) )), floor(input.position.xy / primSize + 0.1 / (primSize / cellSize)));
+				emissiveValue = max(max(grid.x, grid.y), max(tileEdge.x, tileEdge.y));
+				pixelColor = mix( pixelColor, gridColor, clamp(0,1,max(grid.x, grid.y)));
+				pixelColor = mix( pixelColor, tileEdgeColor, clamp(0,1,max(tileEdge.x, tileEdge.y)));
+				metalnessValue =  mix(metalnessValue, 0, emissiveValue);
+				roughnessValue = mix(roughnessValue, 1, emissiveValue);
+				occlusionValue = mix(occlusionValue, 1, emissiveValue);
+				transformedNormal = mix(transformedNormal, vec3(0,0,1), emissiveValue);
 			}
 		}
-
 	};
 }
 

+ 17 - 0
hxd/prefab/ContextShared.hx

@@ -77,6 +77,10 @@ class ContextShared {
 		return cache.loadTexture(null, path);
 	}
 
+	public function loadBytes( file : String) : haxe.io.Bytes {
+		return try hxd.res.Loader.currentInstance.load(file).entry.getBytes() catch( e : hxd.res.NotFound ) null;
+	}
+
 	public function loadBakedBytes( file : String ) {
 		if( bakedData == null ) loadBakedData();
 		return bakedData.get(file);
@@ -115,6 +119,19 @@ class ContextShared {
 		saveBakedFile(bytes.getBytes());
 	}
 
+	public function saveTexture( file : String, bytes : haxe.io.Bytes , dir : String, ext : String) {
+		var path = new haxe.io.Path("");
+		path.dir = dir + "/";
+		path.file = file;
+		path.ext = ext;
+
+		if(!sys.FileSystem.isDirectory( hide.Ide.inst.getPath(dir)))
+			sys.FileSystem.createDirectory( hide.Ide.inst.getPath(dir));
+
+		var file = hide.Ide.inst.getPath(path.toString());
+		sys.io.File.saveBytes(file, bytes);
+	}
+
 	function saveBakedFile( bytes : haxe.io.Bytes ) {
 		throw "Don't know how to save baked file";
 	}