Is unidentified
I was making a script for my models #include "Boxer.h" #include "Controller.h" Boxer::Boxer() { } Boxer::~Boxer() { } void Boxer::InitBoxer() { if (!LoadMD5Model(L"Female.md5mesh", NewMD5Model, meshSRV, textureNameArray)) return false; if (!LoadMD5Anim(L"Female.md5anim", NewMD5Model)) return false; } void Boxer::MoveBoxer(double time, XMVECTOR & destinationDirection, XMMATRIX & worldMatrix) { // Normalize our destinated direction vector destinationDirection = XMVector3Normalize(destinationDirection); // If character is currently facing the complete opposite direction as the desired direction // they will turn around VERY slowly, so we want to make sure they turn around at a normal speed // by making the old character direction not the exact opposite direction as the current character // position. Try commenting out the next two lines to see what i'm talking about if (XMVectorGetX(XMVector3Dot(destinationDirection, oldBoxerDirection)) == -1) oldBoxerDirection += XMVectorSet(0.02f, 0.0f, -0.02f, 0.0f); // Get our current characters position in the world, from it's world matrix boxerPosition = XMVectorSet(0.0f, 0.0f, 0.0f, 0.0f); boxerPosition = XMVector3TransformCoord(boxerPosition, worldMatrix); // Rotate our character smoothly when changing direction (from the GPG series) float destDirLength = 10.0f * frameTime; // Change to the speed you want your character to rotate. This uses the game timer from an earlier lesson // The larget this value, the faster the character rotates currBoxerDirection = oldBoxerDirection + (destinationDirection * destDirLength); // Get the characters direction (based off time, old position, and desired // direction), by adding together the current direction and the old direction // to get vector that smoothly turns from oldCharDir to denstinationDirection currBoxerDirection = XMVector3Normalize(currBoxerDirection); // Normalize the characters current direction vector // Here we find the angle of our character (angle between current direction and world's normal vector), used so that we can actually rotate // our characters world matrix. The three lines below, together, find the angle between 0 PI and 2 PI (360 degrees, and technically, it returns // the degrees in radians from -1 PI to 1 PI, but that has the same effect as 0 PI to 2 PI) between two vectors. // XMVector3AngleBetweenNormals returns an angle between two vectors, but always a positive result between // 0 and 1 PI. Which means, it doesn't tell us which half of the 2 PI degrees that are possible. So, we have the next if statement below, // which crosses the current characters direction and the worlds forward (0,0,1), which should give us the y axis vector (assuming that our character // rotates on the xz plane). We check to see if the y vector is positive ( > 0.0f), and if it is, we set the characters direction angle to be // the opposite of what it currently is, giving us the result in -1 PI to 1 PI. float boxerDirAngle = XMVectorGetX(XMVector3AngleBetweenNormals(XMVector3Normalize(currBoxerDirection), XMVector3Normalize(DefaultForward))); if (XMVectorGetY(XMVector3Cross(currBoxerDirection, DefaultForward)) > 0.0f) boxerDirAngle = -boxerDirAngle; // Now we update our characters position based off the frame time, his old position, and the direction he is facing float speed = 15.0f * frameTime; boxerPosition = boxerPosition + (destinationDirection * speed); // Update characters world matrix XMMATRIX rotationMatrix; Scale = XMMatrixScaling(0.25f, 0.25f, 0.25f); Translation = XMMatrixTranslation(XMVectorGetX(boxerPosition), 0.0f, XMVectorGetZ(boxerPosition)); rotationMatrix = XMMatrixRotationY(boxerDirAngle - 3.14159265f); // Subtract PI from angle so the character doesn't run backwards worldMatrix = Scale * rotationMatrix * Translation; // Set the characters old direction oldBoxerDirection = currBoxerDirection; // Update our animation float timeFactor = 1.0f; // You can speed up or slow down time by changing this UpdateMD5Model(NewMD5Model, time*timeFactor, 0); } void Boxer::DetectInput(double time) { Player1 = new Controller(1); if (Player1->IsConnected()) { if (Player1->GetState().Gamepad.wButtons & XINPUT_GAMEPAD_A) { Player1->Vibrate(65535, 0); } if (Player1->GetState().Gamepad.wButtons & XINPUT_GAMEPAD_B) { Player1->Vibrate(0, 65535); } if (Player1->GetState().Gamepad.wButtons & XINPUT_GAMEPAD_X) { Player1->Vibrate(65535, 65535); } if (Player1->GetState().Gamepad.wButtons & XINPUT_GAMEPAD_Y) { Player1->Vibrate(); } if (Player1->GetState().Gamepad.wButtons & XINPUT_GAMEPAD_BACK) { } } } bool LoadMD5Anim(std::wstring filename, Model3D& MD5Model) { ModelAnimation tempAnim; // Temp animation to later store in our model's animation array std::wifstream fileIn(filename.c_str()); // Open file std::wstring checkString; // Stores the next string from our file if (fileIn) // Check if the file was opened { while (fileIn) // Loop until the end of the file is reached { fileIn >> checkString; // Get next string from file if (checkString == L"MD5Version") // Get MD5 version (this function supports version 10) { fileIn >> checkString; /*MessageBox(0, checkString.c_str(), //display message L"MD5Version", MB_OK);*/ } else if (checkString == L"commandline") { std::getline(fileIn, checkString); // Ignore the rest of this line } else if (checkString == L"numFrames") { fileIn >> tempAnim.numFrames; // Store number of frames in this animation } else if (checkString == L"numJoints") { fileIn >> tempAnim.numJoints; // Store number of joints (must match .md5mesh) } else if (checkString == L"frameRate") { fileIn >> tempAnim.frameRate; // Store animation's frame rate (frames per second) } else if (checkString == L"numAnimatedComponents") { fileIn >> tempAnim.numAnimatedComponents; // Number of components in each frame section } else if (checkString == L"hierarchy") { fileIn >> checkString; // Skip opening bracket "{" for (int i = 0; i < tempAnim.numJoints; i++) // Load in each joint { AnimJointInfo tempJoint; fileIn >> tempJoint.name; // Get joints name // Sometimes the names might contain spaces. If that is the case, we need to continue // to read the name until we get to the closing " (quotation marks) if (tempJoint.name[tempJoint.name.size() - 1] != '"') { wchar_t checkChar; bool jointNameFound = false; while (!jointNameFound) { checkChar = fileIn.get(); if (checkChar == '"') jointNameFound = true; tempJoint.name += checkChar; } } // Remove the quotation marks from joints name tempJoint.name.erase(0, 1); tempJoint.name.erase(tempJoint.name.size() - 1, 1); fileIn >> tempJoint.parentID; // Get joints parent ID fileIn >> tempJoint.flags; // Get flags fileIn >> tempJoint.startIndex; // Get joints start index // Make sure the joint exists in the model, and the parent ID's match up // because the bind pose (md5mesh) joint hierarchy and the animations (md5anim) // joint hierarchy must match up bool jointMatchFound = false; for (int k = 0; k < MD5Model.numJoints; k++) { if (MD5Model.joints[k].name == tempJoint.name) { if (MD5Model.joints[k].parentID == tempJoint.parentID) { jointMatchFound = true; tempAnim.jointInfo.push_back(tempJoint); } } } if (!jointMatchFound) // If the skeleton system does not match up, return false return false; // You might want to add an error message here std::getline(fileIn, checkString); // Skip rest of this line } } else if (checkString == L"bounds") // Load in the AABB for each animation { fileIn >> checkString; // Skip opening bracket "{" for (int i = 0; i < tempAnim.numFrames; i++) { BoundingBox tempBB; fileIn >> checkString; // Skip "(" fileIn >> tempBB.min.x >> tempBB.min.z >> tempBB.min.y; fileIn >> checkString >> checkString; // Skip ") (" fileIn >> tempBB.max.x >> tempBB.max.z >> tempBB.max.y; fileIn >> checkString; // Skip ")" tempAnim.frameBounds.push_back(tempBB); } } else if (checkString == L"baseframe") // This is the default position for the animation { // All frames will build their skeletons off this fileIn >> checkString; // Skip opening bracket "{" for (int i = 0; i < tempAnim.numJoints; i++) { Joint tempBFJ; fileIn >> checkString; // Skip "(" fileIn >> tempBFJ.pos.x >> tempBFJ.pos.z >> tempBFJ.pos.y; fileIn >> checkString >> checkString; // Skip ") (" fileIn >> tempBFJ.orientation.x >> tempBFJ.orientation.z >> tempBFJ.orientation.y; fileIn >> checkString; // Skip ")" tempAnim.baseFrameJoints.push_back(tempBFJ); } } else if (checkString == L"frame") // Load in each frames skeleton (the parts of each joint that changed from the base frame) { FrameData tempFrame; fileIn >> tempFrame.frameID; // Get the frame ID fileIn >> checkString; // Skip opening bracket "{" for (int i = 0; i < tempAnim.numAnimatedComponents; i++) { float tempData; fileIn >> tempData; // Get the data tempFrame.frameData.push_back(tempData); } tempAnim.frameData.push_back(tempFrame); ///*** build the frame skeleton ***/// std::vector<Joint> tempSkeleton; for (int i = 0; i < tempAnim.jointInfo.size(); i++) { int k = 0; // Keep track of position in frameData array // Start the frames joint with the base frame's joint Joint tempFrameJoint = tempAnim.baseFrameJoints[i]; tempFrameJoint.parentID = tempAnim.jointInfo[i].parentID; // Notice how I have been flipping y and z. this is because some modeling programs such as // 3ds max (which is what I use) use a right handed coordinate system. Because of this, we // need to flip the y and z axes. If your having problems loading some models, it's possible // the model was created in a left hand coordinate system. in that case, just reflip all the // y and z axes in our md5 mesh and anim loader. if (tempAnim.jointInfo[i].flags & 1) // pos.x ( 000001 ) tempFrameJoint.pos.x = tempFrame.frameData[tempAnim.jointInfo[i].startIndex + k++]; if (tempAnim.jointInfo[i].flags & 2) // pos.y ( 000010 ) tempFrameJoint.pos.z = tempFrame.frameData[tempAnim.jointInfo[i].startIndex + k++]; if (tempAnim.jointInfo[i].flags & 4) // pos.z ( 000100 ) tempFrameJoint.pos.y = tempFrame.frameData[tempAnim.jointInfo[i].startIndex + k++]; if (tempAnim.jointInfo[i].flags & 8) // orientation.x ( 001000 ) tempFrameJoint.orientation.x = tempFrame.frameData[tempAnim.jointInfo[i].startIndex + k++]; if (tempAnim.jointInfo[i].flags & 16) // orientation.y ( 010000 ) tempFrameJoint.orientation.z = tempFrame.frameData[tempAnim.jointInfo[i].startIndex + k++]; if (tempAnim.jointInfo[i].flags & 32) // orientation.z ( 100000 ) tempFrameJoint.orientation.y = tempFrame.frameData[tempAnim.jointInfo[i].startIndex + k++]; // Compute the quaternions w float t = 1.0f - (tempFrameJoint.orientation.x * tempFrameJoint.orientation.x) - (tempFrameJoint.orientation.y * tempFrameJoint.orientation.y) - (tempFrameJoint.orientation.z * tempFrameJoint.orientation.z); if (t < 0.0f) { tempFrameJoint.orientation.w = 0.0f; } else { tempFrameJoint.orientation.w = -sqrtf(t); } // Now, if the upper arm of your skeleton moves, you need to also move the lower part of your arm, and then the hands, and then finally the fingers (possibly weapon or tool too) // This is where joint hierarchy comes in. We start at the top of the hierarchy, and move down to each joints child, rotating and translating them based on their parents rotation // and translation. We can assume that by the time we get to the child, the parent has already been rotated and transformed based of it's parent. We can assume this because // the child should never come before the parent in the files we loaded in. if (tempFrameJoint.parentID >= 0) { Joint parentJoint = tempSkeleton[tempFrameJoint.parentID]; // Turn the XMFLOAT3 and 4's into vectors for easier computation XMVECTOR parentJointOrientation = XMVectorSet(parentJoint.orientation.x, parentJoint.orientation.y, parentJoint.orientation.z, parentJoint.orientation.w); XMVECTOR tempJointPos = XMVectorSet(tempFrameJoint.pos.x, tempFrameJoint.pos.y, tempFrameJoint.pos.z, 0.0f); XMVECTOR parentOrientationConjugate = XMVectorSet(-parentJoint.orientation.x, -parentJoint.orientation.y, -parentJoint.orientation.z, parentJoint.orientation.w); // Calculate current joints position relative to its parents position XMFLOAT3 rotatedPos; XMStoreFloat3(&rotatedPos, XMQuaternionMultiply(XMQuaternionMultiply(parentJointOrientation, tempJointPos), parentOrientationConjugate)); // Translate the joint to model space by adding the parent joint's pos to it tempFrameJoint.pos.x = rotatedPos.x + parentJoint.pos.x; tempFrameJoint.pos.y = rotatedPos.y + parentJoint.pos.y; tempFrameJoint.pos.z = rotatedPos.z + parentJoint.pos.z; // Currently the joint is oriented in its parent joints space, we now need to orient it in // model space by multiplying the two orientations together (parentOrientation * childOrientation) <- In that order XMVECTOR tempJointOrient = XMVectorSet(tempFrameJoint.orientation.x, tempFrameJoint.orientation.y, tempFrameJoint.orientation.z, tempFrameJoint.orientation.w); tempJointOrient = XMQuaternionMultiply(parentJointOrientation, tempJointOrient); // Normalize the orienation quaternion tempJointOrient = XMQuaternionNormalize(tempJointOrient); XMStoreFloat4(&tempFrameJoint.orientation, tempJointOrient); } // Store the joint into our temporary frame skeleton tempSkeleton.push_back(tempFrameJoint); } // Push back our newly created frame skeleton into the animation's frameSkeleton array tempAnim.frameSkeleton.push_back(tempSkeleton); fileIn >> checkString; // Skip closing bracket "}" } } // Calculate and store some usefull animation data tempAnim.frameTime = 1.0f / tempAnim.frameRate; // Set the time per frame tempAnim.totalAnimTime = tempAnim.numFrames * tempAnim.frameTime; // Set the total time the animation takes tempAnim.currAnimTime = 0.0f; // Set the current time to zero MD5Model.animations.push_back(tempAnim); // Push back the animation into our model object } else // If the file was not loaded { SwapChain->SetFullscreenState(false, NULL); // Make sure we are out of fullscreen // create message std::wstring message = L"Could not open: "; message += filename; return false; } return true; } void UpdateMD5Model(Model3D& MD5Model, float deltaTime, int animation) { MD5Model.animations[animation].currAnimTime += deltaTime; // Update the current animation time if (MD5Model.animations[animation].currAnimTime > MD5Model.animations[animation].totalAnimTime) MD5Model.animations[animation].currAnimTime = 0.0f; // Which frame are we on float currentFrame = MD5Model.animations[animation].currAnimTime * MD5Model.animations[animation].frameRate; int frame0 = floorf(currentFrame); int frame1 = frame0 + 1; // Make sure we don't go over the number of frames if (frame0 == MD5Model.animations[animation].numFrames - 1) frame1 = 0; float interpolation = currentFrame - frame0; // Get the remainder (in time) between frame0 and frame1 to use as interpolation factor std::vector<Joint> interpolatedSkeleton; // Create a frame skeleton to store the interpolated skeletons in // Compute the interpolated skeleton for (int i = 0; i < MD5Model.animations[animation].numJoints; i++) { Joint tempJoint; Joint joint0 = MD5Model.animations[animation].frameSkeleton[frame0][i]; // Get the i'th joint of frame0's skeleton Joint joint1 = MD5Model.animations[animation].frameSkeleton[frame1][i]; // Get the i'th joint of frame1's skeleton tempJoint.parentID = joint0.parentID; // Set the tempJoints parent id // Turn the two quaternions into XMVECTORs for easy computations XMVECTOR joint0Orient = XMVectorSet(joint0.orientation.x, joint0.orientation.y, joint0.orientation.z, joint0.orientation.w); XMVECTOR joint1Orient = XMVectorSet(joint1.orientation.x, joint1.orientation.y, joint1.orientation.z, joint1.orientation.w); // Interpolate positions tempJoint.pos.x = joint0.pos.x + (interpolation * (joint1.pos.x - joint0.pos.x)); tempJoint.pos.y = joint0.pos.y + (interpolation * (joint1.pos.y - joint0.pos.y)); tempJoint.pos.z = joint0.pos.z + (interpolation * (joint1.pos.z - joint0.pos.z)); // Interpolate orientations using spherical interpolation (Slerp) XMStoreFloat4(&tempJoint.orientation, XMQuaternionSlerp(joint0Orient, joint1Orient, interpolation)); interpolatedSkeleton.push_back(tempJoint); // Push the joint back into our interpolated skeleton } for (int k = 0; k < MD5Model.numSubsets; k++) { for (int i = 0; i < MD5Model.subsets[k].vertices.size(); ++i) { Vertex tempVert = MD5Model.subsets[k].vertices[i]; tempVert.pos = XMFLOAT3(0, 0, 0); // Make sure the vertex's pos is cleared first tempVert.normal = XMFLOAT3(0, 0, 0); // Clear vertices normal // Sum up the joints and weights information to get vertex's position and normal for (int j = 0; j < tempVert.WeightCount; ++j) { Weight tempWeight = MD5Model.subsets[k].weights[tempVert.StartWeight + j]; Joint tempJoint = interpolatedSkeleton[tempWeight.jointID]; // Convert joint orientation and weight pos to vectors for easier computation XMVECTOR tempJointOrientation = XMVectorSet(tempJoint.orientation.x, tempJoint.orientation.y, tempJoint.orientation.z, tempJoint.orientation.w); XMVECTOR tempWeightPos = XMVectorSet(tempWeight.pos.x, tempWeight.pos.y, tempWeight.pos.z, 0.0f); // We will need to use the conjugate of the joint orientation quaternion XMVECTOR tempJointOrientationConjugate = XMQuaternionInverse(tempJointOrientation); // 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" XMFLOAT3 rotatedPoint; XMStoreFloat3(&rotatedPoint, XMQuaternionMultiply(XMQuaternionMultiply(tempJointOrientation, tempWeightPos), tempJointOrientationConjugate)); // Now move the verices position from joint space (0,0,0) to the joints position in world space, taking the weights bias into account 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; // Compute the normals for this frames skeleton using the weight normals from before // We can comput the normals the same way we compute the vertices position, only we don't have to translate them (just rotate) XMVECTOR tempWeightNormal = XMVectorSet(tempWeight.normal.x, tempWeight.normal.y, tempWeight.normal.z, 0.0f); // Rotate the normal XMStoreFloat3(&rotatedPoint, XMQuaternionMultiply(XMQuaternionMultiply(tempJointOrientation, tempWeightNormal), tempJointOrientationConjugate)); // Add to vertices normal and ake weight bias into account tempVert.normal.x -= rotatedPoint.x * tempWeight.bias; tempVert.normal.y -= rotatedPoint.y * tempWeight.bias; tempVert.normal.z -= rotatedPoint.z * tempWeight.bias; } MD5Model.subsets[k].positions[i] = tempVert.pos; // Store the vertices position in the position vector instead of straight into the vertex vector MD5Model.subsets[k].vertices[i].normal = tempVert.normal; // Store the vertices normal XMStoreFloat3(&MD5Model.subsets[k].vertices[i].normal, XMVector3Normalize(XMLoadFloat3(&MD5Model.subsets[k].vertices[i].normal))); } // Put the positions into the vertices for this subset for (int i = 0; i < MD5Model.subsets[k].vertices.size(); i++) { MD5Model.subsets[k].vertices[i].pos = MD5Model.subsets[k].positions[i]; } // Update the subsets vertex buffer // First lock the buffer D3D11_MAPPED_SUBRESOURCE mappedVertBuff; hr = d3d11DevCon->Map(MD5Model.subsets[k].vertBuff, 0, D3D11_MAP_WRITE_DISCARD, 0, &mappedVertBuff); // Copy the data into the vertex buffer. memcpy(mappedVertBuff.pData, &MD5Model.subsets[k].vertices[0], (sizeof(Vertex) * MD5Model.subsets[k].vertices.size())); d3d11DevCon->Unmap(MD5Model.subsets[k].vertBuff, 0); // The line below is another way to update a buffer. You will use this when you want to update a buffer less // than once per frame, since the GPU reads will be faster (the buffer was created as a DEFAULT buffer instead // of a DYNAMIC buffer), and the CPU writes will be slower. You can try both methods to find out which one is faster // for you. if you want to use the line below, you will have to create the buffer with D3D11_USAGE_DEFAULT instead // of D3D11_USAGE_DYNAMIC //d3d11DevCon->UpdateSubresource( MD5Model.subsets[k].vertBuff, 0, NULL, &MD5Model.subsets[k].vertices[0], 0, 0 ); } } bool LoadMD5Model(std::wstring filename, Model3D& MD5Model, std::vector<ID3D11ShaderResourceView*>& shaderResourceViewArray, std::vector<std::wstring> texFileNameArray) { std::wifstream fileIn(filename.c_str()); // Open file std::wstring checkString; // Stores the next string from our file if (fileIn) // Check if the file was opened { while (fileIn) // Loop until the end of the file is reached { fileIn >> checkString; // Get next string from file if (checkString == L"MD5Version") // Get MD5 version (this function supports version 10) { /*fileIn >> checkString; MessageBox(0, checkString.c_str(), //display message L"MD5Version", MB_OK);*/ } else if (checkString == L"commandline") { std::getline(fileIn, checkString); // Ignore the rest of this line } else if (checkString == L"numJoints") { fileIn >> MD5Model.numJoints; // Store number of joints } else if (checkString == L"numMeshes") { fileIn >> MD5Model.numSubsets; // Store number of meshes or subsets which we will call them } else if (checkString == L"joints") { Joint tempJoint; fileIn >> checkString; // Skip the "{" for (int i = 0; i < MD5Model.numJoints; i++) { fileIn >> tempJoint.name; // Store joints name // Sometimes the names might contain spaces. If that is the case, we need to continue // to read the name until we get to the closing " (quotation marks) if (tempJoint.name[tempJoint.name.size() - 1] != '"') { wchar_t checkChar; bool jointNameFound = false; while (!jointNameFound) { checkChar = fileIn.get(); if (checkChar == '"') jointNameFound = true; tempJoint.name += checkChar; } } fileIn >> tempJoint.parentID; // Store Parent joint's ID fileIn >> checkString; // Skip the "(" // Store position of this joint (swap y and z axis if model was made in RH Coord Sys) fileIn >> tempJoint.pos.x >> tempJoint.pos.z >> tempJoint.pos.y; fileIn >> checkString >> checkString; // Skip the ")" and "(" // Store orientation of this joint fileIn >> tempJoint.orientation.x >> tempJoint.orientation.z >> tempJoint.orientation.y; // Remove the quotation marks from joints name tempJoint.name.erase(0, 1); tempJoint.name.erase(tempJoint.name.size() - 1, 1); // 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); } std::getline(fileIn, checkString); // Skip rest of this line MD5Model.joints.push_back(tempJoint); // Store the joint into this models joint vector } fileIn >> checkString; // Skip the "}" } else if (checkString == L"mesh") { ModelSubset subset; int numVerts, numTris, numWeights; fileIn >> checkString; // Skip the "{" fileIn >> checkString; while (checkString != L"}") // Read until '}' { // In this lesson, for the sake of simplicity, we will assume a textures filename is givin here. // Usually though, the name of a material (stored in a material library. Think back to the lesson on // loading .obj files, where the material library was contained in the file .mtl) is givin. Let this // be an exercise to load the material from a material library such as obj's .mtl file, instead of // just the texture like we will do here. if (checkString == L"shader") // Load the texture or material { std::wstring fileNamePath; fileIn >> fileNamePath; // Get texture's filename // Take spaces into account if filename or material name has a space in it if (fileNamePath[fileNamePath.size() - 1] != '"') { wchar_t checkChar; bool fileNameFound = false; while (!fileNameFound) { checkChar = fileIn.get(); if (checkChar == '"') fileNameFound = true; fileNamePath += checkChar; } } // Remove the quotation marks from texture path fileNamePath.erase(0, 1); fileNamePath.erase(fileNamePath.size() - 1, 1); //check if this texture has already been loaded bool alreadyLoaded = false; for (int i = 0; i < texFileNameArray.size(); ++i) { if (fileNamePath == texFileNameArray[i]) { alreadyLoaded = true; subset.texArrayIndex = i; } } //if the texture is not already loaded, load it now if (!alreadyLoaded) { ID3D11ShaderResourceView* tempMeshSRV; if (SUCCEEDED(hr)) { texFileNameArray.push_back(fileNamePath.c_str()); subset.texArrayIndex = shaderResourceViewArray.size(); shaderResourceViewArray.push_back(tempMeshSRV); } } std::getline(fileIn, checkString); // Skip rest of this line } else if (checkString == L"numverts") { fileIn >> numVerts; // Store number of vertices std::getline(fileIn, checkString); // Skip rest of this line for (int i = 0; i < numVerts; i++) { Vertex tempVert; fileIn >> checkString // Skip "vert # (" >> checkString >> checkString; fileIn >> tempVert.texCoord.x // Store tex coords >> tempVert.texCoord.y; fileIn >> checkString; // Skip ")" fileIn >> tempVert.StartWeight; // Index of first weight this vert will be weighted to fileIn >> tempVert.WeightCount; // Number of weights for this vertex std::getline(fileIn, checkString); // Skip rest of this line subset.vertices.push_back(tempVert); // Push back this vertex into subsets vertex vector } } else if (checkString == L"numtris") { fileIn >> numTris; subset.numTriangles = numTris; std::getline(fileIn, checkString); // Skip rest of this line for (int i = 0; i < numTris; i++) // Loop through each triangle { DWORD tempIndex; fileIn >> checkString; // Skip "tri" fileIn >> checkString; // Skip tri counter for (int k = 0; k < 3; k++) // Store the 3 indices { fileIn >> tempIndex; subset.indices.push_back(tempIndex); } std::getline(fileIn, checkString); // Skip rest of this line } } else if (checkString == L"numweights") { fileIn >> numWeights; std::getline(fileIn, checkString); // Skip rest of this line for (int i = 0; i < numWeights; i++) { Weight tempWeight; fileIn >> checkString >> checkString; // Skip "weight #" fileIn >> tempWeight.jointID; // Store weight's joint ID fileIn >> tempWeight.bias; // Store weight's influence over a vertex fileIn >> checkString; // Skip "(" fileIn >> tempWeight.pos.x // Store weight's pos in joint's local space >> tempWeight.pos.z >> tempWeight.pos.y; std::getline(fileIn, checkString); // Skip rest of this line subset.weights.push_back(tempWeight); // Push back tempWeight into subsets Weight array } } else std::getline(fileIn, checkString); // Skip anything else fileIn >> checkString; // Skip "}" } //*** 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 = XMFLOAT3(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" XMVECTOR tempJointOrientation = XMVectorSet(tempJoint.orientation.x, tempJoint.orientation.y, tempJoint.orientation.z, tempJoint.orientation.w); XMVECTOR tempWeightPos = XMVectorSet(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 XMVECTOR tempJointOrientationConjugate = XMVectorSet(-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" XMFLOAT3 rotatedPoint; XMStoreFloat3(&rotatedPoint, XMQuaternionMultiply(XMQuaternionMultiply(tempJointOrientation, tempWeightPos), tempJointOrientationConjugate)); // 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 ***/// std::vector<XMFLOAT3> tempNormal; //normalized and unnormalized normals XMFLOAT3 unnormalized = XMFLOAT3(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 XMVECTOR edge1 = XMVectorSet(0.0f, 0.0f, 0.0f, 0.0f); XMVECTOR edge2 = XMVectorSet(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 = XMVectorSet(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 = XMVectorSet(vecX, vecY, vecZ, 0.0f); //Create our second edge //Cross multiply the two edge vectors to get the un-normalized face normal XMStoreFloat3(&unnormalized, XMVector3Cross(edge1, edge2)); tempNormal.push_back(unnormalized); } //Compute vertex normals (normal Averaging) XMVECTOR normalSum = XMVectorSet(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 = XMVectorGetX(normalSum) + tempNormal[j].x; tY = XMVectorGetY(normalSum) + tempNormal[j].y; tZ = XMVectorGetZ(normalSum) + tempNormal[j].z; normalSum = XMVectorSet(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 normalSum = XMVector3Normalize(normalSum); //Store the normal and tangent in our current vertex subset.vertices[i].normal.x = -XMVectorGetX(normalSum); subset.vertices[i].normal.y = -XMVectorGetY(normalSum); subset.vertices[i].normal.z = -XMVectorGetZ(normalSum); // Create the joint space normal for easy normal calculations in animation Vertex tempVert = subset.vertices[i]; // Get the current vertex subset.jointSpaceNormals.push_back(XMFLOAT3(0, 0, 0)); // Push back a blank normal XMVECTOR normal = XMVectorSet(0.0f, 0.0f, 0.0f, 0.0f); // Clear normal for (int k = 0; k < tempVert.WeightCount; k++) // Loop through each of the vertices weights { Joint tempJoint = MD5Model.joints[subset.weights[tempVert.StartWeight + k].jointID]; // Get the joints orientation XMVECTOR jointOrientation = XMVectorSet(tempJoint.orientation.x, tempJoint.orientation.y, tempJoint.orientation.z, tempJoint.orientation.w); // Calculate normal based off joints orientation (turn into joint space) normal = XMQuaternionMultiply(XMQuaternionMultiply(XMQuaternionInverse(jointOrientation), normalSum), jointOrientation); XMStoreFloat3(&subset.weights[tempVert.StartWeight + k].normal, XMVector3Normalize(normal)); // Store the normalized quaternion into our weights normal } //Clear normalSum, facesUsing for next vertex normalSum = XMVectorSet(0.0f, 0.0f, 0.0f, 0.0f); facesUsing = 0; } // Create index buffer D3D11_BUFFER_DESC indexBufferDesc; ZeroMemory(&indexBufferDesc, sizeof(indexBufferDesc)); indexBufferDesc.Usage = D3D11_USAGE_DEFAULT; indexBufferDesc.ByteWidth = sizeof(DWORD) * subset.numTriangles * 3; indexBufferDesc.BindFlags = D3D11_BIND_INDEX_BUFFER; indexBufferDesc.CPUAccessFlags = 0; indexBufferDesc.MiscFlags = 0; D3D11_SUBRESOURCE_DATA iinitData; iinitData.pSysMem = &subset.indices[0]; d3d11Device->CreateBuffer(&indexBufferDesc, &iinitData, &subset.indexBuff); //Create Vertex Buffer D3D11_BUFFER_DESC vertexBufferDesc; ZeroMemory(&vertexBufferDesc, sizeof(vertexBufferDesc)); vertexBufferDesc.Usage = D3D11_USAGE_DYNAMIC; // We will be updating this buffer, so we must set as dynamic vertexBufferDesc.ByteWidth = sizeof(Vertex) * subset.vertices.size(); vertexBufferDesc.BindFlags = D3D11_BIND_VERTEX_BUFFER; vertexBufferDesc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE; // Give CPU power to write to buffer vertexBufferDesc.MiscFlags = 0; D3D11_SUBRESOURCE_DATA vertexBufferData; ZeroMemory(&vertexBufferData, sizeof(vertexBufferData)); vertexBufferData.pSysMem = &subset.vertices[0]; hr = d3d11Device->CreateBuffer(&vertexBufferDesc, &vertexBufferData, &subset.vertBuff); // Push back the temp subset into the models subset vector MD5Model.subsets.push_back(subset); } } } else { SwapChain->SetFullscreenState(false, NULL); // Make sure we are out of fullscreen // create message std::wstring message = L"Could not open: "; message += filename; return false; } return true; } void Boxer::Update() { Scale = XMMatrixScaling(0.25f, 0.25f, 0.25f); Translation = XMMatrixTranslation(0.0f, 0.0f, 0.0f); boxerArena = Scale * Translation; } void Boxer::CalculateAABB(std::vector<XMFLOAT3> boundingBoxVerts, XMMATRIX & worldSpace, XMVECTOR & boundingBoxMin, XMVECTOR & boundingBoxMax) { XMFLOAT3 minVertex = XMFLOAT3(FLT_MAX, FLT_MAX, FLT_MAX); XMFLOAT3 maxVertex = XMFLOAT3(-FLT_MAX, -FLT_MAX, -FLT_MAX); //Loop through the 8 vertices describing the bounding box for (UINT i = 0; i < 8; i++) { //Transform the bounding boxes vertices to the objects world space XMVECTOR Vert = XMVectorSet(boundingBoxVerts[i].x, boundingBoxVerts[i].y, boundingBoxVerts[i].z, 0.0f); Vert = XMVector3TransformCoord(Vert, worldSpace); //Get the smallest vertex minVertex.x = min(minVertex.x, XMVectorGetX(Vert)); // Find smallest x value in model minVertex.y = min(minVertex.y, XMVectorGetY(Vert)); // Find smallest y value in model minVertex.z = min(minVertex.z, XMVectorGetZ(Vert)); // Find smallest z value in model //Get the largest vertex maxVertex.x = max(maxVertex.x, XMVectorGetX(Vert)); // Find largest x value in model maxVertex.y = max(maxVertex.y, XMVectorGetY(Vert)); // Find largest y value in model maxVertex.z = max(maxVertex.z, XMVectorGetZ(Vert)); // Find largest z value in model } //Store Bounding Box's min and max vertices boundingBoxMin = XMVectorSet(minVertex.x, minVertex.y, minVertex.z, 0.0f); boundingBoxMax = XMVectorSet(maxVertex.x, maxVertex.y, maxVertex.z, 0.0f); } bool Boxer::BoundingSphereCollision(float firstObjBoundingSphere, XMVECTOR firstObjCenterOffset, XMMATRIX & firstObjWorldSpace, float secondObjBoundingSphere, XMVECTOR secondObjCenterOffset, XMMATRIX & secondObjWorldSpace) { //Declare local variables XMVECTOR world_1 = XMVectorSet(0.0f, 0.0f, 0.0f, 0.0f); XMVECTOR world_2 = XMVectorSet(0.0f, 0.0f, 0.0f, 0.0f); float objectsDistance = 0.0f; //Transform the objects world space to objects REAL center in world space world_1 = XMVector3TransformCoord(firstObjCenterOffset, firstObjWorldSpace); world_2 = XMVector3TransformCoord(secondObjCenterOffset, secondObjWorldSpace); //Get the distance between the two objects objectsDistance = XMVectorGetX(XMVector3Length(world_1 - world_2)); //If the distance between the two objects is less than the sum of their bounding spheres... if (objectsDistance <= (firstObjBoundingSphere + secondObjBoundingSphere)) //Return true return true; //If the bounding spheres are not colliding, return false return false; } bool Boxer::BoundingBoxCollision(XMVECTOR & firstObjBoundingBoxMinVertex, XMVECTOR & firstObjBoundingBoxMaxVertex, XMMATRIX & firstObjWorldSpace, XMVECTOR & secondObjBoundingBoxMinVertex, XMVECTOR & secondObjBoundingBoxMaxVertex, XMMATRIX & secondObjWorldSpace) { //Is obj1's max X greater than obj2's min X? If not, obj1 is to the LEFT of obj2 if (XMVectorGetX(firstObjBoundingBoxMaxVertex) > XMVectorGetX(secondObjBoundingBoxMinVertex)) //Is obj1's min X less than obj2's max X? If not, obj1 is to the RIGHT of obj2 if (XMVectorGetX(firstObjBoundingBoxMinVertex) < XMVectorGetX(secondObjBoundingBoxMaxVertex)) //Is obj1's max Y greater than obj2's min Y? If not, obj1 is UNDER obj2 if (XMVectorGetY(firstObjBoundingBoxMaxVertex) > XMVectorGetY(secondObjBoundingBoxMinVertex)) //Is obj1's min Y less than obj2's max Y? If not, obj1 is ABOVE obj2 if (XMVectorGetY(firstObjBoundingBoxMinVertex) < XMVectorGetY(secondObjBoundingBoxMaxVertex)) //Is obj1's max Z greater than obj2's min Z? If not, obj1 is IN FRONT OF obj2 if (XMVectorGetZ(firstObjBoundingBoxMaxVertex) > XMVectorGetZ(secondObjBoundingBoxMinVertex)) //Is obj1's min Z less than obj2's max Z? If not, obj1 is BEHIND obj2 if (XMVectorGetZ(firstObjBoundingBoxMinVertex) < XMVectorGetZ(secondObjBoundingBoxMaxVertex)) //If we've made it this far, then the two bounding boxes are colliding return true; //If the two bounding boxes are not colliding, then return false return false; } void Boxer::Render() { //Clear our render target and depth/stencil view float bgColor[4] = { 0.1f, 0.1f, 0.1f, 1.0f }; d3d11DevCon->ClearRenderTargetView(renderTargetView, bgColor); d3d11DevCon->ClearDepthStencilView(depthStencilView, D3D11_CLEAR_DEPTH | D3D11_CLEAR_STENCIL, 1.0f, 0); constbuffPerFrame.light = light; d3d11DevCon->UpdateSubresource(cbPerFrameBuffer, 0, NULL, &constbuffPerFrame, 0, 0); d3d11DevCon->PSSetConstantBuffers(0, 1, &cbPerFrameBuffer); //Set our Render Target d3d11DevCon->OMSetRenderTargets(1, &renderTargetView, depthStencilView); //Set the default blend state (no blending) for opaque objects d3d11DevCon->OMSetBlendState(0, 0, 0xffffffff); //Set Vertex and Pixel Shaders d3d11DevCon->VSSetShader(VS, 0, 0); d3d11DevCon->PSSetShader(PS, 0, 0); ///***Draw MD5 Model***/// for (int i = 0; i < NewMD5Model.numSubsets; i++) { //Set the grounds index buffer d3d11DevCon->IASetIndexBuffer(NewMD5Model.subsets[i].indexBuff, DXGI_FORMAT_R32_UINT, 0); //Set the grounds vertex buffer d3d11DevCon->IASetVertexBuffers(0, 1, &NewMD5Model.subsets[i].vertBuff, stride, &offset); //Set the WVP matrix and send it to the constant buffer in effect file WVP = boxerArena * camView * camProjection; cbPerObj.WVP = XMMatrixTranspose(WVP); cbPerObj.World = XMMatrixTranspose(boxerArena); cbPerObj.hasTexture = true; // We'll assume all md5 subsets have textures cbPerObj.hasNormMap = false; // We'll also assume md5 models have no normal map (easy to change later though) d3d11DevCon->UpdateSubresource(cbPerObjectBuffer, 0, NULL, &cbPerObj, 0, 0); d3d11DevCon->VSSetConstantBuffers(0, 1, &cbPerObjectBuffer); d3d11DevCon->PSSetConstantBuffers(1, 1, &cbPerObjectBuffer); d3d11DevCon->PSSetShaderResources(0, 1, &meshSRV[NewMD5Model.subsets[i].texArrayIndex]); d3d11DevCon->PSSetSamplers(0, 1, &CubesTexSamplerState); d3d11DevCon->RSSetState(RSCullNone); d3d11DevCon->DrawIndexed(NewMD5Model.subsets[i].indices.size(), 0, 0); } } void Boxer::CleanUp() { for (int i = 0; i < NewMD5Model.numSubsets; i++) { NewMD5Model.subsets[i].indexBuff->Release(); NewMD5Model.subsets[i].vertBuff->Release(); } } I keep getting these errors: E0020 identifier "stride" is undefined E0020 identifier "offset" is undefined E0020 identifier "DefaultForward" is undefined
could you please add tabs in front of all your code lines? this is difficult to read. Also the errors are pretty specific. You have not defined "stride", "offset" and "DefaultForward" within the scope you are using them
on Oct 05 `17
iedoc
How do I do that?
on Oct 05 `17
dudedude1234
Sign in to comment
Check what a function need and what you define, there is a collision in variables. This is an example from one of the tutorials from this site: UINT stride = sizeof( Vertex ); UINT offset = 0; d3d11DevCon->IASetVertexBuffers( 0, 1, &squareVertBuffer, &stride, &offset ); note the stride is also a ref and both should be UINT ()
First of all, thanks for cleaning up your post, its a lot easier to read this way. The errors you are getting are really descriptive of what the problem is. Let's take the first error for example: E0020 identifier "stride" is undefined This is saying you are using a variable called ****stride**** without first defining it. You are using it on this line here: d3d11DevCon->IASetVertexBuffers(0, 1, &NewMD5Model.subsets[i].vertBuff, stride, &offset); Next, is an example of "defining" the variable stride: int stride = 10; // declare and define stride No where in your code are you defining or declaring the variable stride, from what i can see anyway. You are using it for ****IASetVertexBuffers****, where it is supposed to be describing the size in bytes of the vertex elements in your bound buffers. for example, say your buffer has only position, which might be a float[3]. each float is 4 bytes, so the stride is going to be 4 bytes * 3 floats, or 12 bytes. The other two errors are the same thing, you are using those variables without declaring or defining them. I'll leave it up to you to find in your code where you are using them, and then define them
I defined stride and offset on pch.h yet I got this error
E0167 argument of type "int" is incompatible with parameter of type "const UINT *"
on Oct 06 `17
dudedude1234