public void SmoothNodeTriangles(RsmNode node, List <RsmTriangle> triangles) { //var maxSmoothGroup = node.Faces.Max(f => f.SmoothGroup); //we can assume all faces in a given triangle has the same normal at this point var faceNormals = new List <Vector3>(); //var faceNormals = triangles.Select(t => new[] {t.Normals[0], t.Normals[1], t.Normals[2]}).ToList(); foreach (var t in triangles) { faceNormals.Add(VectorHelper.CalcNormal(t.Vertices[0], t.Vertices[1], t.Vertices[2])); } for (var i = 0; i < node.Faces.Count; i++) //loop through the first set of faces { var face1 = node.Faces[i]; var f1Normals = new[] { faceNormals[i], faceNormals[i], faceNormals[i] }; var f1Counts = new[] { 1, 1, 1 }; for (var j = 0; j < node.Faces.Count; j++) //loop through the second set of faces { var face2 = node.Faces[j]; if (i == j || face1.SmoothGroup != face2.SmoothGroup) //they must be in the same smooth group and not the same face { continue; } for (var k = 0; k < 3; k++) //loop through each vertex in face1 { for (var l = 0; l < 3; l++) //loop through each vertex in face2 { if (face1.VertexIds[k] == face2.VertexIds[l]) //if the ids match, add their normal to the total { f1Normals[k] += faceNormals[j]; f1Counts[k]++; } } } } for (var k = 0; k < 3; k++) { var normal = (f1Normals[k] / f1Counts[k]).normalized; if (normal.magnitude > 0.1) //discard normals that don't normalize, as that means it's not pointing any direction { triangles[i].Normals[k] = normal; } } } }
private RsmNode LoadNode() { var node = new RsmNode(); node.Name = br.ReadKoreanString(40); node.ParentName = br.ReadKoreanString(40); if (string.IsNullOrWhiteSpace(node.Name)) { node.Name = $"Object {nameId}"; nameId++; } var textureCount = br.ReadInt32(); node.TextureIds = new List <int>(); for (var i = 0; i < textureCount; i++) { node.TextureIds.Add(br.ReadInt32()); } var forward = br.ReadVector3(); var up = br.ReadVector3(); var right = br.ReadVector3(); node.OffsetMatrix = new Matrix4x4(forward, up, right, new Vector4(0, 0, 0, 1)); node.Offset = br.ReadVector3(); node.Position = br.ReadVector3(); node.RotationAngle = br.ReadSingle(); node.RotationAxis = br.ReadVector3(); node.Scale = br.ReadVector3(); var vertCount = br.ReadInt32(); for (var i = 0; i < vertCount; i++) { node.Vertices.Add(node.OffsetMatrix * br.ReadVector3()); } var uvCount = br.ReadInt32(); for (var i = 0; i < uvCount; i++) { node.Colors.Add(model.Version >= 12 ? br.ReadByteColor() : Color.white); var uv = br.ReadVector2(); uv.x = Mathf.Clamp(uv.x, 0, 1); uv.y = Mathf.Clamp(1 - uv.y, 0, 1); //1 - (uv.y * 0.98f + 0.01f); //wut node.UVs.Add(uv); } var faceCount = br.ReadInt32(); for (var i = 0; i < faceCount; i++) { var face = new RsmFace(); face.VertexIds[0] = br.ReadUInt16(); face.VertexIds[1] = br.ReadUInt16(); face.VertexIds[2] = br.ReadUInt16(); face.UVIds[0] = br.ReadUInt16(); face.UVIds[1] = br.ReadUInt16(); face.UVIds[2] = br.ReadUInt16(); face.TextureId = br.ReadUInt16(); face.Padding = br.ReadUInt16(); face.TwoSided = br.ReadInt32() == 1; if (model.Version >= 12) { face.SmoothGroup = br.ReadInt32(); } node.Faces.Add(face); } if (model.Version >= 15) { var posKeyFrames = br.ReadInt32(); for (var i = 0; i < posKeyFrames; i++) { node.PosKeyFrames.Add(new RsmPosKeyframe() { Frame = br.ReadInt32(), Position = br.ReadRoPosition() }); } } var rotKeyFrames = br.ReadInt32(); for (var i = 0; i < rotKeyFrames; i++) { var keyframe = new RsmRotKeyFrame() { Frame = br.ReadInt32(), Rotation = br.ReadQuaternion().FlipY() }; node.RotationKeyFrames.Add(keyframe); //Debug.Log(keyframe.Rotation.eulerAngles); } node.Matrix = Matrix4x4.identity; node.Bounds = new Bounds(); return(node); }
public GameObject CompileNode(GameObject parentGameObject, RsmNode node, Material mat) { var go = new GameObject(node.Name); var mf = go.AddComponent <MeshFilter>(); var mr = go.AddComponent <MeshRenderer>(); var mc = go.AddComponent <MeshCollider>(); go.layer = LayerMask.NameToLayer("Object"); go.isStatic = true; mr.material = mat; mr.receiveGI = ReceiveGI.Lightmaps; mr.shadowCastingMode = ShadowCastingMode.TwoSided; mc.cookingOptions = MeshColliderCookingOptions.CookForFasterSimulation | MeshColliderCookingOptions.EnableMeshCleaning | MeshColliderCookingOptions.WeldColocatedVertices | MeshColliderCookingOptions.UseFastMidphase; go.transform.parent = parentGameObject.transform; var position = node.Position; var rotation = Quaternion.AngleAxis(node.RotationAngle * Mathf.Rad2Deg, node.RotationAxis).FlipY(); var scale = node.Scale; var offset = node.Offset; if (node.PosKeyFrames.Count > 0) { position = node.PosKeyFrames[0].Position; } if (node.RotationKeyFrames.Count > 0) { rotation = node.RotationKeyFrames[0].Rotation; } go.transform.localPosition = position.FlipY(); go.transform.localRotation = rotation; go.transform.localScale = scale; var vTrans = new List <Vector3>(); var tris = new List <RsmTriangle>(); foreach (var f in node.Faces) { var tri = new RsmTriangle() { TwoSided = f.TwoSided }; var realTexId = node.TextureIds[f.TextureId]; for (var i = 0; i < 3; i++) { var v = node.Vertices[f.VertexIds[i]].FlipY() + offset.FlipY(); vTrans.Add(go.transform.TransformPoint(v)); tri.Vertices[i] = v; tri.UVs[i] = VectorHelper.RemapUV(node.UVs[f.UVIds[i]], atlasRects[realTexId]); tri.Colors[i] = node.Colors[f.UVIds[i]]; } tri.CalcNormals(); tris.Add(tri); } if (model.ShadingType == RsmShadingType.Smooth) { SmoothNodeTriangles(node, tris); } if (vTrans.Count > 0) { node.Bounds = GeometryUtility.CalculateBounds(vTrans.ToArray(), Matrix4x4.identity); } else { node.Bounds = new Bounds(Vector3.zero, Vector3.zero); } var mb = new MeshBuilder(); foreach (var t in tris) { mb.AddFullTriangle(t.Vertices, t.FlippedNormals, t.UVs, t.Colors, new[] { 2, 1, 0 }); if (t.TwoSided) { mb.AddFullTriangle(t.Vertices, t.Normals, t.UVs, t.Colors, new[] { 0, 1, 2 }); } } var mesh = mb.Build(node.Name, true); mf.sharedMesh = mesh; mc.sharedMesh = mesh; if (tris.Any(t => t.TwoSided)) { mr.shadowCastingMode = ShadowCastingMode.On; //disable two sided shadows if the model has any two sided faces } if (node.Children.Count > 0) { foreach (var child in node.Children) { CompileNode(go, child, mat); } } if (node.RotationKeyFrames.Count != 0 || node.PosKeyFrames.Count != 0) { go.ChangeStaticRecursive(false); } if (string.IsNullOrWhiteSpace(node.ParentName)) { var bounds = node.Bounds; foreach (var n in model.RsmNodes) { bounds.Encapsulate(n.Bounds); } var centering = new Vector3(bounds.center.x, bounds.min.y, bounds.center.z); //Debug.Log(centering); go.transform.localPosition -= centering; go.transform.localPosition *= 0.2f; go.transform.localScale *= 0.2f; } if (node.RotationKeyFrames.Count > 0) { var r = go.AddComponent <RoKeyframeRotator>(); var keyframes = new List <float>(); var rotations = new List <Quaternion>(); foreach (var k in node.RotationKeyFrames) { keyframes.Add(k.Frame / 1000f); rotations.Add(k.Rotation); } r.Keyframes = keyframes.ToArray(); r.Rotations = rotations.ToArray(); } //save Mesh var meshPath = AssetHelper.GetAssetPath(Path.Combine("Assets/models/mesh", savePath, baseName), Path.GetFileNameWithoutExtension(node.Name) + ".asset"); AssetDatabase.CreateAsset(mesh, meshPath); return(go); }