浏览代码

added mikktspace tangent generation support

ncannasse 7 年之前
父节点
当前提交
f1fb0776f3
共有 5 个文件被更改,包括 151 次插入21 次删除
  1. 3 0
      .gitignore
  2. 108 21
      hxd/fmt/fbx/HMDOut.hx
  3. 34 0
      tools/mikktspace/Mikktspace.hx
  4. 4 0
      tools/mikktspace/build_msvc.bat
  5. 2 0
      tools/mikktspace/mikktspace.hxml

+ 3 - 0
.gitignore

@@ -2,6 +2,7 @@
 *.swf
 *.js
 *.js.map
+*.obj
 bin
 .tmp
 /hxd/net/inspect.min.css
@@ -9,3 +10,5 @@ bin
 /samples/build
 /*.xml
 .vscode
+/tools/mikktspace/out
+*.exe

+ 108 - 21
hxd/fmt/fbx/HMDOut.hx

@@ -34,7 +34,98 @@ class HMDOut extends BaseLibrary {
 		return true;
 	}
 
-	function buildGeom( geom : hxd.fmt.fbx.Geometry, skin : h3d.anim.Skin, dataOut : haxe.io.BytesOutput ) {
+	function buildTangents( geom : hxd.fmt.fbx.Geometry ) {
+		var verts = geom.getVertices();
+		var normals = geom.getNormals();
+		var uvs = geom.getUVs();
+		var index = geom.getIndexes();
+
+		#if (hl && !hl_disable_mikkt)
+		var m = new hl.Format.Mikktspace();
+		m.buffer = new hl.Bytes(8 * 4 * index.vidx.length);
+		m.stride = 8;
+		m.xPos = 0;
+		m.normalPos = 3;
+		m.uvPos = 6;
+
+		m.indexes = new hl.Bytes(4 * index.vidx.length);
+		m.indices = index.vidx.length;
+
+		m.tangents = new hl.Bytes(4 * 4 * index.vidx.length);
+		m.tangentStride = 4;
+		m.tangentPos = 0;
+
+		var out = 0;
+		for( i in 0...index.vidx.length ) {
+			var vidx = index.vidx[i];
+			m.buffer[out++] = verts[vidx*3];
+			m.buffer[out++] = verts[vidx*3+1];
+			m.buffer[out++] = verts[vidx*3+2];
+
+			m.buffer[out++] = normals[i*3];
+			m.buffer[out++] = normals[i*3+1];
+			m.buffer[out++] = normals[i*3+2];
+			var uidx = uvs[0].index[i];
+
+			m.buffer[out++] = uvs[0].values[uidx*2];
+			m.buffer[out++] = uvs[0].values[uidx*2+1];
+
+			m.indexes[i] = i;
+		}
+
+		m.compute();
+		return m.tangents;
+		#elseif (sys || nodejs)
+		var tmp = Sys.getEnv("TMPDIR");
+		if( tmp == null ) tmp = Sys.getEnv("TMP");
+		if( tmp == null ) tmp = Sys.getEnv("TEMP");
+		if( tmp == null ) tmp = ".";
+		var fileName = tmp+"/mikktspace_data"+Date.now().getTime()+"_"+Std.random(0x1000000)+".bin";
+		var outFile = fileName+".out";
+		var outputData = new haxe.io.BytesBuffer();
+		outputData.addInt32(index.vidx.length);
+		outputData.addInt32(8);
+		outputData.addInt32(0);
+		outputData.addInt32(3);
+		outputData.addInt32(6);
+		for( i in 0...index.vidx.length ) {
+			inline function w(v:Float) outputData.addFloat(v);
+			var vidx = index.vidx[i];
+			w(verts[vidx*3]);
+			w(verts[vidx*3+1]);
+			w(verts[vidx*3+2]);
+
+			w(normals[i*3]);
+			w(normals[i*3+1]);
+			w(normals[i*3+2]);
+			var uidx = uvs[0].index[i];
+
+			w(uvs[0].values[uidx*2]);
+			w(uvs[0].values[uidx*2+1]);
+		}
+		outputData.addInt32(index.vidx.length);
+		for( i in 0...index.vidx.length )
+			outputData.addInt32(i);
+		sys.io.File.saveBytes(fileName, outputData.getBytes());
+		var ret = try Sys.command("mikktspace",[fileName,outFile]) catch( e : Dynamic ) -1;
+		if( ret != 0 ) {
+			sys.FileSystem.deleteFile(fileName);
+			throw "Failed to called 'mikktspace' executable required to generate tangent data. Please ensure it's in your PATH";
+		}
+		var bytes = sys.io.File.getBytes(outFile);
+		var arr = [];
+		for( i in 0...index.vidx.length*4 )
+			arr[i] = bytes.getFloat(i << 2);
+		sys.FileSystem.deleteFile(fileName);
+		sys.FileSystem.deleteFile(outFile);
+		return arr;
+		#else
+		throw "Tangent generation is not supported on this platform";
+		return ([] : Array<Float>);
+		#end
+	}
+
+	function buildGeom( geom : hxd.fmt.fbx.Geometry, skin : h3d.anim.Skin, dataOut : haxe.io.BytesOutput, genTangents : Bool ) {
 		var g = new Geometry();
 
 		var verts = geom.getVertices();
@@ -42,8 +133,6 @@ class HMDOut extends BaseLibrary {
 		var uvs = geom.getUVs();
 		var colors = geom.getColors();
 		var mats = geom.getMaterials();
-		var tangents = geom.getTangents(true);
-		var biNorm = geom.getBinormals(true);
 
 		// remove empty color data
 		if( colors != null ) {
@@ -57,6 +146,9 @@ class HMDOut extends BaseLibrary {
 				colors = null;
 		}
 
+		// generate tangents
+		var tangents = genTangents ? buildTangents(geom) : null;
+
 		// build format
 		g.vertexFormat = [
 			new GeometryFormat("position", DVec3),
@@ -133,23 +225,13 @@ class HMDOut extends BaseLibrary {
 				}
 
 				if( tangents != null ) {
-					tmpBuf[p++] = tangents[k * 3];
-					tmpBuf[p++] = tangents[k * 3 + 1];
-					tmpBuf[p++] = tangents[k * 3 + 2];
-
-					if( biNorm != null ) {
-
-						// RH
-						var n = new h3d.Vector(normals[k*3], normals[k*3+1], normals[k*3+2]);
-						var t = new h3d.Vector(tangents[k*3], tangents[k*3+1], tangents[k*3+2]);
-						var b = new h3d.Vector(biNorm[k*3], biNorm[k*3+1], biNorm[k*3+2]);
-
-						if( n.cross(t).dot3(b) < 0 ) {
-							// store binormal flip sign in tangent length
-							tmpBuf[p-3] *= 0.5;
-							tmpBuf[p-2] *= 0.5;
-							tmpBuf[p-1] *= 0.5;
-						}
+					tmpBuf[p++] = round(tangents[k * 4]);
+					tmpBuf[p++] = round(tangents[k * 4 + 1]);
+					tmpBuf[p++] = round(tangents[k * 4 + 2]);
+					if( tangents[k*4+3] > 0 ) {
+						tmpBuf[p-3] *= 0.5;
+						tmpBuf[p-2] *= 0.5;
+						tmpBuf[p-1] *= 0.5;
 					}
 				}
 
@@ -436,10 +518,13 @@ class HMDOut extends BaseLibrary {
 			if( !o.isMesh ) continue;
 
 			var mids : Array<Int> = [];
+			var hasNormalMap = false;
 			for( m in getChilds(o.model, "Material") ) {
 				var mid = hmat.get(m.getId());
 				if( mid != null ) {
 					mids.push(mid);
+					var m = d.materials[mid];
+					hasNormalMap = m.normalMap != null;
 					continue;
 				}
 				var hasHeapsProps = false;
@@ -506,6 +591,8 @@ class HMDOut extends BaseLibrary {
 
 				// get other textures
 				mat.normalMap = makeTexturePath(getSpecChild(m, "NormalMap"));
+				if( mat.normalMap != null )
+					hasNormalMap = true;
 				var spec = getSpecChild(m, "SpecularFactor"); // 3dsMax
 				if( spec == null ) spec = getSpecChild(m, "SpecularColor"); // maya
 				mat.specularTexture = makeTexturePath(spec);
@@ -555,7 +642,7 @@ class HMDOut extends BaseLibrary {
 
 			var gdata = hgeom.get(g.getId());
 			if( gdata == null ) {
-				var geom = buildGeom(new hxd.fmt.fbx.Geometry(this, g), skin, dataOut);
+				var geom = buildGeom(new hxd.fmt.fbx.Geometry(this, g), skin, dataOut, hasNormalMap);
 				gdata = { gid : d.geometries.length, materials : geom.materials };
 				d.geometries.push(geom.g);
 				hgeom.set(g.getId(), gdata);

+ 34 - 0
tools/mikktspace/Mikktspace.hx

@@ -0,0 +1,34 @@
+class Mikktspace {
+
+	static function main() {
+		var args = Sys.args();
+		if( args.length < 2 ) {
+			Sys.println("mikkspace [input] [output] (angle)");
+			Sys.exit(1);
+		}
+
+		var threshold = args.length > 2 ? Std.parseFloat(args[2]) : 180;
+
+		var input = new haxe.io.BytesInput(sys.io.File.getBytes(args[0]));
+		var m = new hl.Format.Mikktspace();
+		var vertCount = input.readInt32();
+		m.stride = input.readInt32();
+		m.xPos = input.readInt32();
+		m.normalPos = input.readInt32();
+		m.uvPos = input.readInt32();
+		m.buffer = input.read(vertCount * m.stride * 4);
+
+		m.indices = input.readInt32();
+		m.indexes = input.read(m.indices * 4);
+
+		var tangents = haxe.io.Bytes.alloc(4 * 4 * vertCount);
+		m.tangents = tangents;
+		m.tangentStride = 4;
+		m.tangentPos = 0;
+
+		m.compute(threshold);
+
+		sys.io.File.saveBytes(args[1], tangents);
+	}
+
+}

+ 4 - 0
tools/mikktspace/build_msvc.bat

@@ -0,0 +1,4 @@
+@echo off
+haxe mikktspace.hxml -D no-compilation
+vcvarsall.bat
+cl /Ox /Femikktspace.exe -I %HASHLINK% -I out out/main.c %HASHLINK_BIN%/libhl.lib %HASHLINK_BIN%/fmt.lib

+ 2 - 0
tools/mikktspace/mikktspace.hxml

@@ -0,0 +1,2 @@
+-hl out/main.c
+-main Mikktspace