- Home /
This question was
closed Aug 21, 2018 at 08:47 AM by
Shreka for the following reason:
The question is answered, right answer was accepted
Question by
Shreka · Aug 04, 2018 at 03:34 PM ·
scripting problemmeshuv mappingimporting problemsmodel importing
Md5mesh uvs and vertices bugging
I wrote a md5mesh import script by luck i got to import the file but i couldnt find why this happened or what i am missing
Imported by my code
imported by blender md5mesh importer.
My unity importer code .
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using UnityEditor;
using System;
using System.IO;
using System.Text.RegularExpressions;
using System.Text;
using MD5;
public class MD5Mesh : MonoBehaviour
{
public static int max_verts = 0;
public static int max_tris = 0;
public static StreamReader br;
public static md5_anim_t Md5_Anim;
public static md5_bbox_t Md5_Bbox;
public static md5_joint_t Md5_Joint;
public static md5_mesh_t Md5_Mesh;
public static md5_model_t mdl = new md5_model_t();
public static md5_triangle_t Md5_Triangle;
public static md5_vertex_t Md5_Vertex;
public static md5_weight_t Md5_Weight;
public static Mesh m_mesh;
public static List<Vector3> vertexArray = new List<Vector3>();
public static int[] vertexIndices;
public static List<Vector2> vertexUv = new List<Vector2>();
public static List<Vector3> vertexNormals = new List<Vector3>();
public static Mesh MD5Load(string path)
{
if (ReadMD5(path) != 1) return null;
SizeArrays();
for (int x = 0; x < mdl.num_meshes; x++)
PrepareMesh(mdl.meshes[x], mdl.baseSkel);
m_mesh = new Mesh();
m_mesh.vertices = new Vector3[max_verts];
m_mesh.SetVertices(vertexArray);
m_mesh.SetNormals(vertexNormals);
int a = 0;
Debug.Log(vertexArray.Count);
//for(int i = 0; i < mdl.meshes.Length; i++)
// for (int x = 0; x < mdl.meshes[i].triangles.Length; x++)
// m_mesh.SetIndices(mdl.meshes[i].triangles[i].index, MeshTopology.Triangles, 0);
m_mesh.SetUVs(0, vertexUv);
m_mesh.SetTriangles(vertexIndices,0);
m_mesh.RecalculateBounds();
return m_mesh;
}
static int ReadMD5(string path)
{
StreamReader fp;
string buff;
int version;
int curr_mesh = 0;
int i;
fp = new StreamReader(File.Open(path, FileMode.Open));
if (fp == null)
{
Debug.Log("Error: couldn't open file at path : " + path);
return 0;
}
while (!fp.EndOfStream)
{
buff = fp.ReadLine();
if (buff.Contains("MD5Version"))
{
version = int.Parse(buff.Split(' ')[1].Trim(), System.Globalization.NumberStyles.Integer);
if (version != 10)
{
/* Bad version */
Debug.Log("Error: bad model version\n");
fp.Close();
return 0;
}
}
else if (buff.Contains("numJoints"))
{
mdl.num_joints = int.Parse(buff.Split(' ')[1].Trim(), System.Globalization.NumberStyles.Integer);
if (mdl.num_joints > 0)
{
mdl.baseSkel = new md5_joint_t[mdl.num_joints];
}
}
else if (buff.Contains("numMeshes"))
{
mdl.num_meshes = int.Parse(buff.Split(' ')[1].Trim(), System.Globalization.NumberStyles.Integer);
if (mdl.num_meshes > 0)
{
mdl.meshes = new md5_mesh_t[mdl.num_meshes];
}
}
else if (string.Compare(buff, 0, "joints {", 0, 8) == 0)
{
for (i = 0; i < mdl.num_joints; ++i)
{
md5_joint_t joint = mdl.baseSkel[i] = new md5_joint_t();
buff = fp.ReadLine();
var sformat = "%s %d ( %f %f %f ) ( %f %f %f )";
var a = buff.Split('"');
var bsplits = a[2].Split(' ');
var fsplits = sformat.Split(' ');
joint.name = a[1].Trim();
joint.parent = int.Parse(bsplits[0].Trim(), System.Globalization.NumberStyles.Integer);
int d = 2;
joint.pos[0] = float.Parse(bsplits[2].Trim(), System.Globalization.NumberStyles.Float);
joint.pos[1] = float.Parse(bsplits[3].Trim(), System.Globalization.NumberStyles.Float);
joint.pos[2] = float.Parse(bsplits[4].Trim(), System.Globalization.NumberStyles.Float);
joint.orient[0] = float.Parse(bsplits[7].Trim(), System.Globalization.NumberStyles.Float);
joint.orient[1] = float.Parse(bsplits[8].Trim(), System.Globalization.NumberStyles.Float);
joint.orient[2] = float.Parse(bsplits[9].Trim(), System.Globalization.NumberStyles.Float);
Utils.Quat_computeW(joint.orient);
Debug.Log("xxxxn : " + joint.name);
Debug.Log("xxxxp : " + joint.parent);
Debug.Log("xxxp0 : " + joint.pos[0]);
Debug.Log("xxxp1 : " + joint.pos[2]);
Debug.Log("xxxp2 : " + joint.pos[2]);
Debug.Log("xxxo0 : " + joint.orient[0]);
Debug.Log("xxxo1 : " + joint.orient[1]);
Debug.Log("xxxo2 : " + joint.orient[2]);
Debug.Log("xxxo3 : " + joint.orient[3]);
}
}
else if (string.Compare(buff, 0, "mesh {", 0, 6) == 0)
{
md5_mesh_t mesh = mdl.meshes[curr_mesh] = new md5_mesh_t();
int vert_index = 0;
int tri_index = 0;
int weight_index = 0;
float[] fdata = new float[4];
int[] idata = new int[3];
while (!buff.Contains("}") && !fp.EndOfStream)
{
buff = fp.ReadLine();
if (StringFunctions.StrStr(buff, "shader") != null)
{
int quote = 0;
int j = 0;
/* Copy the shader name whithout the quote marks */
for (i = 0; i < sizeof(sbyte) && (quote < 2); ++i)
{
if (buff[i] == '"')
{
quote++;
}
if ((quote == 1) && (buff[i] != '"'))
{
mesh.shader = StringFunctions.ChangeCharacter(mesh.shader, j, buff[i]);
Debug.Log(mesh.shader);
j++;
}
}
}
else if (buff.Contains("numverts"))
{
mesh.num_verts = int.Parse(buff.Split(' ')[1].Trim(), System.Globalization.NumberStyles.Integer);
if (mesh.num_verts > 0)
{
mesh.vertices = new md5_vertex_t[mesh.num_verts];
}
if (mesh.num_verts > max_verts)
{
max_verts = mesh.num_verts;
}
}
else if (buff.Contains("numtris"))
{
mesh.num_tris = int.Parse(buff.Split(' ')[1].Trim(), System.Globalization.NumberStyles.Integer);
if (mesh.num_tris > 0)
{
mesh.triangles = new md5_triangle_t[mesh.num_tris];
}
if (mesh.num_tris > max_tris)
{
max_tris = mesh.num_tris;
}
}
else if (buff.Contains("numweights"))
{
mesh.num_weights = int.Parse(buff.Split(' ')[1].Trim(), System.Globalization.NumberStyles.Integer);
if (mesh.num_weights > 0)
{
mesh.weights = new md5_weight_t[mesh.num_weights];
}
}
else if (buff.Contains("vert") && !buff.Contains("numverts"))
{
var splits = buff.Split(' ');
vert_index = Convert.ToInt32(splits[1].Trim());
fdata[0] = float.Parse(splits[3].Trim(), System.Globalization.NumberStyles.Float);
fdata[1] = float.Parse(splits[4].Trim(), System.Globalization.NumberStyles.Float);
idata[0] = int.Parse(splits[6].Trim(), System.Globalization.NumberStyles.Integer);
idata[1] = int.Parse(splits[7].Trim(), System.Globalization.NumberStyles.Integer);
mesh.vertices[vert_index] = new md5_vertex_t();
mesh.vertices[vert_index].uv = new Vector2(fdata[0], fdata[1]);
mesh.vertices[vert_index].start = idata[0];
mesh.vertices[vert_index].count = idata[1];
}
else if (buff.Contains("tri"))
{
var splits = buff.Split(' ');
tri_index = int.Parse(splits[1].Trim(), System.Globalization.NumberStyles.Integer);
idata[0] = int.Parse(splits[2].Trim(), System.Globalization.NumberStyles.Integer);
idata[1] = int.Parse(splits[3].Trim(), System.Globalization.NumberStyles.Integer);
idata[2] = int.Parse(splits[4].Trim(), System.Globalization.NumberStyles.Integer);
mesh.triangles[tri_index] = new md5_triangle_t();
mesh.triangles[tri_index].index[0] = idata[0];
mesh.triangles[tri_index].index[1] = idata[1];
mesh.triangles[tri_index].index[2] = idata[2];
}
else if (buff.Contains("weight"))
{
var splits = buff.Split(' ');
weight_index = int.Parse(splits[1].Trim(), System.Globalization.NumberStyles.Integer);
idata[0] = int.Parse(splits[2].Trim(), System.Globalization.NumberStyles.Integer);
fdata[3] = float.Parse(splits[3].Trim(), System.Globalization.NumberStyles.Float);
fdata[0] = float.Parse(splits[5].Trim(), System.Globalization.NumberStyles.Float);
fdata[1] = float.Parse(splits[6].Trim(), System.Globalization.NumberStyles.Float);
fdata[2] = float.Parse(splits[7].Trim(), System.Globalization.NumberStyles.Float);
mesh.weights[weight_index] = new md5_weight_t();
mesh.weights[weight_index].joint = idata[0];
mesh.weights[weight_index].bias = fdata[3];
mesh.weights[weight_index].pos[0] = fdata[0];
mesh.weights[weight_index].pos[1] = fdata[1];
mesh.weights[weight_index].pos[2] = fdata[2];
}
}
curr_mesh++;
}
}
fp.Close();
return 1;
}
public static void SizeArrays()
{
vertexIndices = new int[max_tris * 3];
}
public static void PrepareMesh(md5_mesh_t mesh, md5_joint_t[] skeleton)
{
int i;
int j;
int k;
for (k = 0, i = 0; i < mesh.num_tris; ++i)
{
for (j = 0; j < 3; ++j, ++k)
{
vertexIndices[k] = mesh.triangles[i].index[j];
}
}
Debug.Log("num of verts = " + mesh.num_verts);
for (i = 0; i < mesh.num_verts; ++i)
{
Vector3 finalVertex = new Vector3(0.0f, 0.0f, 0.0f);
/* Calculate final vertex to draw with weights */
for (j = 0; j < mesh.vertices[i].count; ++j)
{
md5_weight_t weight = mesh.weights[mesh.vertices[i].start + j];
md5_joint_t joint = skeleton[weight.joint];
/* Calculate transformed vertex for this weight */
Vector3 wv = new Vector3(0f, 0f, 0f);
Utils.Quat_rotatePoint(joint.orient, weight.pos ,out wv);
/* The sum of all weight->bias should be 1.0 */
finalVertex += (joint.pos + wv) * weight.bias;
}
vertexArray.Add(finalVertex);
}
foreach (md5_triangle_t MD5Triangle in mesh.triangles)
{
// Normals
var v0 = MD5Triangle.index[0];
var v1 = MD5Triangle.index[1];
var v2 = MD5Triangle.index[2];
Vector3 pos0 = vertexArray[v0];
Vector3 pos1 = vertexArray[v1];
Vector3 pos2 = vertexArray[v2];
Vector3 normal = (pos2 - pos0).cross((pos1) - (pos0));
vertexNormals.Add(normal.normalized);
vertexNormals.Add(normal.normalized);
vertexNormals.Add(normal.normalized);
}
for (i = 0; i < mesh.num_verts; ++i)
{
vertexUv.Add(mesh.vertices[i].uv);
}
}
}
the vertices culculation was from "http://tfc.duke.free.fr/coding/src/md5mesh.c"
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEditor;
public class Md5import : MonoBehaviour {
public Object md5mesh;
private Mesh m_mesh;
// Use this for initialization
void Start () {
m_mesh = MD5Mesh.MD5Load(AssetDatabase.GetAssetPath (md5mesh));
m_mesh.name = md5mesh.name;
GetComponentInChildren<MeshFilter>().sharedMesh = m_mesh;
GetComponentInChildren<SkinnedMeshRenderer>().sharedMesh = m_mesh;
Vector3[] normals = m_mesh.normals;
for (int i = 0; i < normals.Length; i++)
normals[i] = -normals[i];
m_mesh.normals = normals;
for (int m = 0; m < m_mesh.subMeshCount; m++)
{
int[] triangles = m_mesh.GetTriangles(m);
for (int i = 0; i < triangles.Length; i += 3)
{
int temp = triangles[i + 0];
triangles[i + 0] = triangles[i + 1];
triangles[i + 1] = temp;
}
m_mesh.SetTriangles(triangles, m);
}
}
// Update is called once per frame
void Update () {
}
}
here is the model classes
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using UnityEditor;
using System;
using System.IO;
using System.Text.RegularExpressions;
namespace MD5
{
public static class md5model
{
}
/*
* md5model.h -- md5mesh model loader + animation
* last modification: aug. 14, 2007
*
* Copyright (c) 2005-2007 David HENRY
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
* files (the "Software"), to deal in the Software without
* restriction, including without limitation the rights to use,
* copy, modify, merge, publish, distribute, sublicense, and/or
* sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
* ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
* gcc -Wall -ansi -lGL -lGLU -lglut md5anim.c md5anim.c -o md5model
*/
public enum AnonymousEnum
{
X,
Y,
Z,
W
}
/* Joint */
public class md5_joint_t
{
public string name = new string(new char[64]);
public int parent = 0;
public Vector3 pos = new Vector3(0f,0f,0f);
public Quaternion orient = new Quaternion(0f,0f,0f,0f);
}
/* Vertex */
public class md5_vertex_t
{
public Vector2 uv = new Vector2(0f,0f);
public int start = 0; // start weight
public int count = 0; // weight count
}
/* Triangle */
public class md5_triangle_t
{
public int[] index = new int[3];
}
/* Weight */
public class md5_weight_t
{
public int joint = 0;
public float bias = 0f;
public Vector3 pos = new Vector3(0f, 0f, 0f);
}
/* Bounding box */
public class md5_bbox_t
{
public float[] min = new float[3];
public float[] max = new float[3];
}
/* MD5 mesh */
public class md5_mesh_t
{
public md5_vertex_t[] vertices;
public md5_triangle_t[] triangles;
public md5_weight_t[] weights;
public int num_verts = 0;
public int num_tris = 0;
public int num_weights = 0;
public string shader = new string(new char[256]);
}
/* MD5 model structure */
public class md5_model_t
{
public md5_joint_t[] baseSkel;
public md5_mesh_t[] meshes;
public int num_joints = 0;
public int num_meshes = 0;
}
/* Animation data */
public class md5_anim_t
{
public int num_frames = 0;
public int num_joints = 0;
public int frameRate = 0;
public md5_joint_t[][] skelFrames;
public md5_bbox_t bboxes = new md5_bbox_t();
}
/* Animation info */
public class anim_info_t
{
public int curr_frame = 0;
public int next_frame = 0;
public double last_time = 0D;
public double max_time = 0D;
}
public static class Utils
{
public static Vector3 cross(this Vector3 v, Vector3 vector3)
{
return new Vector3(vector3.z - v.z * vector3.y, v.z * vector3.x - v.x * vector3.z, v.x * vector3.y - v.y * vector3.x);
}
public static void Quat_computeW(Quaternion q)
{
float t = 1.0f - (q.x * q.x) - (q.y * q.y) - (q.z * q.z);
if (t < 0.0f)
q.w = 0.0f;
else
q.w = -Mathf.Sqrt(t);
}
public static void Quat_normalize(Quaternion q)
{
/* compute magnitude of the quaternion */
float mag = Mathf.Sqrt((q.x * q.x) + (q.y * q.y)
+ (q.z * q.z) + (q.w * q.w));
/* check for bogus length, to protect against divide by zero */
if (mag > 0.0f)
{
/* normalize it */
float oneOverMag = 1.0f / mag;
q.x *= oneOverMag;
q.y *= oneOverMag;
q.z *= oneOverMag;
q.w *= oneOverMag;
}
}
public static void Quat_multQuat(Quaternion qa, Quaternion qb, out Quaternion _out)
{
_out.w = (qa.w * qb.w) - (qa.x * qb.x) - (qa.y * qb.y) - (qa.z * qb.z);
_out.x = (qa.x * qb.w) + (qa.w * qb.x) + (qa.y * qb.z) - (qa.z * qb.y);
_out.y = (qa.y * qb.w) + (qa.w * qb.y) + (qa.z * qb.x) - (qa.x * qb.z);
_out.z = (qa.z * qb.w) + (qa.w * qb.z) + (qa.x * qb.y) - (qa.y * qb.x);
}
public static void Quat_multVec(Quaternion q, Vector3 v, out Quaternion _out)
{
_out.w = -(q.x * v.x) - (q.y * v.y) - (q.z * v.z);
_out.x = (q.w * v.x) + (q.y * v.z) - (q.z * v.y);
_out.y = (q.w * v.y) + (q.z * v.x) - (q.x * v.z);
_out.z = (q.w * v.z) + (q.x * v.y) - (q.y * v.x);
}
public static void Quat_rotatePoint(Quaternion q, Vector3 @in, out Vector3 @out)
{
@out = new Vector3(0f, 0f, 0f);
Quaternion tmp;
Quaternion inv;
Quaternion final;
inv.x = -q.x;
inv.y = -q.y;
inv.z = -q.z;
inv.w = q.w;
Quat_normalize(inv);
Quat_multVec(q, @in, out tmp);
Quat_multQuat(tmp, inv, out final);
@out.x = final.x;
@out.y = final.y;
@out.z = final.z;
}
}
}
my string function class
//----------------------------------------------------------------------------------------
// Copyright © 2006 - 2014 Tangible Software Solutions Inc.
// This class can be used by anyone provided that the copyright notice remains intact.
//
// This class provides the ability to simulate various classic C string functions
// which don't have exact equivalents in the .NET Framework.
//----------------------------------------------------------------------------------------
internal static class StringFunctions
{
//------------------------------------------------------------------------------------
// This method allows replacing a single character in a string, to help convert
// C++ code where a single character in a character array is replaced.
//------------------------------------------------------------------------------------
internal static string ChangeCharacter(string sourcestring, int charindex, char changechar)
{
return (charindex > 0 ? sourcestring.Substring(0, charindex) : "")
+ changechar.ToString() + (charindex < sourcestring.Length - 1 ? sourcestring.Substring(charindex + 1) : "");
}
//------------------------------------------------------------------------------------
// This method simulates the classic C string function 'isxdigit' (and 'iswxdigit').
//------------------------------------------------------------------------------------
internal static bool IsXDigit(char character)
{
if (char.IsDigit(character))
return true;
else if ("ABCDEFabcdef".IndexOf(character) > -1)
return true;
else
return false;
}
//------------------------------------------------------------------------------------
// This method simulates the classic C string function 'strchr' (and 'wcschr').
//------------------------------------------------------------------------------------
internal static string StrChr(string stringtosearch, char chartofind)
{
int index = stringtosearch.IndexOf(chartofind);
if (index > -1)
return stringtosearch.Substring(index);
else
return null;
}
//------------------------------------------------------------------------------------
// This method simulates the classic C string function 'strrchr' (and 'wcsrchr').
//------------------------------------------------------------------------------------
internal static string StrRChr(string stringtosearch, char chartofind)
{
int index = stringtosearch.LastIndexOf(chartofind);
if (index > -1)
return stringtosearch.Substring(index);
else
return null;
}
//------------------------------------------------------------------------------------
// This method simulates the classic C string function 'strstr' (and 'wcsstr').
//------------------------------------------------------------------------------------
internal static string StrStr(string stringtosearch, string stringtofind)
{
int index = stringtosearch.IndexOf(stringtofind);
if (index > -1)
return stringtosearch.Substring(index);
else
return null;
}
//------------------------------------------------------------------------------------
// This method simulates the classic C string function 'strtok' (and 'wcstok').
// Note that the .NET string 'Split' method cannot be used to simulate 'strtok' since
// it doesn't allow changing the delimiters between each token retrieval.
//------------------------------------------------------------------------------------
private static string activestring;
private static int activeposition;
internal static string StrTok(string stringtotokenize, string delimiters)
{
if (stringtotokenize != null)
{
activestring = stringtotokenize;
activeposition = -1;
}
//the stringtotokenize was never set:
if (activestring == null)
return null;
//all tokens have already been extracted:
if (activeposition == activestring.Length)
return null;
//bypass delimiters:
activeposition++;
while (activeposition < activestring.Length && delimiters.IndexOf(activestring[activeposition]) > -1)
{
activeposition++;
}
//only delimiters were left, so return null:
if (activeposition == activestring.Length)
return null;
//get starting position of string to return:
int startingposition = activeposition;
//read until next delimiter:
do
{
activeposition++;
} while (activeposition < activestring.Length && delimiters.IndexOf(activestring[activeposition]) == -1);
return activestring.Substring(startingposition, activeposition - startingposition);
}
}
I am newly posting this type of questions and I dont know if my title is correct or the question is on the right place. But hope Ill get a answer or this benefits anyone out there.
Im really sorry if there is any speliing or any other mistake in the question.
Found solution and added to work in progress. Here : )
Comment