Browse Source

added hmd normals generation and precise mode

Nicolas Cannasse 4 years ago
parent
commit
9ea045607d
5 changed files with 96 additions and 2 deletions
  1. 5 0
      h3d/prim/HMDModel.hx
  2. 8 2
      hxd/fmt/fbx/BaseLibrary.hx
  3. 22 0
      hxd/fmt/fbx/Geometry.hx
  4. 57 0
      hxd/fmt/fbx/HMDOut.hx
  5. 4 0
      hxd/fs/Convert.hx

+ 5 - 0
h3d/prim/HMDModel.hx

@@ -110,8 +110,13 @@ class HMDModel extends MeshPrimitive {
 
 	public function recomputeNormals( ?name : String ) {
 
+		for( f in data.vertexFormat )
+			if( f.name == name )
+				return;
+
 		if( name == null ) name = "normal";
 
+
 		var pos = lib.getBuffers(data, [new hxd.fmt.hmd.Data.GeometryFormat("position", DVec3)]);
 		var ids = new Array();
 		var pts : Array<h3d.col.Point> = [];

+ 8 - 2
hxd/fmt/fbx/BaseLibrary.hx

@@ -142,6 +142,11 @@ class BaseLibrary {
 	**/
 	public var normalizeScaleOrient : Bool = true;
 
+	/**
+		Keep high precision values. Might increase animation data size and compressed size.
+	**/
+	public var highPrecision : Bool = false;
+
 	public function new( fileName ) {
 		this.fileName = fileName;
 		root = { name : "Root", props : [], childs : [] };
@@ -772,9 +777,10 @@ class BaseLibrary {
 
 	function roundValues( data : Array<Float>, def : Float, mult : Float = 1. ) {
 		var hasValue = false;
+		var epsi = highPrecision ? 0 : 1e-3;
 		for( i in 0...data.length ) {
 			var v = data[i] * mult;
-			if( Math.abs(v - def) > 1e-3 )
+			if( Math.abs(v - def) > epsi )
 				hasValue = true;
 			else
 				v = def;
@@ -1362,7 +1368,7 @@ class BaseLibrary {
 
 	function round(v:Float) {
 		if( v != v ) throw "NaN found";
-		return std.Math.fround(v * 131072) / 131072;
+		return highPrecision ? v : std.Math.fround(v * 131072) / 131072;
 	}
 
 	function updateDefaultMatrix( model : FbxNode, d : DefaultMatrixes ) {

+ 22 - 0
hxd/fmt/fbx/Geometry.hx

@@ -169,6 +169,28 @@ class Geometry {
 		return { vidx : vout, idx : iout };
 	}
 
+	public function getPoints(?matrix) {
+		if( matrix == null ) matrix = getGeomMatrix();
+		if( matrix != null && matrix.isIdentity() ) matrix = null;
+		var verts = getVertices();
+		var points = [];
+		var tmp = new h3d.col.Point();
+		for( i in 0...Std.int(verts.length/3) ) {
+			var x = verts[i*3];
+			var y = verts[i*3+1];
+			var z = verts[i*3+2];
+			if( matrix != null ) {
+				tmp.set(x,y,z);
+				tmp.transform(matrix);
+				x = tmp.x;
+				y = tmp.y;
+				z = tmp.z;
+			}
+			points.push(new h3d.col.Point(x,y,z));
+		}
+		return points;
+	}
+
 	public function getNormals() {
 		return processVectors("LayerElementNormal", "Normals");
 	}

+ 57 - 0
hxd/fmt/fbx/HMDOut.hx

@@ -11,6 +11,7 @@ class HMDOut extends BaseLibrary {
 	var tmp = haxe.io.Bytes.alloc(4);
 	public var absoluteTexturePath : Bool;
 	public var optimizeSkin = true;
+	public var generateNormals = false;
 	/*
 		Store the skin indexes as multiple premultiplied floats instead of as packed into a single 4 bytes ints.
 		This is necessary for GPUs that does not respect OpenGLES spec and does not allow non-constant indexing in vertex shader (Adreno 20X)
@@ -128,6 +129,49 @@ class HMDOut extends BaseLibrary {
 		#end
 	}
 
+	function updateNormals( g : Geometry, vbuf : hxd.FloatBuffer, idx : Array<Array<Int>> ) {
+		var stride = g.vertexStride;
+		var normalPos = 0;
+		for( f in g.vertexFormat ) {
+			if( f.name == "logicNormal" ) break;
+			normalPos += f.format.getSize();
+		}
+
+		var points : Array<h3d.col.Point> = [];
+		var pmap = [];
+		for( vid in 0...g.vertexCount ) {
+			var x = vbuf[vid * stride];
+			var y = vbuf[vid * stride + 1];
+			var z = vbuf[vid * stride + 2];
+			var found = false;
+			for( i => p in points ) {
+				if( p.x == x && p.y == y && p.z == z ) {
+					pmap[vid] = i;
+					found = true;
+					break;
+				}
+			}
+			if( !found ) {
+				pmap[vid] = points.length;
+				points.push(new h3d.col.Point(x,y,z));
+			}
+		}
+		var realIdx = new hxd.IndexBuffer();
+		for( idx in idx )
+			for( i in idx )
+				realIdx.push(pmap[i]);
+
+		var poly = new h3d.prim.Polygon(points, realIdx);
+		poly.addNormals();
+
+		for( vid in 0...g.vertexCount ) {
+			var nid = pmap[vid];
+			vbuf[vid*stride + normalPos] = poly.normals[nid].x;
+			vbuf[vid*stride + normalPos + 1] = poly.normals[nid].y;
+			vbuf[vid*stride + normalPos + 2] = poly.normals[nid].z;
+		}
+	}
+
 	function buildGeom( geom : hxd.fmt.fbx.Geometry, skin : h3d.anim.Skin, dataOut : haxe.io.BytesOutput, genTangents : Bool ) {
 		var g = new Geometry();
 
@@ -170,6 +214,10 @@ class HMDOut extends BaseLibrary {
 			g.vertexFormat.push(new GeometryFormat("weights", [DFloat, DVec2, DVec3, DVec4][bonesPerVertex-1]));
 			g.vertexFormat.push(new GeometryFormat("indexes", floatSkinIndexes ? [DFloat, DVec2, DVec3, DVec4][bonesPerVertex-1] : DBytes4));
 		}
+
+		if( generateNormals )
+			g.vertexFormat.push(new GeometryFormat("logicNormal", DVec3));
+
 		var stride = 0;
 		for( f in g.vertexFormat )
 			stride += f.format.getSize();
@@ -267,6 +315,12 @@ class HMDOut extends BaseLibrary {
 						tmpBuf[p++] = int32tof(idx);
 				}
 
+				if( generateNormals ) {
+					tmpBuf[p++] = 0;
+					tmpBuf[p++] = 0;
+					tmpBuf[p++] = 0;
+				}
+
 				var total = 0.;
 				for( i in 0...stride )
 					total += tmpBuf[i];
@@ -336,6 +390,9 @@ class HMDOut extends BaseLibrary {
 			count = 0;
 		}
 
+		if( generateNormals )
+			updateNormals(g,vbuf,ibufs);
+
 		// write data
 		g.vertexPosition = dataOut.length;
 		for( i in 0...vbuf.length )

+ 4 - 0
hxd/fs/Convert.hx

@@ -78,6 +78,10 @@ class ConvertFBX2HMD extends Convert {
 	override function convert() {
 		var fbx = try hxd.fmt.fbx.Parser.parse(srcBytes) catch( e : Dynamic ) throw Std.string(e) + " in " + srcPath;
 		var hmdout = new hxd.fmt.fbx.HMDOut(srcPath);
+		if( params.normals )
+			hmdout.generateNormals = true;
+		if( params.precise )
+			hmdout.highPrecision = true;		
 		hmdout.load(fbx);
 		var isAnim = StringTools.startsWith(originalFilename, "Anim_") || originalFilename.toLowerCase().indexOf("_anim_") > 0;
 		var hmd = hmdout.toHMD(null, !isAnim);