/// <summary> /// laske luurangolle asento. /// </summary> void InterpolateSkeletons(ref MD5Joint[,] skel, int curFrame, int nextFrame, int num_joints, float interp) { for (int i = 0; i < num_joints; ++i) { /* Copy parent index */ skeleton[i].parent = skel[curFrame, i].parent; /* Linear interpolation for Position */ skeleton[i].pos.X = skel[curFrame, i].pos.X + interp * (skel[nextFrame, i].pos.X - skel[curFrame, i].pos.X); skeleton[i].pos.Y = skel[curFrame, i].pos.Y + interp * (skel[nextFrame, i].pos.Y - skel[curFrame, i].pos.Y); skeleton[i].pos.Z = skel[curFrame, i].pos.Z + interp * (skel[nextFrame, i].pos.Z - skel[curFrame, i].pos.Z); /* Spherical linear interpolation for orientation */ skeleton[i].orient = QuaternionExt.Slerp(skel[curFrame, i].orient, skel[nextFrame, i].orient, interp); } }
/// <summary> /// Prepare mesh for rendering /// </summary> void PrepareMesh() { int i, j, k; meshes.Clear(); // Calculate the final Position ingame Position of all the model vertexes for (k = 0; k < numMesh; k++) { numOfFaces = model[k].numTris; VertexBuffer = new Vertex[numOfFaces * 3]; for (i = 0; i < model[k].numVert; i++) { Vector3 finalVertex = new Vector3(0, 0, 0); for (j = 0; j < model[k].verts[i].countw; j++) { MD5Weight wt = model[k].weights[model[k].verts[i].startw + j]; MD5Joint joint = skeleton[wt.joint]; Vector3 wv = QuaternionExt.RotatePoint(joint.orient, wt.pos); finalVertex.X += (joint.pos.X + wv.X) * wt.bias; finalVertex.Y += (joint.pos.Y + wv.Y) * wt.bias; finalVertex.Z += (joint.pos.Z + wv.Z) * wt.bias; } finalVert[i] = finalVertex; } int count = 0; // Organize the final vertexes acording to the meshes triangles for (i = 0; i < model[k].numTris; i++) { VertexBuffer[count] = new Vertex(finalVert[(int)model[k].faces[i][0]], normals[(int)model[k].faces[i][0]], model[k].verts[(int)model[k].faces[i][0]].uv); VertexBuffer[count + 1] = new Vertex(finalVert[(int)model[k].faces[i][1]], normals[(int)model[k].faces[i][1]], model[k].verts[(int)model[k].faces[i][1]].uv); VertexBuffer[count + 2] = new Vertex(finalVert[(int)model[k].faces[i][2]], normals[(int)model[k].faces[i][2]], model[k].verts[(int)model[k].faces[i][2]].uv); count += 3; } meshes.Add(VertexBuffer); if (model[k].vbo != null) { model[k].vbo.Update(VertexBuffer); } } }
/// <summary> /// lataa md5-animaatio. /// </summary> public override void LoadMD5Animation(string animName, string fileName) { if (fileName == null || fileName == "") { return; } Animation anim = new Animation(); anim.animName = animName; Buffer t = new Buffer(); MD5JointInfo[] jointInfos = null; MD5BaseFrameJoint[] baseFrame = null; float[] animFrameData = null; int numAnimatedComponents = 0; int frame_index; int i; using (System.IO.StreamReader file = new System.IO.StreamReader(Settings.ModelDir + fileName)) { string line; while ((line = file.ReadLine()) != null) { if (line == "") { continue; } // Read number of joints if (ParseLine(ref t, line, "numFrames %d")) { /* Allocate memory for skeleton frames and bounding boxes */ anim.numFrames = t.ibuffer[0]; if (anim.numFrames > 0) { anim.bboxes = new MD5BoundingBox[anim.numFrames]; } } if (ParseLine(ref t, line, "numJoints %d")) { /* Allocate memory for joints of each frame */ anim.numJoints = t.ibuffer[0]; if (anim.numJoints > 0) { /* Allocate temporary memory for building skeleton frames */ jointInfos = new MD5JointInfo[anim.numJoints]; baseFrame = new MD5BaseFrameJoint[anim.numJoints]; } anim.skelFrames = new MD5Joint[anim.numFrames, anim.numJoints]; } if (ParseLine(ref t, line, "frameRate %d")) { anim.frameRate = t.ibuffer[0]; } if (ParseLine(ref t, line, "numAnimatedComponents %d")) { numAnimatedComponents = t.ibuffer[0]; if (numAnimatedComponents > 0) { /* Allocate memory for animation frame data */ animFrameData = new float[numAnimatedComponents]; } } if (line.Equals("hierarchy {")) { for (i = 0; i < anim.numJoints; ++i) { /* Read whole line */ line = file.ReadLine(); Cleanstring(ref line); /* Read joint info */ ParseLine(ref t, line, "%s %d %d %d"); jointInfos[i].name = t.sbuffer; jointInfos[i].parent = t.ibuffer[0]; jointInfos[i].flags = t.ibuffer[1]; jointInfos[i].startIndex = t.ibuffer[2]; } } if (line.Equals("bounds {")) { for (i = 0; i < anim.numFrames; ++i) { /* Read whole line */ line = file.ReadLine(); Cleanstring(ref line); /* Read bounding box */ ParseLine(ref t, line, "( %f %f %f ) ( %f %f %f )"); anim.bboxes[i].min.X = t.fbuffer[0]; anim.bboxes[i].min.Y = t.fbuffer[1]; anim.bboxes[i].min.Z = t.fbuffer[2]; anim.bboxes[i].max.X = t.fbuffer[3]; anim.bboxes[i].max.Y = t.fbuffer[4]; anim.bboxes[i].max.Z = t.fbuffer[5]; } } if (line.Equals("baseframe {")) { for (i = 0; i < anim.numJoints; ++i) { /* Read whole line */ line = file.ReadLine(); Cleanstring(ref line); /* Read base frame joint */ ParseLine(ref t, line, "( %f %f %f ) ( %f %f %f )"); if (t.fbuffer.Length == 6) { baseFrame[i].pos.X = t.fbuffer[0]; baseFrame[i].pos.Y = t.fbuffer[1]; baseFrame[i].pos.Z = t.fbuffer[2]; baseFrame[i].orient.X = t.fbuffer[3]; baseFrame[i].orient.Y = t.fbuffer[4]; baseFrame[i].orient.Z = t.fbuffer[5]; /* Compute the w component */ QuaternionExt.ComputeW(ref baseFrame[i].orient); } } } if (ParseLine(ref t, line, "frame %d")) { frame_index = t.ibuffer[0]; /* Read frame data */ for (i = 0; i < numAnimatedComponents;) { line = file.ReadLine(); if (line[0] == '}') { break; } Cleanstring(ref line); string[] splt = line.Split(' '); for (int ww = 0; ww < splt.Length; ww++) { animFrameData[i++] = MathExt.GetFloat(splt[ww]); } } /* Build frame skeleton from the collected data */ BuildFrameSkeleton(ref jointInfos, ref baseFrame, ref animFrameData, frame_index, anim.numJoints, ref anim); } } anim.curFrame = 0; anim.nextFrame = 1; anim.lastTime = 0; anim.maxTime = 1.0f / anim.frameRate; /* Allocate memory for animated skeleton */ skeleton = new MD5Joint[anim.numJoints]; animated = true; Vector3 min = new Vector3(9999, 9999, 9999); Vector3 max = new Vector3(-9999, -9999, -9999); // laske bboxit for (int q = 0; q < anim.numFrames; q++) { if (anim.bboxes[q].min.X < min.X) { min.X = anim.bboxes[q].min.X; } if (anim.bboxes[q].min.Y < min.Y) { min.Y = anim.bboxes[q].min.Y; } if (anim.bboxes[q].min.Z < min.Z) { min.Z = anim.bboxes[q].min.Z; } if (anim.bboxes[q].max.X > max.X) { max.X = anim.bboxes[q].max.X; } if (anim.bboxes[q].max.Y > max.Y) { max.Y = anim.bboxes[q].max.Y; } if (anim.bboxes[q].max.Z > max.Z) { max.Z = anim.bboxes[q].max.Z; } } Boundings = new BoundingSphere(); Boundings.CreateBoundingVolume(this, min, max); Update(0); animations.Add(anim); Log.WriteLine("Animation: " + fileName, false); SetAnimation(animName); } }
/// <summary> /// luo luuranko. /// </summary> void BuildFrameSkeleton(ref MD5JointInfo[] jointInfos, ref MD5BaseFrameJoint[] baseFrame, ref float[] animFrameData, int frameIndex, int num_joints, ref Animation md5anim) { for (int i = 0; i < num_joints; ++i) { MD5BaseFrameJoint baseJoint = baseFrame[i]; Vector3 animatedPos; Quaternion animatedOrient; int j = 0; animatedPos = baseJoint.pos; animatedOrient = baseJoint.orient; if ((jointInfos[i].flags & 1) > 0) /* Tx */ { animatedPos.X = animFrameData[jointInfos[i].startIndex + j]; ++j; } if ((jointInfos[i].flags & 2) > 0) /* Ty */ { animatedPos.Y = animFrameData[jointInfos[i].startIndex + j]; ++j; } if ((jointInfos[i].flags & 4) > 0) /* Tz */ { animatedPos.Z = animFrameData[jointInfos[i].startIndex + j]; ++j; } if ((jointInfos[i].flags & 8) > 0) /* Qx */ { animatedOrient.X = animFrameData[jointInfos[i].startIndex + j]; ++j; } if ((jointInfos[i].flags & 16) > 0) /* Qy */ { animatedOrient.Y = animFrameData[jointInfos[i].startIndex + j]; ++j; } if ((jointInfos[i].flags & 32) > 0) /* Qz */ { animatedOrient.Z = animFrameData[jointInfos[i].startIndex + j]; ++j; } /* Compute orient quaternion's w value */ QuaternionExt.ComputeW(ref animatedOrient); int parent = jointInfos[i].parent; md5anim.skelFrames[frameIndex, i].parent = parent; md5anim.skelFrames[frameIndex, i].name = jointInfos[i].name; /* Has parent? */ if (md5anim.skelFrames[frameIndex, i].parent < 0) { md5anim.skelFrames[frameIndex, i].pos = animatedPos; md5anim.skelFrames[frameIndex, i].orient = animatedOrient; } else { MD5Joint parentJoint = md5anim.skelFrames[frameIndex, parent]; Vector3 rpos; /* Rotated Position */ /* Add positions */ rpos = QuaternionExt.RotatePoint(parentJoint.orient, animatedPos); md5anim.skelFrames[frameIndex, i].pos.X = rpos.X + parentJoint.pos.X; md5anim.skelFrames[frameIndex, i].pos.Y = rpos.Y + parentJoint.pos.Y; md5anim.skelFrames[frameIndex, i].pos.Z = rpos.Z + parentJoint.pos.Z; /* Concatenate rotations */ md5anim.skelFrames[frameIndex, i].orient = Quaternion.Multiply(parentJoint.orient, animatedOrient); md5anim.skelFrames[frameIndex, i].orient = Quaternion.Normalize(md5anim.skelFrames[frameIndex, i].orient); } } }
void LoadMD5(string fileName) { Name = fileName; // Initialize everything string line, textureName = ""; int i; Buffer t = new Buffer(); meshCount = 0; using (System.IO.StreamReader file = new System.IO.StreamReader(Settings.ModelDir + fileName)) { { while ((line = file.ReadLine()) != null) { Cleanstring(ref line); // Read number of joints if (ParseLine(ref t, line, "numJoints %d")) { numJoints = t.ibuffer[0]; baseSkel = new MD5Joint[numJoints]; } // Read number os meshes if (ParseLine(ref t, line, "numMeshes %d")) { numMesh = t.ibuffer[0]; model = new MD5Mesh[numMesh]; meshes = new List <Vertex[]>(numMesh); } // Parse model joints if (line.Equals("joints {")) { for (i = 0; i < numJoints; i++) { line = file.ReadLine(); Cleanstring(ref line); ParseLine(ref t, line, "%s %d ( %f %f %f ) ( %f %f %f )"); baseSkel[i].name = t.sbuffer; baseSkel[i].parent = t.ibuffer[0]; baseSkel[i].pos.X = t.fbuffer[0]; baseSkel[i].pos.Y = t.fbuffer[1]; baseSkel[i].pos.Z = t.fbuffer[2]; baseSkel[i].orient = new Quaternion(t.fbuffer[3], t.fbuffer[4], t.fbuffer[5], 1); QuaternionExt.ComputeW(ref baseSkel[i].orient); } } // Parse model meshes if (line.Equals("mesh {")) { while (!line.Equals("}")) { line = file.ReadLine(); Cleanstring(ref line); // Read texture name if (line.StartsWith("shader")) { string str = line.Substring(7); textureName = Settings.TextureDir + str; textureName = textureName.Replace(",", "."); } // Read mesh data if (ParseLine(ref t, line, "numverts %d")) { model[meshCount].numVert = t.ibuffer[0]; model[meshCount].verts = new MD5Vertex[model[meshCount].numVert]; model[meshCount].texture = Texture.Load(textureName); for (i = 0; i < model[meshCount].numVert; i++) { line = file.ReadLine(); ParseLine(ref t, line, "vert %d ( %f %f ) %d %d"); model[meshCount].verts[t.ibuffer[0]].uv.X = t.fbuffer[0]; model[meshCount].verts[t.ibuffer[0]].uv.Y = 1 - t.fbuffer[1]; model[meshCount].verts[t.ibuffer[0]].startw = t.ibuffer[1]; model[meshCount].verts[t.ibuffer[0]].countw = t.ibuffer[2]; } } if (ParseLine(ref t, line, "numtris %d")) { model[meshCount].numTris = t.ibuffer[0]; model[meshCount].faces = new int[model[meshCount].numTris][]; for (i = 0; i < model[meshCount].numTris; i++) { line = file.ReadLine(); ParseLine(ref t, line, "tri %d %d %d %d"); model[meshCount].faces[t.ibuffer[0]] = new int[3]; model[meshCount].faces[t.ibuffer[0]][0] = t.ibuffer[3]; // poly toisin päin model[meshCount].faces[t.ibuffer[0]][1] = t.ibuffer[2]; model[meshCount].faces[t.ibuffer[0]][2] = t.ibuffer[1]; } } if (ParseLine(ref t, line, "numweights %d")) { model[meshCount].numWeights = t.ibuffer[0]; model[meshCount].weights = new MD5Weight[model[meshCount].numWeights]; for (i = 0; i < model[meshCount].numWeights; i++) { line = file.ReadLine(); ParseLine(ref t, line, "weight %d %d %f ( %f %f %f )"); model[meshCount].weights[t.ibuffer[0]].joint = t.ibuffer[1]; model[meshCount].weights[t.ibuffer[0]].bias = t.fbuffer[0]; model[meshCount].weights[t.ibuffer[0]].pos.X = t.fbuffer[1]; model[meshCount].weights[t.ibuffer[0]].pos.Y = t.fbuffer[2]; model[meshCount].weights[t.ibuffer[0]].pos.Z = t.fbuffer[3]; } } } meshCount++; } } } } int maxvert = 0; for (int k = 0; k < numMesh; k++) { if (model[k].numVert > maxvert) { maxvert = model[k].numVert; } } for (int k = 0; k < numMesh; k++) { finalVert = new Vector3[maxvert]; normals = new Vector3[maxvert]; } skeleton = baseSkel; // prepare model for rendering PrepareMesh(); for (int q = 0; q < numMesh; q++) { Vertex[] v = meshes[q]; ushort[] ind = new ushort[v.Length]; for (ushort w = 0; w < ind.Length; w++) { ind[w] = w; } // luo vbo ja datat sinne model[q].vbo = new VBO(BufferUsageHint.DynamicDraw); model[q].vbo.DataToVBO(v, ind, VBO.VertexMode.UV1); } // laske normaalit for (int k = 0; k < numMesh; k++) { MathExt.CalcNormals(ref finalVert, ref model[k].faces, ref normals, false); } Log.WriteLine("Model: " + Name, false); }
/* * protected void processLightAttenuation(XmlElement XMLNode, Light pLight) * { * // Process attributes * float range = XML.GetAttribReal(XMLNode, "range"); * float constant = XML.GetAttribReal(XMLNode, "constant"); * float linear = XML.GetAttribReal(XMLNode, "linear"); * float quadratic = XML.GetAttribReal(XMLNode, "quadratic"); * // Setup the light attenuation * pLight.SetAttenuation(range, constant, linear, quadratic); * } * * protected void processLightRange(XmlElement XMLNode, Light pLight) * { * // Process attributes * float inner = XML.GetAttribReal(XMLNode, "inner"); * float outer = XML.GetAttribReal(XMLNode, "outer"); * float falloff = XML.GetAttribReal(XMLNode, "falloff", 1.0f); * // Setup the light range * pLight.SetSpotlightRange(new Radian((Degree)inner), new Radian((Degree)outer), falloff); * } */ protected void processNode(XmlElement XMLNode, Node pParent) { // Construct the node's name String name = XML.GetAttrib(XMLNode, "name"); // Create the scene node Node pNode = new Node(); Vector3 pos = Vector3.Zero, scale = Vector3.Zero; Quaternion orientation = new Quaternion(); // Process other attributes XmlElement pElement; // Process position pElement = (XmlElement)XMLNode.SelectSingleNode("position"); if (pElement != null) { pos = XML.ParseVector3(pElement); } // Process rotation pElement = (XmlElement)XMLNode.SelectSingleNode("rotation"); if (pElement != null) { orientation = XML.ParseOrientation(pElement); } // Process scale pElement = (XmlElement)XMLNode.SelectSingleNode("scale"); if (pElement != null) { scale = XML.ParseVector3(pElement); } // Process ogremesh pElement = (XmlElement)XMLNode.SelectSingleNode("entity"); if (pElement != null) { pNode = processEntity(pElement); if (pNode == null) { return; } // jos .scene tiedostossa näkyy että pathin position, rotation tai scale on muuttunut, // silloin path ei toimi oikein koska niitä ei tässä oteta huomioon ollenkaan // (joten path voi ollaki ihan eri kohdassa missä pitäis). // ratkaisu on että pathia EI liikuteta, pyöritetä eikä skaalata 3dsmaxissa! // pivot point pitää olla origossa ja muokkaukset tehdään vain vertex edit moodissa. } // Process light pElement = (XmlElement)XMLNode.SelectSingleNode("light"); if (pElement != null) { pNode = processLight(pElement); pNode.Rotation = QuaternionExt.QuatToEuler(orientation); pElement = (XmlElement)XMLNode.NextSibling; if (pElement != null) { string nname = XML.GetAttrib(pElement, "name"); if (nname.Contains(".Target")) { Vector3 targetPos; pElement = (XmlElement)pElement.SelectSingleNode("position"); if (pElement != null) { targetPos = XML.ParseVector3(pElement); } else { targetPos = Vector3.Zero; } pNode.OrigOrientationMatrix = Matrix4.LookAt(pos, targetPos, Vector3.UnitY); } pNode.Name = name; pNode.Position = pos; pNode.Scale = scale; pParent.Add(pNode); return; } } // Process camera pElement = (XmlElement)XMLNode.SelectSingleNode("camera"); if (pElement != null) { pNode = processCamera(pElement); pNode.Rotation = QuaternionExt.QuatToEuler(orientation); } // Process childnodes pElement = (XmlElement)XMLNode.SelectSingleNode("node"); while (pElement != null) { processNode(pElement, pNode); pElement = (XmlElement)pElement.NextSibling; } pNode.Name = name; pNode.Position = pos; pNode.Scale = scale; Matrix4Ext.CreateFromQuaternion(ref orientation, out pNode.OrigOrientationMatrix); pParent.Add(pNode); }