فهرست منبع

Fix support for normal maps in World/BigTexture

trethaller 7 سال پیش
والد
کامیت
6f68ff01aa
2فایلهای تغییر یافته به همراه62 افزوده شده و 13 حذف شده
  1. 13 2
      h3d/mat/BigTexture.hx
  2. 49 11
      h3d/scene/World.hx

+ 13 - 2
h3d/mat/BigTexture.hx

@@ -8,6 +8,12 @@ class BigTextureElement {
 	public var dv : Float;
 	public var dv : Float;
 	public var su : Float;
 	public var su : Float;
 	public var sv : Float;
 	public var sv : Float;
+
+	public var width(get, never) : Int;
+	function get_width() { return q.width; }
+	public var height(get, never) : Int;
+	function get_height() { return q.height; }
+
 	public function new(t, q, du, dv, su, sv) {
 	public function new(t, q, du, dv, su, sv) {
 		this.t = t;
 		this.t = t;
 		this.q = q;
 		this.q = q;
@@ -69,10 +75,12 @@ class BigTexture {
 	var pending : Array<{ t : hxd.res.Image, q : QuadTree, alpha : Bool, skip : Bool }>;
 	var pending : Array<{ t : hxd.res.Image, q : QuadTree, alpha : Bool, skip : Bool }>;
 	var waitTimer : haxe.Timer;
 	var waitTimer : haxe.Timer;
 	var lastEvent : Float;
 	var lastEvent : Float;
+	var bgColor : Int;
 
 
 	public function new(id, size, bgColor = 0xFF8080FF, ?allocPos : h3d.impl.AllocPos ) {
 	public function new(id, size, bgColor = 0xFF8080FF, ?allocPos : h3d.impl.AllocPos ) {
 		this.id = id;
 		this.id = id;
 		this.size = size;
 		this.size = size;
+		this.bgColor = bgColor;
 		space = new QuadTree(0,0,size,size);
 		space = new QuadTree(0,0,size,size);
 		tex = new h3d.mat.Texture(1, 1, allocPos);
 		tex = new h3d.mat.Texture(1, 1, allocPos);
 		tex.flags.set(Serialize);
 		tex.flags.set(Serialize);
@@ -134,7 +142,7 @@ class BigTexture {
 		return split(q.tl, sw, sh, rw, rh);
 		return split(q.tl, sw, sh, rw, rh);
 	}
 	}
 
 
-	function allocPos( w : Int, h : Int ) {
+	public function allocPos( w : Int, h : Int ) {
 		var q = findBest(space, w, h);
 		var q = findBest(space, w, h);
 		if( q == null )
 		if( q == null )
 			return null;
 			return null;
@@ -258,8 +266,11 @@ class BigTexture {
 		if( isDone )
 		if( isDone )
 			return;
 			return;
 		isDone = true;
 		isDone = true;
-		if( allPixels == null )
+		if( allPixels == null ) {
 			allPixels = hxd.Pixels.alloc(size, size, h3d.mat.Texture.nativeFormat);
 			allPixels = hxd.Pixels.alloc(size, size, h3d.mat.Texture.nativeFormat);
+			if(bgColor != 0)
+				allPixels.clear(bgColor);
+		}
 		// start loading all
 		// start loading all
 		function loadRec(q:QuadTree) {
 		function loadRec(q:QuadTree) {
 			if( q == null )
 			if( q == null )

+ 49 - 11
h3d/scene/World.hx

@@ -112,7 +112,7 @@ class World extends Object {
 	/*
 	/*
 		For each texture loaded, will call resolveNormalMap and have separate normal texture.
 		For each texture loaded, will call resolveNormalMap and have separate normal texture.
 	*/
 	*/
-	public var enableNormals = false;
+	public var enableNormalMaps = false;
 	/*
 	/*
 		When enableSpecular=true, will store the specular value in the alpha channel instead of a different texture.
 		When enableSpecular=true, will store the specular value in the alpha channel instead of a different texture.
 		This will erase alpha value of transparent textures, so should only be used if specular is only on opaque models.
 		This will erase alpha value of transparent textures, so should only be used if specular is only on opaque models.
@@ -121,7 +121,10 @@ class World extends Object {
 
 
 	var worldStride : Int;
 	var worldStride : Int;
 	var bigTextureSize = 2048;
 	var bigTextureSize = 2048;
-	var bigTextureBG = 0xFF8080FF;
+	var defaultDiffuseBG = 0;
+	var defaultNormalBG = 0x8080FF;
+	var defaultSpecularBG = 0;
+
 	var soilColor = 0x408020;
 	var soilColor = 0x408020;
 	var chunks : Array<WorldChunk>;
 	var chunks : Array<WorldChunk>;
 	var allChunks : Array<WorldChunk>;
 	var allChunks : Array<WorldChunk>;
@@ -151,14 +154,20 @@ class World extends Object {
 	}
 	}
 
 
 	function buildFormat() {
 	function buildFormat() {
-		return {
+		var r = {
 			fmt : [
 			fmt : [
 				new hxd.fmt.hmd.Data.GeometryFormat("position", DVec3),
 				new hxd.fmt.hmd.Data.GeometryFormat("position", DVec3),
 				new hxd.fmt.hmd.Data.GeometryFormat("normal", DVec3),
 				new hxd.fmt.hmd.Data.GeometryFormat("normal", DVec3),
-				new hxd.fmt.hmd.Data.GeometryFormat("uv", DVec2),
 			],
 			],
-			defaults : [],
+			defaults : [null, new h3d.Vector(0,0,1)],
 		};
 		};
+		if(enableNormalMaps) {
+			r.fmt.push(new hxd.fmt.hmd.Data.GeometryFormat("tangent", DVec3));
+			r.defaults.push(new h3d.Vector(1,0,0));
+		}
+		r.fmt.push(new hxd.fmt.hmd.Data.GeometryFormat("uv", DVec2));
+		r.defaults.push(null);
+		return r;
 	}
 	}
 
 
 	function getBlend( r : hxd.res.Image ) : h3d.mat.BlendMode {
 	function getBlend( r : hxd.res.Image ) : h3d.mat.BlendMode {
@@ -213,16 +222,25 @@ class World extends Object {
 			}
 			}
 		}
 		}
 		if( t == null ) {
 		if( t == null ) {
-			var b = new h3d.mat.BigTexture(bigTextures.length, bigTextureSize, bigTextureBG);
+			var b = new h3d.mat.BigTexture(bigTextures.length, bigTextureSize, defaultDiffuseBG);
 			btex = { diffuse : b, spec : null, normal : null };
 			btex = { diffuse : b, spec : null, normal : null };
 			bigTextures.unshift( btex );
 			bigTextures.unshift( btex );
 			t = b.add(rt);
 			t = b.add(rt);
 			if( t == null ) throw "Texture " + texturePath + " is too big";
 			if( t == null ) throw "Texture " + texturePath + " is too big";
 		}
 		}
 
 
+		inline function checkSize(res:hxd.res.Image) {
+			if(res != null) {
+				var size = res.getSize();
+				if(size.width != t.width || size.height != t.height)
+					throw 'Texture ${res.entry.path} has different size from diffuse (${size.width}x${size.height})';
+			}
+		}
+
 		var specTex = null;
 		var specTex = null;
 		if( enableSpecular ) {
 		if( enableSpecular ) {
 			var res = resolveSpecularTexture(texturePath, mat);
 			var res = resolveSpecularTexture(texturePath, mat);
+			checkSize(res);
 			if( specularInAlpha ) {
 			if( specularInAlpha ) {
 				if( res != null ) {
 				if( res != null ) {
 					t.setAlpha(res);
 					t.setAlpha(res);
@@ -230,23 +248,24 @@ class World extends Object {
 				}
 				}
 			} else {
 			} else {
 				if( btex.spec == null )
 				if( btex.spec == null )
-					btex.spec = new h3d.mat.BigTexture(-1, bigTextureSize, bigTextureBG);
+					btex.spec = new h3d.mat.BigTexture(-1, bigTextureSize, defaultSpecularBG);
 				if( res != null )
 				if( res != null )
 					specTex = btex.spec.add(res);
 					specTex = btex.spec.add(res);
 				else
 				else
-					@:privateAccess btex.spec.allocPos(t.t.tex.width, t.t.tex.height); // keep UV in-sync
+					btex.spec.allocPos(t.width, t.height); // keep UV in-sync
 			}
 			}
 		}
 		}
 
 
 		var normalMap = null;
 		var normalMap = null;
-		if( enableNormals ) {
+		if( enableNormalMaps ) {
 			var res = resolveNormalMap(texturePath, mat);
 			var res = resolveNormalMap(texturePath, mat);
+			checkSize(res);
 			if( btex.normal == null )
 			if( btex.normal == null )
-				btex.normal = new h3d.mat.BigTexture(-1, bigTextureSize, bigTextureBG);
+				btex.normal = new h3d.mat.BigTexture(-1, bigTextureSize, defaultNormalBG);
 			if( res != null )
 			if( res != null )
 				normalMap = btex.normal.add(res);
 				normalMap = btex.normal.add(res);
 			else
 			else
-				@:privateAccess btex.normal.allocPos(t.t.tex.width, t.t.tex.height); // keep UV in-sync
+				btex.normal.allocPos(t.width, t.height); // keep UV in-sync
 		}
 		}
 
 
 		var m = new WorldMaterial();
 		var m = new WorldMaterial();
@@ -311,6 +330,9 @@ class World extends Object {
 				var vl = data.vertexes;
 				var vl = data.vertexes;
 				var p = 0;
 				var p = 0;
 				var extra = model.stride - 8;
 				var extra = model.stride - 8;
+				if(enableNormalMaps)
+					extra -= 3;
+
 				for( i in 0...m.vertexCount ) {
 				for( i in 0...m.vertexCount ) {
 					var x = vl[p++];
 					var x = vl[p++];
 					var y = vl[p++];
 					var y = vl[p++];
@@ -318,6 +340,12 @@ class World extends Object {
 					var nx = vl[p++];
 					var nx = vl[p++];
 					var ny = vl[p++];
 					var ny = vl[p++];
 					var nz = vl[p++];
 					var nz = vl[p++];
+					var tx = 0., ty = 0., tz = 0.;
+					if(enableNormalMaps) {
+						tx = vl[p++];
+						ty = vl[p++];
+						tz = vl[p++];
+					}
 					var u = vl[p++];
 					var u = vl[p++];
 					var v = vl[p++];
 					var v = vl[p++];
 
 
@@ -337,6 +365,16 @@ class World extends Object {
 					model.buf.push(n.y * len);
 					model.buf.push(n.y * len);
 					model.buf.push(n.z * len);
 					model.buf.push(n.z * len);
 
 
+					if( enableNormalMaps ) {
+						var t = new h3d.Vector(tx, ty, tz);
+						var tlen = t.length();
+						t.transform3x3(pos);
+						var len = tlen * hxd.Math.invSqrt(n.lengthSq());
+						model.buf.push(t.x * len);
+						model.buf.push(t.y * len);
+						model.buf.push(t.z * len);
+					}
+
 					// uv
 					// uv
 					model.buf.push(u * wmat.t.su + wmat.t.du);
 					model.buf.push(u * wmat.t.su + wmat.t.du);
 					model.buf.push(v * wmat.t.sv + wmat.t.dv);
 					model.buf.push(v * wmat.t.sv + wmat.t.dv);