//! Loads the model from a file.[TODO] void SkinnedModel::Load(string filename) { ifstream fin(filename, ios::binary | ios::in); string ignore; int numMeshes; fin >> ignore >> numMeshes; for(int i = 0; i < numMeshes; i++) { SkinnedMesh* mesh = new SkinnedMesh(); mesh->Load(fin); AddMesh(mesh); } // The space after the last index. fin >> ignore; // Make sure to start loading animation data from the right place. // [NOTE] After some investigation it seems like it should be at the first '\f' character. char x = fin.peek(); while(x != '\f') { fin >> ignore; x = fin.peek(); } mAnimator = new SceneAnimator(); mAnimator->Load(fin); fin.close(); }
void Application::Render() { if (!m_deviceLost) { try { //Create Matrices D3DXMATRIX identity, view, proj, shadow; D3DXMatrixIdentity(&identity); D3DXMatrixLookAtLH(&view, &D3DXVECTOR3(cos(m_time) * m_radius, m_height, sin(m_time) * m_radius), &D3DXVECTOR3(0.0f, 1.0f, 0.0f), &D3DXVECTOR3(0.0f, 1.0f, 0.0f)); D3DXMatrixPerspectiveFovLH(&proj, D3DX_PI / 4.0f, (float)WINDOW_WIDTH / (float)WINDOW_HEIGHT, 1.0f, 1000.0f); D3DXPLANE ground(0.0f, 1.0f, 0.0f, 0.0f); D3DXVECTOR4 lightPos(-50.0f, 75.0f, -150.0f, 0.0f); // 点光源, 光照计算在 shader 中 D3DXMatrixShadow(&shadow, &lightPos, &ground); g_pDevice->SetTransform(D3DTS_WORLD, &identity); g_pDevice->SetTransform(D3DTS_VIEW, &view); g_pDevice->SetTransform(D3DTS_PROJECTION, &proj); // Clear the viewport g_pDevice->Clear(0, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, D3DCOLOR_ARGB(0xff, 0x40, 0x40, 0x40), 1.0f, 0); // Begin the scene if (SUCCEEDED(g_pDevice->BeginScene())) { //Render Drone { g_pEffect->SetMatrix("matW", &identity); g_pEffect->SetMatrix("matVP", &(view * proj)); g_pEffect->SetVector("lightPos", &lightPos); m_drone.Render(NULL); } if (KeyDown(VK_SPACE)) { g_pDevice->Clear(0, NULL, D3DCLEAR_ZBUFFER, D3DCOLOR_ARGB(0xff, 0x40, 0x40, 0x40), 1.0f, 0); m_drone.RenderSkeleton(NULL, NULL, identity); } RECT rc = {10, 10, 0, 0}; g_pFont->DrawText(NULL, "Press Space to Toggle Skeleton", -1, &rc, DT_LEFT | DT_TOP | DT_NOCLIP, D3DCOLOR_ARGB(0xff, 0, 0x80, 0)); // End the scene. g_pDevice->EndScene(); g_pDevice->Present(0, 0, 0, 0); } } catch(...) { g_debug << "Error in Application::Render() \n"; } } }
void Application::Render() { if (!m_deviceLost) { try { //Create Matrices D3DXMATRIX identity, world, view, proj; D3DXMatrixIdentity(&identity); D3DXMatrixLookAtLH(&view, &D3DXVECTOR3(0.0f, 1.5f, -3.0f), &D3DXVECTOR3(0.0f, 1.0f, 0.0f), &D3DXVECTOR3(0.0f, 1.0f, 0.0f)); D3DXMatrixPerspectiveFovLH(&proj, D3DX_PI / 4.0f, (float)WINDOW_WIDTH / (float)WINDOW_HEIGHT, 1.0f, 1000.0f); D3DXVECTOR4 lightPos(-50.0f, 75.0f, -150.0f, 0.0f); g_pDevice->SetTransform(D3DTS_WORLD, &identity); g_pDevice->SetTransform(D3DTS_VIEW, &view); g_pDevice->SetTransform(D3DTS_PROJECTION, &proj); // Clear the viewport g_pDevice->Clear(0L, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, 0xffffffff, 1.0f, 0L); // Begin the scene if (SUCCEEDED(g_pDevice->BeginScene())) { //Render Drone { g_pEffect->SetMatrix("matW", &identity); g_pEffect->SetMatrix("matVP", &(view * proj)); g_pEffect->SetVector("lightPos", &lightPos); //Update skeletal animation m_drone.SetPose(identity); //Update IK if (m_pIK) { m_pIK->UpdateHeadIK(); m_pIK->UpdateArmIK(); } m_drone.Render(NULL); } // End the scene. g_pDevice->EndScene(); g_pDevice->Present(0, 0, 0, 0); } } catch(...) { g_debug << "Error in Application::Render() \n"; } } }
void Destroy() { axis.Destroy(); cube.Destroy(); skinMesh.Destroy(); GraphicsDevice::ReleaseInstance(); }
void Render( unsigned int _dt ) { //DebugPrintf("Frame count: %d\n", FrameCount); HRESULT hr = S_OK; //清除视区 pGDevice->Clear(); //开始场景 pGDevice->BeginScene(); //Render skinmesh skinMesh.Render(pGDevice->m_pD3DDevice, identity, view, proj, eyePoint); //Render cube { pGDevice->SetViewport(pGDevice->mCubeViewport); cube.SetConstants(pGDevice->m_pD3DDevice, identity, fixedView, pGDevice->m_matCubeProj); cube.Draw(pGDevice->m_pD3DDevice); if (hovering || moving) { //将cube所在的viewport的位置(top-left)处的屏幕坐标变换到(0,0) D3DXVECTOR2 tmp(currentCursorPos); tmp.x -= pGDevice->mCubeViewport.X; tmp.y -= pGDevice->mCubeViewport.Y; cube.DrawRay(tmp, identity, fixedView, pGDevice->m_matCubeProj); } pGDevice->ResetViewport(); } //Render axis { pGDevice->SetViewport(pGDevice->mAxisViewport); axis.SetConstants(pGDevice->m_pD3DDevice, identity, fixedView, pGDevice->m_matAxisProj); axis.Draw(pGDevice->m_pD3DDevice); //axis.DrawXYZ(); pGDevice->ResetViewport(); } //结束场景 pGDevice->EndScene(); //显示场景 pGDevice->Present(); }
void Update( unsigned int _dt ) { //Update camera D3DXMatrixLookAtLH(&view, &eyePoint, &lookAt, &up); D3DXMatrixLookAtLH(&fixedView, &fixedEyePoint, &fixedLookAt, &fixedUp); cube.Update(currentCursorPos, identity, fixedView, pGDevice->m_matCubeProj); if (dragging) { //拖动时进行旋转 D3DXVECTOR2 mousePosDetla(currentCursorPos-lastCursorPos); RotateCameraHorizontally(D3DX_PI/50*mousePosDetla.x); RotateCameraVertically(D3DX_PI/50*mousePosDetla.y); } axis.Update(); //axis.UpdateXYZ(fixedEyePoint); skinMesh.Update(identity, _dt); }
BOOL InitInstance(HINSTANCE hInstance, int nCmdShow) { hInst = hInstance; // 将实例句柄存储在全局变量中 //创建并将主窗口句柄存储在全局变量中 hWnd = CreateWindow(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL, NULL, hInstance, NULL); if (!hWnd) { return FALSE; } ShowWindow(hWnd, nCmdShow); UpdateWindow(hWnd); /* timer */ //创建WaitableTimer HTimer = CreateWaitableTimer(NULL,FALSE,NULL); DebugAssert(NULL!=HTimer, "CreateWaitableTimer 失败: %d", GetLastError()); //初始化WaitableTimer LARGE_INTEGER liDueTime; liDueTime.QuadPart = -1i64; //1秒后开始计时 SetWaitableTimer(HTimer, &liDueTime, 100, NULL, NULL, 0); //周期200ms = 0.2s FrameCount = 0; /* GraphicsDevice */ pGDevice = GraphicsDevice::getInstance(hWnd); pGDevice->BuildViewports(); /* Camera */ InitCamera(); cube.SetVertexData(0); cube.Create(pGDevice->m_pD3DDevice); /* Axis */ axis.SetVertexData(0); //参数实际上不起作用 TODO: 改进设计 axis.Create(pGDevice->m_pD3DDevice); //axis.CreateXYZ(pGDevice->m_pD3DDevice); //axis.UpdateXYZ(fixedEyePoint); /* 读取fbx,加载Skinned mesh */ // 获取输出文件路径 测试用 char fileSrc[MAX_PATH]; GetTestFileName(fileSrc); skinMesh.Load(fileSrc, pGDevice->m_pD3DDevice); /* Matrix */ D3DXMatrixIdentity(&identity); D3DXMatrixPerspectiveFovLH(&proj, D3DX_PI / 4.0f, (float)pGDevice->mDefaultViewport.Width / (float)pGDevice->mDefaultViewport.Height, 1.0f, 1000.0f); return TRUE; }
HRESULT Application::Init(HINSTANCE hInstance, bool windowed) { g_debug << "Application Started \n"; //Create Window Class WNDCLASS wc; memset(&wc, 0, sizeof(WNDCLASS)); wc.style = CS_HREDRAW | CS_VREDRAW; wc.lpfnWndProc = (WNDPROC)WndProc; wc.hInstance = hInstance; wc.lpszClassName = "D3DWND"; RECT rc = {0, 0, WINDOW_WIDTH, WINDOW_HEIGHT}; AdjustWindowRect(&rc, WS_OVERLAPPEDWINDOW, false); //Register Class and Create new Window RegisterClass(&wc); m_mainWindow = ::CreateWindow("D3DWND", "Character Animation with Direct3D: Example 3.3", WS_OVERLAPPEDWINDOW, 0, 0, rc.right - rc.left, rc.bottom - rc.top, 0, 0, hInstance, 0); SetCursor(NULL); ::ShowWindow(m_mainWindow, SW_SHOW); ::UpdateWindow(m_mainWindow); //Create IDirect3D9 Interface IDirect3D9* d3d9 = Direct3DCreate9(D3D_SDK_VERSION); if (d3d9 == NULL) { g_debug << "Direct3DCreate9() - FAILED \n"; return E_FAIL; } //Check that the Device supports what we need from it D3DCAPS9 caps; d3d9->GetDeviceCaps(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, &caps); //Check vertex & pixelshader versions if (caps.VertexShaderVersion < D3DVS_VERSION(2, 0) || caps.PixelShaderVersion < D3DPS_VERSION(2, 0)) { g_debug << "Warning - Your graphic card does not support vertex and pixelshaders version 2.0 \n"; } //Set D3DPRESENT_PARAMETERS m_present.BackBufferWidth = WINDOW_WIDTH; m_present.BackBufferHeight = WINDOW_HEIGHT; m_present.BackBufferFormat = D3DFMT_A8R8G8B8; m_present.BackBufferCount = 2; m_present.MultiSampleType = D3DMULTISAMPLE_NONE; m_present.MultiSampleQuality = 0; m_present.SwapEffect = D3DSWAPEFFECT_DISCARD; m_present.hDeviceWindow = m_mainWindow; m_present.Windowed = windowed; m_present.EnableAutoDepthStencil = true; m_present.AutoDepthStencilFormat = D3DFMT_D24S8; m_present.Flags = 0; m_present.FullScreen_RefreshRateInHz = D3DPRESENT_RATE_DEFAULT; m_present.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE; //Hardware Vertex Processing int vp = 0; if (caps.DevCaps & D3DDEVCAPS_HWTRANSFORMANDLIGHT) vp = D3DCREATE_HARDWARE_VERTEXPROCESSING; else vp = D3DCREATE_SOFTWARE_VERTEXPROCESSING; //Create the IDirect3DDevice9 if (FAILED(d3d9->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, m_mainWindow, vp, &m_present, &g_pDevice))) { g_debug << "Failed to create IDirect3DDevice9 \n"; return E_FAIL; } //Release IDirect3D9 interface d3d9->Release(); //Load Application Specific resources here... D3DXCreateFont(g_pDevice, 20, 0, FW_BOLD, 1, false, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH | FF_DONTCARE, "Arial", &g_pFont); //Create Sprite D3DXCreateSprite(g_pDevice, &g_pSprite); //Load Effect ID3DXBuffer *pErrorMsgs = NULL; HRESULT hRes = D3DXCreateEffectFromFile(g_pDevice, "resources/fx/lighting.fx", NULL, NULL, D3DXSHADER_DEBUG, NULL, &g_pEffect, &pErrorMsgs); if (FAILED(hRes) && (pErrorMsgs != NULL)) { //Failed to create Effect g_debug << (char*)pErrorMsgs->GetBufferPointer() << "\n"; return E_FAIL; } m_deviceLost = false; m_drone.Load("resources/meshes/soldier.x"); return S_OK; }
//! Loads and returns a skinned model from a file. SkinnedModel* ModelImporter::LoadSkinnedModel(string filename) { // Is the model already loaded? if(mSkinnedModelMap.find(filename) != mSkinnedModelMap.end()) return mSkinnedModelMap[filename]; Assimp::Importer importer; mFilename = filename; SkinnedModel* model = NULL; // Important! Makes sure that if the angle between two face normals is > 80 they are not smoothed together. // Since the angle between a cubes face normals is 90 the lighting looks very bad if we don't specify this. importer.SetPropertyFloat(AI_CONFIG_PP_GSN_MAX_SMOOTHING_ANGLE, 80.0f); importer.SetPropertyInteger(AI_CONFIG_IMPORT_TER_MAKE_UVS, 1); importer.SetPropertyInteger(AI_CONFIG_PP_SBP_REMOVE, aiPrimitiveType_LINE); // Load scene from the file. const aiScene* scene = importer.ReadFile(filename, aiProcess_CalcTangentSpace | aiProcess_Triangulate | aiProcess_GenSmoothNormals | aiProcess_SplitLargeMeshes | aiProcess_ConvertToLeftHanded | aiProcess_SortByPType); if(scene) { // Create the model that is getting filled out. model = new SkinnedModel(); // Create the animator. SceneAnimator* animator = new SceneAnimator(); animator->Init(scene); model->SetAnimator(animator); // Loop through all meshes. for(int j = 0; j < scene->mNumMeshes; j++) { aiMesh* assimpMesh = scene->mMeshes[j]; // Calculate vertex weight and bone indices. vector<Weights> weights = CalculateWeights(assimpMesh, animator); vector<SkinnedVertex> vertices; vector<UINT> indices; // Add vertices to the vertex list. for(int i = 0; i < assimpMesh->mNumVertices; i++) { aiVector3D v = assimpMesh->mVertices[i]; aiVector3D n = assimpMesh->mNormals[i]; aiVector3D t = aiVector3D(0, 0, 0); if(assimpMesh->HasTextureCoords(0)) t = assimpMesh->mTextureCoords[0][i]; n = n.Normalize(); // Pos, normal and texture coordinates. SkinnedVertex vertex(v.x, v.y, v.z, n.x, n.y, n.z, 0, 0, 1, t.x, t.y); // Bone indices and weights. for(int k = 0; k < weights[i].boneIndices.size(); k++) vertex.BoneIndices[k] = weights[i].boneIndices[k]; vertex.Weights.x = weights[i].weights.size() >= 1 ? weights[i].weights[0] : 0; vertex.Weights.y = weights[i].weights.size() >= 2 ? weights[i].weights[1] : 0; vertex.Weights.z = weights[i].weights.size() >= 3 ? weights[i].weights[2] : 0; vertices.push_back(vertex); } // Add indices to the index list. for(int i = 0; i < assimpMesh->mNumFaces; i++) for(int k = 0; k < assimpMesh->mFaces[i].mNumIndices; k++) indices.push_back(assimpMesh->mFaces[i].mIndices[k]); // Get the path to the texture in the directory. aiString path; aiMaterial* material = scene->mMaterials[assimpMesh->mMaterialIndex]; material->Get(AI_MATKEY_TEXTURE_DIFFUSE(0), path); FindValidPath(&path); // Extract all the ambient, diffuse and specular colors. aiColor4D ambient, diffuse, specular; material->Get(AI_MATKEY_COLOR_AMBIENT, ambient); material->Get(AI_MATKEY_COLOR_DIFFUSE, diffuse); material->Get(AI_MATKEY_COLOR_SPECULAR, specular); // Create the mesh and its primitive. SkinnedMesh* mesh = new SkinnedMesh(); Primitive* primitive = new Primitive(GlobalApp::GetD3DDevice(), vertices, indices); mesh->SetPrimitive(primitive); mesh->SetVertices(vertices); mesh->SetIndices(indices); mPrimtiveFactory->AddPrimitive(path.C_Str(), primitive); // Replace .tga with .bmp [HACK]. string texturePath = path.C_Str(); int tgaPos = texturePath.find_first_of(".tga"); if(tgaPos != string::npos) { texturePath.replace(texturePath.size()-4, 4, ".bmp"); path = texturePath; } // Any texture? if(_stricmp(path.C_Str(), "") != 0) mesh->LoadTexture(path.C_Str()); // Any normal map? aiString nmap; material->Get(AI_MATKEY_TEXTURE_HEIGHT(0), nmap); FindValidPath(&nmap); if(_stricmp(nmap.C_Str(), "") != 0) mesh->SetNormalMap(GlobalApp::GetGraphics()->LoadTexture(nmap.C_Str())); // [NOTE] The material is set to white. mesh->SetMaterial(Material(Colors::White)); //mesh->SetMaterial(Material(diffuse, diffuse, diffuse)); model->SetFilename(filename); // Add the mesh to the model. model->AddMesh(mesh); } // Pre-calculate the bounding box. model->CalculateAABB(); // Add the newly created mesh to the map and return it. mSkinnedModelMap[filename] = model; return mSkinnedModelMap[filename]; } else { char buffer[246]; sprintf(buffer, "Error loading model: %s", filename.c_str()); MessageBox(0, buffer, "Error!", 0); mSkinnedModelMap[filename] = LoadSkinnedModel("models/box.obj"); return mSkinnedModelMap[filename]; } }
bool SkinnedModel::Init(std::string filename, VulkanInterface * vulkan, VulkanCommandBuffer * cmdBuffer) { VulkanDevice * vulkanDevice = vulkan->GetVulkanDevice(); // Uniform buffer init vertexUniformBuffer.worldMatrix = glm::mat4(1.0f); vertexUniformBuffer.MVP = glm::mat4(); for (unsigned int i = 0; i < MAX_BONES; i++) boneUniformBufferData.bones[i] = glm::mat4(); // Vertex shader - Uniform buffer skinnedVS_UBO = new VulkanBuffer(); if (!skinnedVS_UBO->Init(vulkanDevice, VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, &vertexUniformBuffer, sizeof(vertexUniformBuffer), false)) return false; // Vertex shader - Bone Uniform buffer skinnedVS_bone_UBO = new VulkanBuffer(); if (!skinnedVS_bone_UBO->Init(vulkanDevice, VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, &boneUniformBufferData, sizeof(boneUniformBufferData), false)) return false; // Open .rcs file FILE * file = fopen(filename.c_str(), "rb"); if (file == NULL) { gLogManager->AddMessage("ERROR: Model file not found! (" + filename + ")"); return false; } // Open .mat file size_t pos = filename.rfind('.'); filename.replace(pos, 4, ".mat"); std::ifstream matFile(filename.c_str()); if (!matFile.is_open()) { gLogManager->AddMessage("ERROR: Model .mat file not found! (" + filename + ")"); return false; } unsigned int meshCount; fread(&meshCount, sizeof(unsigned int), 1, file); for (unsigned int i = 0; i < meshCount; i++) { // Create and read mesh data char meshIdentifier[16]; sprintf(meshIdentifier, "_mesh%d", i); SkinnedMesh * mesh = new SkinnedMesh(); if (!mesh->Init(vulkan, file, filename + meshIdentifier)) { gLogManager->AddMessage("ERROR: Failed to init a mesh!"); return false; } meshes.push_back(mesh); std::string texturePath; char diffuseTextureName[64]; char normalTextureName[64]; // Init mesh material Material * material = new Material(); // Read diffuse texture fread(diffuseTextureName, sizeof(char), 64, file); if (strcmp(diffuseTextureName, "NONE") == 0) texturePath = "data/textures/default_diffuse.rct"; else texturePath = "data/textures/" + std::string(diffuseTextureName); Texture * diffuse = gTextureManager->RequestTexture(texturePath, vulkan->GetVulkanDevice(), cmdBuffer); if (diffuse == nullptr) return false; textures.push_back(diffuse); material->SetDiffuseTexture(diffuse); // Read normal texture if available fread(normalTextureName, sizeof(char), 64, file); if (strcmp(normalTextureName, "NONE") != 0) { texturePath = "data/textures/" + std::string(normalTextureName); Texture * normal = gTextureManager->RequestTexture(texturePath, vulkan->GetVulkanDevice(), cmdBuffer); if (normal == nullptr) return false; textures.push_back(normal); material->SetNormalTexture(normal); } std::string matName, matTextureName; float metallicOffset, roughnessOffset; matFile >> matName >> matTextureName >> metallicOffset >> roughnessOffset; // Read material texture if (matTextureName == "NONE") texturePath = "data/textures/default_material.rct"; else texturePath = "data/textures/" + matTextureName; Texture * matTexture = gTextureManager->RequestTexture(texturePath, vulkan->GetVulkanDevice(), cmdBuffer); if (matTexture == nullptr) return false; textures.push_back(matTexture); material->SetMaterialTexture(matTexture); material->SetMetallicOffset(metallicOffset); material->SetRoughnessOffset(roughnessOffset); materials.push_back(material); meshes[i]->SetMaterial(material); // Init draw command buffers for each meash VulkanCommandBuffer * drawCmdBuffer = new VulkanCommandBuffer(); if (!drawCmdBuffer->Init(vulkanDevice, vulkan->GetVulkanCommandPool(), false)) { gLogManager->AddMessage("ERROR: Failed to create a draw command buffer!"); return false; } drawCmdBuffers.push_back(drawCmdBuffer); } matFile.close(); // Read bone offsets fread(&numBones, sizeof(unsigned int), 1, file); boneOffsets.resize(numBones); fread(boneOffsets.data(), sizeof(aiMatrix4x4), numBones, file); // Read bone mappings for (unsigned int i = 0; i < numBones; i++) { unsigned int strSize; char * str; std::string boneName; uint32_t id; fread(&strSize, sizeof(unsigned int), 1, file); str = new char[strSize+1]; fread(str, sizeof(char), strSize, file); fread(&id, sizeof(uint32_t), 1, file); str[strSize] = 0; boneName = str; boneMapping[boneName] = id; } fclose(file); return true; }