Selaa lähdekoodia

Update Terrain

ShiroSmith 7 vuotta sitten
vanhempi
commit
b2dea05c2d
3 muutettua tiedostoa jossa 124 lisäystä ja 73 poistoa
  1. 23 5
      h3d/scene/pbr/terrain/Terrain.hx
  2. 85 50
      h3d/scene/pbr/terrain/Tile.hx
  3. 16 18
      h3d/shader/pbr/Terrain.hx

+ 23 - 5
h3d/scene/pbr/terrain/Terrain.hx

@@ -92,21 +92,17 @@ class Terrain extends Object {
 		grid = new h3d.prim.Grid( cellCount, cellCount, cellSize, cellSize);
 		grid.addUVs();
 		grid.addNormals();
-
 		for(tile in tiles){
 			tile.x = tile.tileX * tileSize;
 			tile.y = tile.tileY * tileSize;
 			tile.refreshMesh();
 		}
-
-		for(tile in tiles){
+		for(tile in tiles)
 			tile.blendEdges();
-		}
 	}
 
 	public function refreshTex(){
 		for(tile in tiles){
-			tile.surfaceCount = surfaces.length;
 			tile.refresh();
 		}
 	}
@@ -126,6 +122,22 @@ class Terrain extends Object {
 		return tile;
 	}
 
+	public function addTile(tile : Tile, ?replace = false){
+		for(t in tiles){
+			if(tile == t) return;
+			if(tile.tileX == t.tileX && tile.tileY == t.tileY){
+				if(replace){
+					removeTile(t);
+					break;
+				}else
+					return;
+			}
+		}
+		tile.parent = this;
+		tiles.push(tile);
+		addChild(tile);
+	}
+
 	public function removeTileAt(x : Int, y : Int) : Bool {
 		var t = getTile(x,y);
 		if(t == null){
@@ -142,6 +154,12 @@ class Terrain extends Object {
 		return r;
 	}
 
+	public function getTileIndex(t : Tile) : Int {
+		for(i in 0 ... tiles.length)
+			if(t == tiles[i]) return i;
+		return -1;
+	}
+
 	public function getTile(x : Int, y : Int) : Tile {
 		var result : Tile = null;
 		for(tile in tiles)

+ 85 - 50
h3d/scene/pbr/terrain/Tile.hx

@@ -1,19 +1,22 @@
 package h3d.scene.pbr.terrain;
 
+enum Direction{
+	Up; Down; Left; Right; UpLeft; UpRight; DownLeft; DownRight;
+}
+
 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 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 var grid (default, null) : h3d.prim.Grid;
 	public var needAlloc = false;
-	var heightmapPixels : hxd.Pixels.PixelsFloat;
 	public var needNewPixelCapture = false;
+	var heightmapPixels : hxd.Pixels.PixelsFloat;
+	var shader : h3d.shader.pbr.Terrain;
 
 	public function new(x : Int, y : Int , ?parent){
 		super(null, null, parent);
@@ -24,7 +27,6 @@ class Tile extends h3d.scene.Mesh {
 		material.mainPass.culling = None;
 		this.x = x * getTerrain().tileSize;
 		this.y = y * getTerrain().tileSize;
-		this.surfaceCount = getTerrain().surfaces.length;
 		refreshMesh();
 	}
 
@@ -33,6 +35,10 @@ class Tile extends h3d.scene.Mesh {
 		return heightMap = v;
 	}
 
+	inline function getTerrain(){
+		return Std.instance(parent, Terrain);
+	}
+
 	public function getHeightPixels(){
 		if(needNewPixelCapture || heightmapPixels == null)
 			heightmapPixels = heightMap.capturePixels();
@@ -50,8 +56,32 @@ class Tile extends h3d.scene.Mesh {
 		computeNormals();
 	}
 
-	public function blendEdges(?propagate = false){
-		computeEdgesHeight();
+	public function blendEdges(){
+		var adjTileX = getTerrain().getTile(tileX - 1, tileY);
+		if( adjTileX != null){
+			var flags = new haxe.EnumFlags<Direction>();
+        	flags.set(Left);
+			adjTileX.computeEdgesHeight(flags);
+		}
+		var adjTileY = getTerrain().getTile(tileX, tileY - 1);
+		if( adjTileY != null){
+			var flags = new haxe.EnumFlags<Direction>();
+        	flags.set(Up);
+			adjTileY.computeEdgesHeight(flags);
+		}
+		var adjTileXY = getTerrain().getTile(tileX - 1, tileY - 1);
+		if( adjTileXY != null){
+			var flags = new haxe.EnumFlags<Direction>();
+        	flags.set(UpLeft);
+			adjTileXY.computeEdgesHeight(flags);
+		}
+		var flags = new haxe.EnumFlags<Direction>();
+        flags.set(Left);
+		flags.set(Up);
+		flags.set(UpLeft);
+		computeEdgesHeight(flags);
+		computeNormals();
+
 		computeEdgesNormals();
 	}
 
@@ -77,11 +107,10 @@ class Tile extends h3d.scene.Mesh {
 			}
 		}
 
-		if(surfaceWeights.length != surfaceCount || surfaceWeights[0].width != getTerrain().weightMapResolution){
+		if(surfaceWeights.length != getTerrain().surfaces.length || surfaceWeights[0].width != getTerrain().weightMapResolution){
 			var oldArray = surfaceWeights;
 			surfaceWeights = new Array<h3d.mat.Texture>();
-			//surfaceWeights.resize(surfaceCount);
-			surfaceWeights = [for (i in 0...surfaceCount) null];
+			surfaceWeights = [for (i in 0...getTerrain().surfaces.length) null];
 			for(i in 0 ... surfaceWeights.length){
 				surfaceWeights[i] = new h3d.mat.Texture(getTerrain().weightMapResolution, getTerrain().weightMapResolution, [Target], R8);
 				surfaceWeights[i].wrap = Clamp;
@@ -104,33 +133,42 @@ class Tile extends h3d.scene.Mesh {
 			if(surfaceWeights[i] != null) getTerrain().copyPass.apply(surfaceWeights[i], surfaceWeightArray, None, null, i);
 	}
 
-	public function computeEdgesHeight(){
+	public function computeEdgesHeight(flag : haxe.EnumFlags<Direction>){
+
 		if(heightMap == null) return;
 		var pixels : hxd.Pixels.PixelsFloat = getHeightPixels();
-		var adjTileX = getTerrain().getTile(tileX + 1, tileY);
-		var adjHeightMapX = adjTileX != null ? adjTileX.heightMap : null;
-		if(adjHeightMapX != null){
-			var adjpixels : hxd.Pixels.PixelsFloat = adjTileX.getHeightPixels();
-			for( i in 0 ... heightMap.height - 1){
-				pixels.setPixelF(heightMap.width - 1, i, adjpixels.getPixelF(0,i) );
+
+		if(flag.has(Left)){
+			var adjTileX = getTerrain().getTile(tileX + 1, tileY);
+			var adjHeightMapX = adjTileX != null ? adjTileX.heightMap : null;
+			if(adjHeightMapX != null){
+				var adjpixels : hxd.Pixels.PixelsFloat = adjTileX.getHeightPixels();
+				for( i in 0 ... heightMap.height - 1){
+					pixels.setPixelF(heightMap.width - 1, i, adjpixels.getPixelF(0,i) );
+				}
 			}
 		}
-		var adjTileY = getTerrain().getTile(tileX, tileY + 1);
-		var adjHeightMapY = adjTileY != null ? adjTileY.heightMap : null;
-		if(adjHeightMapY != null){
-			var adjpixels : hxd.Pixels.PixelsFloat = adjTileY.getHeightPixels();
-			for( i in 0 ... heightMap.width - 1){
-				pixels.setPixelF(i, heightMap.height - 1, adjpixels.getPixelF(i,0) );
+		if(flag.has(Up)){
+			var adjTileY = getTerrain().getTile(tileX, tileY + 1);
+			var adjHeightMapY = adjTileY != null ? adjTileY.heightMap : null;
+			if(adjHeightMapY != null){
+				var adjpixels : hxd.Pixels.PixelsFloat = adjTileY.getHeightPixels();
+				for( i in 0 ... heightMap.width - 1){
+					pixels.setPixelF(i, heightMap.height - 1, adjpixels.getPixelF(i,0) );
+				}
 			}
 		}
-		var adjTileXY = getTerrain().getTile(tileX + 1, tileY + 1);
-		var adjHeightMapXY = adjTileXY != null ? adjTileXY.heightMap : null;
-		if(adjHeightMapXY != null){
-			var adjpixels : hxd.Pixels.PixelsFloat = adjTileXY.getHeightPixels();
-			pixels.setPixelF(heightMap.width - 1, heightMap.height - 1, adjpixels.getPixelF(0,0));
+		if(flag.has(UpLeft)){
+			var adjTileXY = getTerrain().getTile(tileX + 1, tileY + 1);
+			var adjHeightMapXY = adjTileXY != null ? adjTileXY.heightMap : null;
+			if(adjHeightMapXY != null){
+				var adjpixels : hxd.Pixels.PixelsFloat = adjTileXY.getHeightPixels();
+				pixels.setPixelF(heightMap.width - 1, heightMap.height - 1, adjpixels.getPixelF(0,0));
+			}
 		}
 		heightmapPixels = pixels;
 		heightMap.uploadPixels(pixels);
+		needNewPixelCapture = false;
 	}
 
 	public function computeEdgesNormals(){
@@ -144,11 +182,10 @@ class Tile extends h3d.scene.Mesh {
 		var i0, i1, i2 : Int = 0;
 
 		inline function computeVertexPos(tile : Tile){
-			var pixels : hxd.Pixels.PixelsFloat = tile.getHeightPixels();
 			t0.load(tile.grid.points[i0]); t1.load(tile.grid.points[i1]); t2.load(tile.grid.points[i2]);
-			t0.z += tile.getHeight(t0.x / getTerrain().tileSize, t0.y / getTerrain().tileSize, pixels);
-			t1.z += tile.getHeight(t1.x / getTerrain().tileSize, t1.y / getTerrain().tileSize, pixels);
-			t2.z += tile.getHeight(t2.x / getTerrain().tileSize, t2.y / getTerrain().tileSize, pixels);
+			t0.z += tile.getHeight(t0.x / getTerrain().tileSize, t0.y / getTerrain().tileSize);
+			t1.z += tile.getHeight(t1.x / getTerrain().tileSize, t1.y / getTerrain().tileSize);
+			t2.z += tile.getHeight(t2.x / getTerrain().tileSize, t2.y / getTerrain().tileSize);
 		}
 
 		inline function computeNormal() : h3d.col.Point {
@@ -359,13 +396,10 @@ class Tile extends h3d.scene.Mesh {
 		if(adjDownLeftTile != null) adjDownLeftTile.needAlloc = true;
 		if(adjUpRightTile != null) adjUpRightTile.needAlloc = true;
 		if(adjDownRightTile != null) adjDownRightTile.needAlloc = true;
-		needAlloc = true;
+		this.needAlloc = true;
 	}
 
 	public function computeNormals(){
-		var pixels : hxd.Pixels.PixelsFloat = null;
-		if(heightMap != null)
-			pixels = getHeightPixels();
 		if(grid.normals == null) grid.normals = new Array<h3d.col.Point>();
 		grid.normals = [
 		for (i in 0...grid.points.length){
@@ -386,10 +420,10 @@ class Tile extends h3d.scene.Mesh {
 				i0 = grid.idx[pos++]; i1 = grid.idx[pos++]; i2 = grid.idx[pos++];
 			}
 			t0.load(grid.points[i0]); t1.load(grid.points[i1]); t2.load(grid.points[i2]);
-			if(pixels != null){
-				t0.z += getHeight(t0.x / getTerrain().tileSize, t0.y / getTerrain().tileSize, pixels);
-				t1.z += getHeight(t1.x / getTerrain().tileSize, t1.y / getTerrain().tileSize, pixels);
-				t2.z += getHeight(t2.x / getTerrain().tileSize, t2.y / getTerrain().tileSize, pixels);
+			if(heightMap != null){
+				t0.z += getHeight(t0.x / getTerrain().tileSize, t0.y / getTerrain().tileSize);
+				t1.z += getHeight(t1.x / getTerrain().tileSize, t1.y / getTerrain().tileSize);
+				t2.z += getHeight(t2.x / getTerrain().tileSize, t2.y / getTerrain().tileSize);
 			}
 			var n1 = t1.sub(t0);
 			n1.normalize();
@@ -406,7 +440,8 @@ class Tile extends h3d.scene.Mesh {
 		needAlloc = true;
 	}
 
-	function getHeight(u : Float, v : Float, pixels : hxd.Pixels.PixelsFloat ){
+	public function getHeight(u : Float, v : Float){
+		var pixels = getHeightPixels();
 		if(heightMap.filter == Linear){
 			var coordsX = hxd.Math.max(0, u * (heightMap.width - 1) - 0.5);
 			var coordsY =  hxd.Math.max(0, v * (heightMap.width - 1) - 0.5);
@@ -436,8 +471,10 @@ class Tile extends h3d.scene.Mesh {
 	}
 
 	override function emit(ctx:RenderContext){
-		if( getTerrain().surfaceArray == null) return;
+		if( getTerrain().surfaceArray == null || getTerrain().surfaces.length == 0) return;
 		var bounds = getBounds();
+		bounds.zMax = 10000;
+		bounds.zMin = -10000;
 		if(bounds != null){
 			if(ctx.camera.getFrustum().hasBounds(bounds))
 				super.emit(ctx);
@@ -446,18 +483,20 @@ class Tile extends h3d.scene.Mesh {
 	}
 
 	override function sync(ctx:RenderContext) {
-		if( getTerrain().surfaceArray == null) return;
-		shader.heightMap = heightMap;
+		shader.SHOW_GRID = getTerrain().showGrid;
+		shader.SURFACE_COUNT = getTerrain().surfaces.length;
+
 		shader.heightMapSize = heightMap.width;
 		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.heightMap = heightMap;
+		shader.surfaceIndexMap = surfaceIndexMap;
+
 		shader.surfaceParams = getTerrain().surfaceArray.params;
 		shader.secondSurfaceParams = getTerrain().surfaceArray.secondParams;
 		shader.tileIndex = new h3d.Vector(tileX, tileY);
@@ -467,8 +506,4 @@ class Tile extends h3d.scene.Mesh {
 		shader.heightBlendStrength = getTerrain().heightBlendStrength;
 		shader.heightBlendSharpness = getTerrain().heightBlendSharpness;
 	}
-
-	inline function getTerrain(){
-		return Std.instance(parent, Terrain);
-	}
 }

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

@@ -5,11 +5,10 @@ class Terrain extends hxsl.Shader {
 	static var SRC = {
 
 		@:import h3d.shader.BaseMesh;
+		@const var SHOW_GRID : Bool;
+		@const var SURFACE_COUNT : Int;
 
-		@param var previewTex : Sampler2D;
-		@param var heightMap : Sampler2D;
 		@param var heightMapSize : Float;
-		@param var surfaceIndexMap : Sampler2D;
 		@param var primSize : Float;
 		@param var cellSize : Float;
 
@@ -17,24 +16,22 @@ class Terrain extends hxsl.Shader {
 		@param var normalTextures : Sampler2DArray;
 		@param var pbrTextures : Sampler2DArray;
 		@param var weightTextures : Sampler2DArray;
-		@param var weightCount : Int;
+		@param var surfaceIndexMap : Sampler2D;
+		@param var heightMap : Sampler2D;
+		@param var surfaceParams : Array<Vec4, SURFACE_COUNT>;
+		@param var secondSurfaceParams : Array<Vec4, SURFACE_COUNT>;
+
 		@param var heightBlendStrength : Float;
 		@param var heightBlendSharpness : Float;
-
 		@param var parallaxAmount : Float;
 		@param var minStep : Int;
 		@param var maxStep : Int;
-
-		@param var surfaceParams : Array<Vec4, 8>;
-		@param var secondSurfaceParams : Array<Vec4, 8>;
 		@param var tileIndex : Vec2;
 
-		@const var showGrid : Bool;
-
 		var calculatedUV : Vec2;
 		var terrainUV : Vec2;
 		var TBN : Mat3;
-		var worldNormal : Vec3;
+
 		var emissiveValue : Float;
 		var metalnessValue : Float;
 		var roughnessValue : Float;
@@ -117,7 +114,7 @@ class Terrain extends hxsl.Shader {
 			var albedo = vec3(0);
 			var normal = vec4(0,0,0,0);
 			var pbr = vec4(0);
-			var weightSum = 0 + heightBlendSharpness * 0;
+			var weightSum = 0.0;
 
 			// Keep the surface with the heightest weight for sharpness
 			var maxAlbedo = vec3(0);
@@ -146,17 +143,17 @@ class Terrain extends hxsl.Shader {
 			normal /= vec4(weightSum);
 
 			// Find the max
-			var maxW = clamp(ceil(b1 - curMaxWeight), 0 ,1);
+			var maxW = clamp(ceil(b1 - curMaxWeight), 0, 1);
 			curMaxWeight = mix(curMaxWeight, b1, maxW);
 			maxAlbedo = mix(maxAlbedo, albedo1, maxW);
 			maxPbr = mix(maxPbr, pbr1, maxW);
 			maxNormal = mix(maxNormal, normal1, maxW);
-			maxW = clamp(ceil(b2 - curMaxWeight), 0 ,1);
+			maxW = clamp(ceil(b2 - curMaxWeight), 0, 1);
 			curMaxWeight = mix(curMaxWeight, b2, maxW);
 			maxAlbedo = mix(maxAlbedo, albedo2, maxW);
 			maxPbr = mix(maxPbr, pbr2, maxW);
 			maxNormal = mix(maxNormal, normal2, maxW);
-			maxW = clamp(ceil(b3 - curMaxWeight), 0 ,1);
+			maxW = clamp(ceil(b3 - curMaxWeight), 0,1);
 			curMaxWeight = mix(curMaxWeight, b3, maxW);
 			maxAlbedo = mix(maxAlbedo, albedo3, maxW);
 			maxPbr = mix(maxPbr, pbr3, maxW);
@@ -164,19 +161,19 @@ class Terrain extends hxsl.Shader {
 
 			// Sharpness
 			albedo = mix(albedo, maxAlbedo, heightBlendSharpness);
-			pbr = mix(normal, maxPbr, heightBlendSharpness);
+			pbr = mix(pbr, maxPbr, heightBlendSharpness);
 			normal = mix(normal, maxNormal, heightBlendSharpness);
 
 			// Output
 			normal = vec4(unpackNormal(normal), 0.0);
-			pixelColor = vec4(albedo, 0.0);
+			pixelColor = vec4(albedo, 1.0);
 			transformedNormal = normalize(normal.xyz) * TBN;
 			roughnessValue = 1 - pbr.g * pbr.g;
 			metalnessValue = pbr.r;
 			occlusionValue = pbr.b;
 			emissiveValue = 0;
 
-			if(showGrid){
+			if(SHOW_GRID){
 				var gridColor = vec4(1,0,0,1);
 				var tileEdgeColor = vec4(1,1,0,1);
 				var grid : Vec2 = ((input.position.xy.mod(cellSize) / cellSize ) - 0.5) * 2.0;
@@ -192,5 +189,6 @@ class Terrain extends hxsl.Shader {
 			}
 		}
 	};
+
 }