このリンクからアニメーションコードを移植しています。MD5モデルの読み込み、線形コードなので、指向性に変わりました。
問題は、モデル全体を読み取ると(正常に実行されると)、デバッガーがコードの別の部分(別のモデルファイル(静的モデル)をロードする場所)でエラーを示すことです。
スタンジ部分はcuzです。整数または浮動小数点変数に数値を書き込もうとすると、ヒープが破損します。文字または文字列に書き込もうとしても、エラーは発生しません。
いくつかのテストで、このエラーは2つのコードが実行された場合にのみ表示されることがわかりました。これは、1つだけが発生した場合、プログラムが正常に動作するためです。
コードは次のとおりです。
MD5ファイルをロードします:(大きいです)
bool AnimationModelClass::LoadMD5Model(ID3D10Device* device, wstring filename)
{
ifstream fin;
char input=' ';
string temp, temp2;
int i;
// Crear temp2
temp2.clear();
// Open the model file.
fin.open(filename);
// If it could not open the file then exit.
if(fin.fail())
{
return false;
}
// Look for MD5 Version
temp.clear();
continue_after_string(fin, "MD5Version");
// Store MD5 Version
fin >> MD5Model.version;
// Look for Command Line
temp.clear();
continue_after_string(fin, "commandline");
// Skip line
skip_lines(fin, 1);
// Look for the number of joints
temp.clear();
continue_after_string(fin, "numJoints");
// Store the number of meshes (subsets)
fin >> MD5Model.numJoints;
// Look for the number of joints
temp.clear();
continue_after_string(fin, "numMeshes");
// Store the number of joints
fin >> MD5Model.numSubsets;
// Look for the joints
temp.clear();
continue_after_string(fin, "joints");
continue_after_char(fin, '{');
// Skip the rest of this line
skip_lines(fin, 1);
// - JOINTS - //
// Fill each joint information
Joint tempJoint;
for(i=0; i < MD5Model.numJoints; i++){
// Jump to name
skip_chars(fin, 3, input);
temp.clear();
// Find closing brackets
while(input!='"')
{
temp+=input;
fin.get(input);
}
// Store tempJoint name
tempJoint.name = temp;
// Storte parent ID
fin >> tempJoint.parentID;
// Find the positions of this joint
continue_after_char(fin, '(');
// Store the positions
fin >> tempJoint.pos.x >> tempJoint.pos.z >> tempJoint.pos.y;
// Find the orientation of this joint
continue_after_char(fin, ')');
continue_after_char(fin, '(');
// Store orientation
fin >> tempJoint.orientation.x >> tempJoint.orientation.z >> tempJoint.orientation.y;
// Compute the w axis of the quaternion (The MD5 model uses a 3D vector to describe the
// direction the bone is facing. However, we need to turn this into a quaternion, and the way
// quaternions work, is the xyz values describe the axis of rotation, while the w is a value
// between 0 and 1 which describes the angle of rotation)
float t = 1.0f - ( tempJoint.orientation.x * tempJoint.orientation.x ) - ( tempJoint.orientation.y * tempJoint.orientation.y ) - ( tempJoint.orientation.z * tempJoint.orientation.z );
if ( t < 0.0f )
{
tempJoint.orientation.w = 0.0f;
}
else
{
tempJoint.orientation.w = -sqrtf(t);
}
// Skip the rest of this line
skip_lines(fin, 1);
// Store the joint into this models joint vector
MD5Model.joints.push_back(tempJoint);
}
// Skip "}"
continue_after_char(fin, '}');
// Find meshes
continue_after_string(fin, "mesh");
// Skip "{"
continue_after_char(fin, '{');
temp.clear();
// Variables to fill model subsets
ModelSubset subset;
int numVerts, numTris, numWeights;
// End of file controller
bool eof = false;
int gg=0;
// Read until EOF
while(!eof){
// Clear the temp string
temp.clear();
// Read until "}"
while(temp!= "}"){
if(!get_string(fin, temp)){
// Break if we cant read anymore
eof = true;
break;
}
// Case we found shader
if(temp == "shader"){
// Store it
get_string(fin, subset.fileNamePath);
// Skip the rest of this line
skip_lines(fin, 1);
// CHECAR SE A TEXTURA FOI CARREGADA E CARREGA-LA SE NECESSÁRIO
}
// Case we found tex vertices
else if(temp == "numverts"){
// Store the number of tex vertices
fin >> numVerts;
// Skip the rest of this line
skip_lines(fin, 1);
// Store stuff for each tex vertice
for(int i = 0; i < numVerts; i++)
{
Vertex tempVert;
// Skip "vert # ("
continue_after_char(fin, '(');
fin >> tempVert.texCoord.x;
fin >> tempVert.texCoord.y;
// Skip ")"
continue_after_char(fin, ')');
fin >> tempVert.StartWeight;
fin >> tempVert.WeightCount;
// Skip the rest of this line
skip_lines(fin, 1);
// Push back this vertex into subsets vertex vector
subset.vertices.push_back(tempVert);
}
}
// Case we found the triangles
else if(temp == "numtris"){
// Store the number of triangles
fin >> numTris;
subset.numTriangles = numTris;
// Skip the rest of this line
skip_lines(fin, 1);
// Save stuff for each triangle
for(int i = 0; i < numTris; i++)
{
DWORD tempIndex;
// Skip "tri"
get_string(fin, temp);
// Skip tri counter
get_string(fin, temp);
// Store the 3 indices
for(int k = 0; k < 3; k++)
{
fin >> tempIndex;
subset.indices.push_back(tempIndex);
}
// Skip the rest of this line
skip_lines(fin, 1);
}
}
// Case we found the weights
else if(temp == "numweights"){
// Store the number of weights
fin >> numWeights;
// Skip the rest of this line
skip_lines(fin, 1);
// Save stuff for each weight
for(int i = 0; i < numWeights; i++)
{
Weight tempWeight;
// Skip "weight"
get_string(fin, temp);
// Skip "#"
get_string(fin, temp);
// Store weight's joint ID
fin >> tempWeight.jointID;
// Store weight's influence over a vertex
fin >> tempWeight.bias;
// Skip "("
continue_after_char(fin, '(');
// Store weight's pos in joint's local space
fin >> tempWeight.pos.x >> tempWeight.pos.z >> tempWeight.pos.y;
// Skip the rest of this line
skip_lines(fin, 1);
// Push back tempWeight into subsets Weight array
subset.weights.push_back(tempWeight);
}
}
}
//*** find each vertex's position using the joints and weights
for ( int i = 0; i < subset.vertices.size(); ++i )
{
Vertex tempVert = subset.vertices[i];
tempVert.pos = D3DXVECTOR3(0, 0, 0); // Make sure the vertex's pos is cleared first
// Sum up the joints and weights information to get vertex's position
for ( int j = 0; j < tempVert.WeightCount; ++j )
{
Weight tempWeight = subset.weights[tempVert.StartWeight + j];
Joint tempJoint = MD5Model.joints[tempWeight.jointID];
// Convert joint orientation and weight pos to vectors for easier computation
// When converting a 3d vector to a quaternion, you should put 0 for "w", and
// When converting a quaternion to a 3d vector, you can just ignore the "w"
D3DXQUATERNION tempJointOrientation = D3DXQUATERNION(tempJoint.orientation.x, tempJoint.orientation.y, tempJoint.orientation.z, tempJoint.orientation.w);
D3DXQUATERNION tempWeightPos = D3DXQUATERNION(tempWeight.pos.x, tempWeight.pos.y, tempWeight.pos.z, 0.0f);
// We will need to use the conjugate of the joint orientation quaternion
// To get the conjugate of a quaternion, all you have to do is inverse the x, y, and z
D3DXQUATERNION tempJointOrientationConjugate = D3DXQUATERNION(-tempJoint.orientation.x, -tempJoint.orientation.y, -tempJoint.orientation.z, tempJoint.orientation.w);
// Calculate vertex position (in joint space, eg. rotate the point around (0,0,0)) for this weight using the joint orientation quaternion and its conjugate
// We can rotate a point using a quaternion with the equation "rotatedPoint = quaternion * point * quaternionConjugate"
D3DXVECTOR3 rotatedPoint;
D3DXQUATERNION temp;
D3DXQuaternionMultiply(&temp, &tempJointOrientation, &tempWeightPos);
D3DXQuaternionMultiply(&temp, &temp, &tempJointOrientationConjugate);
rotatedPoint.x = temp.x;
rotatedPoint.y = temp.y;
rotatedPoint.z = temp.z;
// Now move the verices position from joint space (0,0,0) to the joints position in world space, taking the weights bias into account
// The weight bias is used because multiple weights might have an effect on the vertices final position. Each weight is attached to one joint.
tempVert.pos.x += ( tempJoint.pos.x + rotatedPoint.x ) * tempWeight.bias;
tempVert.pos.y += ( tempJoint.pos.y + rotatedPoint.y ) * tempWeight.bias;
tempVert.pos.z += ( tempJoint.pos.z + rotatedPoint.z ) * tempWeight.bias;
// Basically what has happened above, is we have taken the weights position relative to the joints position
// we then rotate the weights position (so that the weight is actually being rotated around (0, 0, 0) in world space) using
// the quaternion describing the joints rotation. We have stored this rotated point in rotatedPoint, which we then add to
// the joints position (because we rotated the weight's position around (0,0,0) in world space, and now need to translate it
// so that it appears to have been rotated around the joints position). Finally we multiply the answer with the weights bias,
// or how much control the weight has over the final vertices position. All weight's bias effecting a single vertex's position
// must add up to 1.
}
subset.positions.push_back(tempVert.pos); // Store the vertices position in the position vector instead of straight into the vertex vector
// since we can use the positions vector for certain things like collision detection or picking
// without having to work with the entire vertex structure.
}
// Put the positions into the vertices for this subset
for(int i = 0; i < subset.vertices.size(); i++)
{
subset.vertices[i].pos = subset.positions[i];
}
//*** Calculate vertex normals using normal averaging
vector<D3DXVECTOR3> tempNormal;
//normalized and unnormalized normals
D3DXVECTOR3 unnormalized = D3DXVECTOR3(0.0f, 0.0f, 0.0f);
//Used to get vectors (sides) from the position of the verts
float vecX, vecY, vecZ;
//Two edges of our triangle
D3DXQUATERNION edge1 = D3DXQUATERNION(0.0f, 0.0f, 0.0f, 0.0f);
D3DXQUATERNION edge2 = D3DXQUATERNION(0.0f, 0.0f, 0.0f, 0.0f);
//Compute face normals
for(int i = 0; i < subset.numTriangles; ++i)
{
//Get the vector describing one edge of our triangle (edge 0,2)
vecX = subset.vertices[subset.indices[(i*3)]].pos.x - subset.vertices[subset.indices[(i*3)+2]].pos.x;
vecY = subset.vertices[subset.indices[(i*3)]].pos.y - subset.vertices[subset.indices[(i*3)+2]].pos.y;
vecZ = subset.vertices[subset.indices[(i*3)]].pos.z - subset.vertices[subset.indices[(i*3)+2]].pos.z;
edge1 = D3DXQUATERNION(vecX, vecY, vecZ, 0.0f); //Create our first edge
//Get the vector describing another edge of our triangle (edge 2,1)
vecX = subset.vertices[subset.indices[(i*3)+2]].pos.x - subset.vertices[subset.indices[(i*3)+1]].pos.x;
vecY = subset.vertices[subset.indices[(i*3)+2]].pos.y - subset.vertices[subset.indices[(i*3)+1]].pos.y;
vecZ = subset.vertices[subset.indices[(i*3)+2]].pos.z - subset.vertices[subset.indices[(i*3)+1]].pos.z;
edge2 = D3DXQUATERNION(vecX, vecY, vecZ, 0.0f); //Create our second edge
//Cross multiply the two edge vectors to get the un-normalized face normal
unnormalized.x = (edge1.y * edge2.z) - (edge1.z * edge2.y);
unnormalized.y = (edge1.z * edge2.x) - (edge1.x * edge2.z);
unnormalized.z = (edge1.x * edge2.y) - (edge1.y * edge2.x);
tempNormal.push_back(unnormalized);
}
//Compute vertex normals (normal Averaging)
D3DXQUATERNION normalSum = D3DXQUATERNION(0.0f, 0.0f, 0.0f, 0.0f);
int facesUsing = 0;
float tX, tY, tZ; //temp axis variables
//Go through each vertex
for(int i = 0; i < subset.vertices.size(); ++i)
{
//Check which triangles use this vertex
for(int j = 0; j < subset.numTriangles; ++j)
{
if(subset.indices[j*3] == i ||
subset.indices[(j*3)+1] == i ||
subset.indices[(j*3)+2] == i)
{
tX = normalSum.x + tempNormal[j].x;
tY = normalSum.y + tempNormal[j].y;
tZ = normalSum.z + tempNormal[j].z;
normalSum = D3DXQUATERNION(tX, tY, tZ, 0.0f); //If a face is using the vertex, add the unormalized face normal to the normalSum
facesUsing++;
}
}
//Get the actual normal by dividing the normalSum by the number of faces sharing the vertex
normalSum = normalSum / facesUsing;
//Normalize the normalSum vector
D3DXVECTOR3 temp;
temp.x = normalSum.x;
temp.y = normalSum.y;
temp.z = normalSum.z;
D3DXVec3Normalize(&temp, &temp);
//Store the normal and tangent in our current vertex
subset.vertices[i].normal.x = -temp.x;
subset.vertices[i].normal.y = -temp.y;
subset.vertices[i].normal.z = -temp.z;
//Clear normalSum, facesUsing for next vertex
normalSum = D3DXQUATERNION(0.0f, 0.0f, 0.0f, 0.0f);
facesUsing = 0;
}
// Create index buffer
D3D10_BUFFER_DESC indexBufferDesc;
ZeroMemory( &indexBufferDesc, sizeof(indexBufferDesc) );
indexBufferDesc.Usage = D3D10_USAGE_DEFAULT;
indexBufferDesc.ByteWidth = sizeof(DWORD) * subset.numTriangles * 3;
indexBufferDesc.BindFlags = D3D10_BIND_INDEX_BUFFER;
indexBufferDesc.CPUAccessFlags = 0;
indexBufferDesc.MiscFlags = 0;
D3D10_SUBRESOURCE_DATA iinitData;
iinitData.pSysMem = &subset.indices[0];
device->CreateBuffer(&indexBufferDesc, &iinitData, &subset.indexBuff);
//Create Vertex Buffer
D3D10_BUFFER_DESC vertexBufferDesc;
ZeroMemory( &vertexBufferDesc, sizeof(vertexBufferDesc) );
vertexBufferDesc.Usage = D3D10_USAGE_DYNAMIC; // We will be updating this buffer, so we must set as dynamic
vertexBufferDesc.ByteWidth = sizeof( Vertex ) * subset.vertices.size();
vertexBufferDesc.BindFlags = D3D10_BIND_VERTEX_BUFFER;
vertexBufferDesc.CPUAccessFlags = D3D10_CPU_ACCESS_WRITE; // Give CPU power to write to buffer
vertexBufferDesc.MiscFlags = 0;
D3D10_SUBRESOURCE_DATA vertexBufferData;
ZeroMemory( &vertexBufferData, sizeof(vertexBufferData) );
vertexBufferData.pSysMem = &subset.vertices[0];
HRESULT hr;
hr = device->CreateBuffer( &vertexBufferDesc, &vertexBufferData, &subset.vertBuff);
// Push back the temp subset into the models subset vector
MD5Model.subsets.push_back(subset);
if(eof == true){
break;
}
i=i;
}
fin.clear();
fin.close();
return true;
}
そしてここに別のコード:(ここにヒープの問題があります!)
bool ModelClass::LoadModel(char* filename)
{
ifstream fin;
char input;
int i;
// Open the model file.
fin.open(filename);
// If it could not open the file then exit.
if(fin.fail())
{
return false;
}
// Read up to the value of vertex count.
fin.get(input);
while(input != ':')
{
fin.get(input);
}
// Read in the vertex count.
fin >> m_vertexCount;
// Set the number of indices to be the same as the vertex count.
m_indexCount = m_vertexCount;
// Create the model using the vertex count that was read in.
m_model = new ModelType[m_vertexCount];
if(!m_model)
{
return false;
}
// Read up to the beginning of the data.
fin.get(input);
while(input != ':')
{
fin.get(input);
}
fin.get(input);
fin.get(input);
// Read in the vertex data.
for(i=0; i<m_vertexCount; i++)
{
///////////// HERE IS THE PROBLEM!! //////////////
fin >> m_model[i].x >> m_model[i].y >> m_model[i].z;
fin >> m_model[i].tu >> m_model[i].tv;
fin >> m_model[i].nx >> m_model[i].ny >> m_model[i].nz;
}
// Close the model file.
fin.close();
return true;
}
ブレークポイントの配置をテストしましたが、問題はそこにあります(上記)。
私がこれを行う場合:
// Read in the vertex data.
for(i=0; i<m_vertexCount; i++)
{
char a;
fin >> a;
}
それは動作します...しかし、私がこれを行う場合、なぜ私は知りません:
// Read in the vertex data.
for(i=0; i<m_vertexCount; i++)
{
float f; // or int, but float is what I want
fin >> f;
}
バン、ヒープの破損!
上で述べたように、両方のコードは適切に分離されて機能します。
英語が下手でごめんなさい。
誰かが助けることができるなら、これは私を悩ませています...:D
Obs:順序を切り替えると、両方が機能し(これらのコード)、ヒープの破損は発生しません