浏览代码

- Add terrain ( not def )

ShiroSmith 7 年之前
父节点
当前提交
f8d8be7f7b
共有 7 个文件被更改,包括 271 次插入6 次删除
  1. 2 0
      h2d/BlendMode.hx
  2. 1 1
      h2d/Drawable.hx
  3. 1 1
      h3d/mat/Material.hx
  4. 16 0
      h3d/mat/Pass.hx
  5. 175 0
      h3d/scene/pbr/Terrain.hx
  6. 16 4
      h3d/shader/pbr/PropsValues.hx
  7. 60 0
      h3d/shader/pbr/Terrain.hx

+ 2 - 0
h2d/BlendMode.hx

@@ -9,4 +9,6 @@ enum BlendMode {
 	Multiply;
 	Erase;
 	Screen;
+	Sub;
+	Max;
 }

+ 1 - 1
h2d/Drawable.hx

@@ -10,7 +10,7 @@ typedef ColorAdjust = {
 
 class Drawable extends Sprite {
 
-	public var color(default,null) : h3d.Vector;
+	public var color(default,default) : h3d.Vector;
 	public var blendMode : BlendMode;
 	public var smooth : Null<Bool>;
 	public var tileWrap(default, set) : Bool;

+ 1 - 1
h3d/mat/Material.hx

@@ -138,7 +138,7 @@ class Material extends BaseMaterial {
 			case Alpha:
 				mainPass.depthWrite = true;
 				mainPass.setPassName("alpha");
-			case Add, AlphaAdd, SoftAdd, Multiply, Erase, Screen:
+			case Add, AlphaAdd, SoftAdd, Multiply, Erase, Screen, Sub, Max:
 				mainPass.depthWrite = false;
 				mainPass.setPassName("additive");
 			}

+ 16 - 0
h3d/mat/Pass.hx

@@ -88,20 +88,36 @@ class Pass implements hxd.impl.Serializable {
 		switch( b ) {
 		case None:
 			blend(One, Zero);
+			blendOp = Add;
 		case Alpha:
 			blend(SrcAlpha, OneMinusSrcAlpha);
+			blendOp = Add;
 		case Add:
 			blend(SrcAlpha, One);
+			blendOp = Add;
 		case AlphaAdd:
 			blend(One, OneMinusSrcAlpha);
+			blendOp = Add;
 		case SoftAdd:
 			blend(OneMinusDstColor, One);
+			blendOp = Add;
 		case Multiply:
 			blend(DstColor, Zero);
 		case Erase:
 			blend(Zero, OneMinusSrcColor);
+			blendOp = Add;
 		case Screen:
 			blend(One, OneMinusSrcColor);
+			blendOp = Add;
+		case Sub:
+			blend(SrcAlpha, One);
+			blendOp = ReverseSub;
+		case Max:
+			this.blendSrc = SrcColor;
+			this.blendAlphaSrc = SrcAlpha;
+			this.blendDst = DstColor;
+			this.blendAlphaDst = DstAlpha;
+			blendOp = Max;
 		}
 	}
 

+ 175 - 0
h3d/scene/pbr/Terrain.hx

@@ -0,0 +1,175 @@
+package h3d.scene.pbr;
+
+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 surfaceCount = 0;
+	public var surfaceWeights : Array<h3d.mat.Texture> = [];
+	var shader : h3d.shader.pbr.Terrain;
+
+	public function new(x : Int, y : Int , surfaceCount, prim, ?parent){
+		super(prim, 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;
+	}
+
+	function set_heightMap(v){
+		shader.heightMap = v;
+		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 override function dispose() {
+		if(heightMap != null) heightMap.dispose();
+		if(surfaceIndex != null) surfaceIndex.dispose();
+		for(i in 0 ... surfaceWeights.length) surfaceWeights[i].dispose();
+	}
+
+	override function emit(ctx:RenderContext){
+		var bounds = getBounds();
+		if(bounds != null){
+			if(ctx.camera.getFrustum().hasBounds(bounds))
+				super.emit(ctx);
+		}else
+			super.emit(ctx);
+	}
+
+	override function sync(ctx:RenderContext) {
+		shader.heightMap = heightMap;
+		shader.heightMapSize = getTerrain().heightMapResolution ;
+		shader.primSize = getTerrain().tileSize;
+		shader.cellSize = getTerrain().cellSize;
+		shader.showGrid = getTerrain().showGrid;
+	}
+
+	inline function getTerrain(){
+		return Std.instance(parent, Terrain);
+	}
+}
+
+class Surface {
+	public var index : Int;
+	public var albedo : h3d.mat.Texture;
+	public var normal : h3d.mat.Texture;
+	public var pbrTex : h3d.mat.Texture;
+}
+
+class Terrain extends Object {
+
+	public var tileSize = 1.0;
+	public var cellSize = 1.0;
+	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 function new(?parent){
+		super(parent);
+		grid = new h3d.prim.Grid( Math.floor(tileSize/cellSize), Math.floor(tileSize/cellSize), cellSize, cellSize);
+		grid.addUVs();
+		grid.addNormals();
+	}
+
+	public function refreshMesh(){
+		if(grid != null) grid.dispose();
+		grid = new h3d.prim.Grid( Math.floor(tileSize/cellSize), Math.floor(tileSize/cellSize), cellSize, cellSize);
+		grid.addUVs();
+		grid.addNormals();
+
+		for(tile in tiles){
+			tile.primitive = grid;
+			tile.x = tile.tileX * tileSize;
+			tile.y = tile.tileY * tileSize;
+		}
+	}
+
+	public function refreshTex(){
+		for(tile in tiles){
+			tile.surfaceCount = surfaces.length;
+			tile.initTex();
+		}
+	}
+
+	public function refresh(){
+		refreshMesh();
+		refreshTex();
+	}
+
+	public function createTile(x : Int, y : Int){
+		var tile = getTile(x,y);
+		if(tile == null){
+			tile = new Tile(x, y, surfaces.length, grid, this);
+			tile.initTex();
+			tiles.push(tile);
+		}
+		return tile;
+	}
+
+	public function getTile(x : Int, y : Int){
+		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){
+		var result : Tile = null;
+		var tileX = Math.floor(pos.x / tileSize);
+		var tileY = Math.floor(pos.y / tileSize);
+		for(tile in tiles)
+			if(tile.tileX == tileX && tile.tileY == tileY) result = tile;
+		return result;
+	}
+
+	public function createTileAtWorldPos(pos : h3d.Vector){
+		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){
+		if(create){
+			var maxTileX = Math.floor((pos.x + range)/ tileSize);
+			var minTileX = Math.floor((pos.x - range)/ tileSize);
+			var maxTileY = Math.floor((pos.y + range)/ tileSize);
+			var minTileY = Math.floor((pos.y - range)/ tileSize);
+
+			for( x in minTileX ... maxTileX + 1)
+				for( y in minTileY...maxTileY + 1)
+					createTile(x, y);
+		}
+
+		var result : Array<Tile> = [];
+		for(tile in tiles)
+			if( Math.abs(pos.x - (tile.tileX * tileSize + tileSize * 0.5)) <= range + (tileSize * 0.5)
+			&& Math.abs(pos.y - (tile.tileY * tileSize + tileSize * 0.5)) <= range + (tileSize * 0.5))
+				result.push(tile);
+		return result;
+	}
+}
+
+

+ 16 - 4
h3d/shader/pbr/PropsValues.hx

@@ -16,11 +16,23 @@ class PropsValues extends hxsl.Shader {
 		@param var occlusion : Float;
 		@param var emissive : Float;
 
+		var metalnessValue : Float;
+		var roughnessValue : Float;
+		var occlusionValue : Float;
+		var emissiveValue : Float;
+
+		function __init__() {
+			metalnessValue = metalness;
+			roughnessValue = roughness;
+			occlusionValue = occlusion;
+			emissiveValue = emissive;
+		}
+
 		function fragment() {
-			output.metalness = metalness;
-			output.roughness = roughness;
-			output.occlusion = occlusion;
-			output.emissive = emissive;
+			output.metalness = metalnessValue;
+			output.roughness = roughnessValue;
+			output.occlusion = occlusionValue;
+			output.emissive = emissiveValue;
 		}
 
 	};

+ 60 - 0
h3d/shader/pbr/Terrain.hx

@@ -0,0 +1,60 @@
+package h3d.shader.pbr;
+
+class Terrain extends hxsl.Shader {
+
+	static var SRC = {
+
+		@:import h3d.shader.BaseMesh;
+
+		@param var previewTex : Sampler2D;
+		@param var heightMap : Sampler2D;
+		@param var heightMapSize : Float;
+		@param var primSize : Float;
+		@param var cellSize : Float;
+
+		@const var usePreview : Bool;
+		@const var showGrid : Bool;
+
+		var calculatedUV : Vec2;
+
+		function getNormal(uv: Vec2) : Vec3 {
+			var offset = vec2(1.0/heightMapSize, 0);
+			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));
+			normal = (normal * global.modelView.mat3()).normalize();
+			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);
+		}
+
+		var emissiveValue : Float;
+		var metalnessValue : Float;
+		var roughnessValue : Float;
+		function fragment() {
+			if(usePreview) emissiveValue = previewTex.get(calculatedUV).r * 0.5;
+			else emissiveValue = 0;
+
+			metalnessValue = 0.0;
+			roughnessValue = 0.5;
+
+			//emissiveValue = heightMap.get(calculatedUV).r;
+			//pixelColor = vec4(calculatedUV.xy, 0,0);
+
+			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);
+			}
+		}
+
+	};
+}
+