├── SSDR.h ├── README.md ├── SSDR.cpp ├── stdafx.h ├── data └── url.txt ├── stdafx.cpp ├── targetver.h ├── .gitignore ├── util.h ├── main.cpp ├── QuadProg.h ├── ssdr.sln ├── LICENSE ├── ssdr.fx ├── ssdr.vcxproj.filters ├── QuadProg.cpp ├── HorseObject.h ├── Object.h ├── SampleApp.h ├── util.cpp ├── RigidTransform.h ├── ssdr.vcxproj ├── SampleApp.cpp └── HorseObject.cpp /SSDR.h: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TomohikoMukai/ssdr/HEAD/SSDR.h -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TomohikoMukai/ssdr/HEAD/README.md -------------------------------------------------------------------------------- /SSDR.cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TomohikoMukai/ssdr/HEAD/SSDR.cpp -------------------------------------------------------------------------------- /stdafx.h: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TomohikoMukai/ssdr/HEAD/stdafx.h -------------------------------------------------------------------------------- /data/url.txt: -------------------------------------------------------------------------------- 1 | http://people.csail.mit.edu/sumner/research/deftransfer/data.html -------------------------------------------------------------------------------- /stdafx.cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TomohikoMukai/ssdr/HEAD/stdafx.cpp -------------------------------------------------------------------------------- /targetver.h: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TomohikoMukai/ssdr/HEAD/targetver.h -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Compiled Object files 2 | *.slo 3 | *.lo 4 | *.o 5 | *.obj 6 | 7 | # Precompiled Headers 8 | *.gch 9 | *.pch 10 | 11 | # Compiled Dynamic libraries 12 | *.so 13 | *.dylib 14 | *.dll 15 | 16 | # Fortran module files 17 | *.mod 18 | 19 | # Compiled Static libraries 20 | *.lai 21 | *.la 22 | *.a 23 | *.lib 24 | 25 | # Executables 26 | *.exe 27 | *.out 28 | *.app 29 | -------------------------------------------------------------------------------- /util.h: -------------------------------------------------------------------------------- 1 | #ifndef UTIL_H 2 | #define UTIL_H 3 | #pragma once 4 | 5 | #include 6 | #include 7 | 8 | extern bool LoadObjFile(std::vector& position, std::vector& index, const std::wstring& filePath, float scale = 1.0f); 9 | extern bool ComputeNormal(std::vector& normal, const std::vector& position, const std::vector& index); 10 | 11 | #endif //UTIL_H 12 | -------------------------------------------------------------------------------- /main.cpp: -------------------------------------------------------------------------------- 1 | #include "SampleApp.h" 2 | #include 3 | #include "HorseObject.h" 4 | 5 | int _tmain(int argc, _TCHAR* argv[]) 6 | { 7 | #ifdef _DEBUG 8 | _CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF); 9 | #endif 10 | 11 | SampleApp::Config config; 12 | config.title = L"DemoSSDR"; 13 | 14 | SampleApp app(config); 15 | 16 | HorseObject::SharedPtr horse = HorseObject::CreateInstance(); 17 | app.AddObject(horse); 18 | 19 | return app.Run(); 20 | } 21 | 22 | -------------------------------------------------------------------------------- /QuadProg.h: -------------------------------------------------------------------------------- 1 | #ifndef QUADPROG_H 2 | #define QUADPROG_H 3 | #pragma once 4 | 5 | #include 6 | #include "QuadProg++.hh" 7 | 8 | // min (0.5 * xv^T * gm * xv + gv^T * x) 9 | // s.t. cem * xv + cev = 0 10 | // cim * xv + civ >= 0 11 | double SolveQP(const Eigen::MatrixXd& gm, const Eigen::VectorXd& gv, 12 | const Eigen::MatrixXd& cem, const Eigen::VectorXd& cev, 13 | const Eigen::MatrixXd& cim, const Eigen::VectorXd& civ, 14 | Eigen::VectorXd& xv); 15 | double TestSolveQP(); 16 | 17 | #endif //QUADPROG_H 18 | -------------------------------------------------------------------------------- /ssdr.sln: -------------------------------------------------------------------------------- 1 | 2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 2013 4 | VisualStudioVersion = 12.0.31101.0 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ssdr", "ssdr.vcxproj", "{4C49F59B-C04D-43A9-B5AD-C796FD3A81DD}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|x64 = Debug|x64 11 | Release|x64 = Release|x64 12 | EndGlobalSection 13 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 14 | {4C49F59B-C04D-43A9-B5AD-C796FD3A81DD}.Debug|x64.ActiveCfg = Debug|x64 15 | {4C49F59B-C04D-43A9-B5AD-C796FD3A81DD}.Debug|x64.Build.0 = Debug|x64 16 | {4C49F59B-C04D-43A9-B5AD-C796FD3A81DD}.Release|x64.ActiveCfg = Release|x64 17 | {4C49F59B-C04D-43A9-B5AD-C796FD3A81DD}.Release|x64.Build.0 = Release|x64 18 | EndGlobalSection 19 | GlobalSection(SolutionProperties) = preSolution 20 | HideSolutionNode = FALSE 21 | EndGlobalSection 22 | EndGlobal 23 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 Mukai Laboratory 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /ssdr.fx: -------------------------------------------------------------------------------- 1 | cbuffer CBPerFrame : register(b0) 2 | { 3 | matrix viewMatrix; 4 | matrix projectionMatrix; 5 | float4 lightColor; 6 | }; 7 | 8 | cbuffer CBPerObj : register(b1) 9 | { 10 | matrix worldMatrix; 11 | float3 localEyePos; 12 | float3 localLightPos; 13 | float4 ambientColor; 14 | float specExpon; 15 | }; 16 | 17 | cbuffer CBSkinningMatrix : register(b2) 18 | { 19 | matrix pallet[100]; 20 | } 21 | 22 | struct VertexData 23 | { 24 | float3 position : POSITION; 25 | float3 normal : NORMAL; 26 | float4 weight : BLENDWEIGHT; 27 | uint4 index : BLENDINDICES; 28 | float4 color : COLOR; 29 | }; 30 | 31 | struct LambertData 32 | { 33 | float4 position : SV_POSITION; 34 | float3 normal : NORMAL; 35 | float3 viewVec : TEXCOORD1; 36 | float3 lightVec : TEXCOORD2; 37 | float4 color : COLOR; 38 | }; 39 | 40 | float4 BlendPosition(float4 weight, uint4 index, float3 p) 41 | { 42 | float4 v = float4(p.xyz, 1.0f); 43 | float4 output = weight.x * mul(v, pallet[index.x]); 44 | output += weight.y * mul(v, pallet[index.y]); 45 | output += weight.z * mul(v, pallet[index.z]); 46 | output += weight.w * mul(v, pallet[index.w]); 47 | return float4(output.xyz, 1.0f); 48 | } 49 | 50 | float3 BlendNormal(float4 weight, uint4 index, float3 n) 51 | { 52 | float4 v = float4(n.xyz, 0); 53 | float4 output = weight.x * mul(v, pallet[index.x]); 54 | output += weight.y * mul(v, pallet[index.y]); 55 | output += weight.z * mul(v, pallet[index.z]); 56 | output += weight.w * mul(v, pallet[index.w]); 57 | return output.xyz; 58 | } 59 | 60 | LambertData LambertSkinVS(VertexData input) 61 | { 62 | LambertData output = (LambertData)0; 63 | output.position = BlendPosition(input.weight, input.index, input.position); 64 | output.position = mul(output.position, worldMatrix); 65 | output.position = mul(output.position, viewMatrix); 66 | output.position = mul(output.position, projectionMatrix); 67 | output.normal = BlendNormal(input.weight, input.index, input.normal.xyz); 68 | output.viewVec = normalize(localEyePos - input.position); 69 | output.lightVec = normalize(localLightPos - input.position); 70 | output.color = input.color; 71 | return output; 72 | } 73 | 74 | float4 LambertPS(LambertData input) : SV_TARGET0 75 | { 76 | float3 hn = normalize(input.viewVec + input.lightVec); 77 | float3 diffContrib = (lightColor.xyz * input.color.xyz) * max(dot(input.lightVec, input.normal), 0); 78 | return float4(ambientColor + diffContrib, input.color.w); 79 | } 80 | -------------------------------------------------------------------------------- /ssdr.vcxproj.filters: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 6 | cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx 7 | 8 | 9 | {93995380-89BD-4b04-88EB-625FBE52EBFB} 10 | h;hh;hpp;hxx;hm;inl;inc;xsd 11 | 12 | 13 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} 14 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms 15 | 16 | 17 | 18 | 19 | ヘッダー ファイル 20 | 21 | 22 | ヘッダー ファイル 23 | 24 | 25 | ヘッダー ファイル 26 | 27 | 28 | ヘッダー ファイル 29 | 30 | 31 | ヘッダー ファイル 32 | 33 | 34 | ヘッダー ファイル 35 | 36 | 37 | ヘッダー ファイル 38 | 39 | 40 | ヘッダー ファイル 41 | 42 | 43 | ヘッダー ファイル 44 | 45 | 46 | ヘッダー ファイル 47 | 48 | 49 | ヘッダー ファイル 50 | 51 | 52 | 53 | 54 | ソース ファイル 55 | 56 | 57 | ソース ファイル 58 | 59 | 60 | ソース ファイル 61 | 62 | 63 | ソース ファイル 64 | 65 | 66 | ソース ファイル 67 | 68 | 69 | ソース ファイル 70 | 71 | 72 | ソース ファイル 73 | 74 | 75 | ソース ファイル 76 | 77 | 78 | ソース ファイル 79 | 80 | 81 | 82 | 83 | 84 | -------------------------------------------------------------------------------- /QuadProg.cpp: -------------------------------------------------------------------------------- 1 | #include "QuadProg.h" 2 | 3 | using namespace Eigen; 4 | 5 | double SolveQP(const MatrixXd& gm, const VectorXd& gv, 6 | const MatrixXd& cem, const VectorXd& cev, 7 | const MatrixXd& cim, const VectorXd& civ, 8 | VectorXd& xv) 9 | { 10 | QuadProgPP::Matrix G(gm.rows(), gm.cols()); 11 | for (int i = 0; i < gm.rows(); ++i) 12 | { 13 | for (int j = 0; j < gm.cols(); ++j) 14 | { 15 | G[i][j] = gm(i, j); 16 | } 17 | } 18 | QuadProgPP::Vector g0(gv.size()); 19 | for (int i = 0; i < gv.size(); ++i) 20 | { 21 | g0[i] = gv[i]; 22 | } 23 | QuadProgPP::Matrix CE; 24 | if (cem.rows() > 0 && cem.cols() > 0) 25 | { 26 | CE.resize(cem.cols(), cem.rows()); 27 | for (int i = 0; i < cem.rows(); ++i) 28 | { 29 | for (int j = 0; j < cem.cols(); ++j) 30 | { 31 | CE[j][i] = cem(i, j); 32 | } 33 | } 34 | } 35 | QuadProgPP::Vector ce0; 36 | if (cev.size() > 0) 37 | { 38 | ce0.resize(cev.size()); 39 | for (int i = 0; i < cev.size(); ++i) 40 | { 41 | ce0[i] = cev[i]; 42 | } 43 | } 44 | QuadProgPP::Matrix CI; 45 | if (cim.rows() > 0 && cim.cols() > 0) 46 | { 47 | CI.resize(cim.cols(), cim.rows()); 48 | for (int i = 0; i < cim.rows(); ++i) 49 | { 50 | for (int j = 0; j < cim.cols(); ++j) 51 | { 52 | CI[j][i] = cim(i, j); 53 | } 54 | } 55 | } 56 | QuadProgPP::Vector ci0; 57 | if (civ.size() > 0) 58 | { 59 | ci0.resize(civ.size()); 60 | for (int i = 0; i < civ.size(); ++i) 61 | { 62 | ci0[i] = civ[i]; 63 | } 64 | } 65 | QuadProgPP::Vector x(0.0, xv.size()); 66 | double retval = QuadProgPP::solve_quadprog(G, g0, CE, ce0, CI, ci0, x); 67 | for (int i = 0; i < xv.size(); ++i) 68 | { 69 | xv[i] = x[i]; 70 | } 71 | return retval; 72 | } 73 | 74 | double TestSolveQP() 75 | { 76 | MatrixXd H(2, 2); 77 | H(0, 0) = 1.0; 78 | H(0, 1) = -1.0; 79 | H(1, 0) = -1.0; 80 | H(1, 1) = 2.0; 81 | 82 | VectorXd f(2); 83 | f(0) = -2.0; 84 | f(1) = -6.0; 85 | 86 | MatrixXd A(2, 5); 87 | A(0, 0) = -1.0; 88 | A(1, 0) = -1.0; 89 | A(0, 1) = 1.0; 90 | A(1, 1) = -2.0; 91 | A(0, 2) = -2.0; 92 | A(1, 2) = -1.0; 93 | A(0, 3) = 1.0; 94 | A(1, 3) = 0.0; 95 | A(0, 4) = 0.0; 96 | A(1, 4) = 1.0; 97 | 98 | VectorXd b(5); 99 | b(0) = 2.0; 100 | b(1) = 2.0; 101 | b(2) = 3.0; 102 | b(3) = 0; 103 | b(4) = 0; 104 | 105 | MatrixXd C; 106 | VectorXd d; 107 | 108 | VectorXd xv(2); 109 | SolveQP(H, f, C, d, A, b, xv); 110 | printf("%f - %f\n", xv[0], xv[1]); 111 | return (xv[0] - 2.0 / 3.0) * (xv[0] - 2.0 / 3.0) + (xv[1] - 4.0 / 3.0) * (xv[1] - 4.0 / 3.0); 112 | } 113 | -------------------------------------------------------------------------------- /HorseObject.h: -------------------------------------------------------------------------------- 1 | #ifndef HORSE_OBJECT_H 2 | #define HORSE_OBJECT_H 3 | #pragma once 4 | 5 | #include "Object.h" 6 | #include "RigidTransform.h" 7 | 8 | class HorseObject : public Object 9 | { 10 | public: 11 | using SharedPtr = std::shared_ptr; 12 | using UniquePtr = std::unique_ptr; 13 | 14 | protected: 15 | struct ConstantBufferPerFrame 16 | { 17 | DirectX::XMFLOAT4X4A view; 18 | DirectX::XMFLOAT4X4A proj; 19 | DirectX::XMFLOAT4A lightColor; 20 | }; 21 | static const int NumMaxSkinningMatrix = 100; 22 | struct ConstantBufferSkinningMatrix 23 | { 24 | DirectX::XMFLOAT4X4A pallet[NumMaxSkinningMatrix]; 25 | }; 26 | struct ConstantBufferPerObj 27 | { 28 | DirectX::XMFLOAT4X4A world; 29 | DirectX::XMFLOAT3A localEyePos; 30 | DirectX::XMFLOAT3A localLightPos; 31 | DirectX::XMFLOAT4A ambientColor; 32 | float specExpon; 33 | }; 34 | struct CustomVertex 35 | { 36 | static const int NumInfluences = 4; 37 | DirectX::XMFLOAT3A position; 38 | DirectX::XMFLOAT3A normal; 39 | float weight[NumInfluences]; 40 | unsigned int indices[NumInfluences]; 41 | DirectX::XMFLOAT4A color; 42 | }; 43 | static D3D11_INPUT_ELEMENT_DESC customVertexLayout[5]; 44 | 45 | 46 | public: 47 | static SharedPtr CreateInstance() 48 | { 49 | SharedPtr r(new HorseObject()); 50 | r->self = r; 51 | return r; 52 | } 53 | virtual ~HorseObject(); 54 | 55 | public: 56 | bool OnInit(ID3D11Device* device, ID3D11DeviceContext* deviceContext, const UINT width, const UINT height) override; 57 | void OnResize(ID3D11Device* device, ID3D11DeviceContext* deviceContext, const UINT width, const UINT height) override; 58 | void OnUpdate(ID3D11Device* device, ID3D11DeviceContext* deviceContext, float elapsed); 59 | void OnRender(ID3D11Device* device, ID3D11DeviceContext* deviceContext) override; 60 | void OnDestroy() override; 61 | 62 | protected: 63 | HRESULT InitShader(ID3D11Device* device); 64 | HRESULT LoadModel(ID3D11Device* device, const wchar_t* filePath, const DirectX::XMFLOAT4A& color); 65 | bool LoadAnim(const wchar_t* filePath); 66 | void ColorVerticesByError(int frame, float upperBound); 67 | 68 | private: 69 | ID3D11Buffer* constantBufferPerFrame; 70 | ID3D11Buffer* constantBufferPerObj; 71 | ID3D11Buffer* constantBufferSkinningBone; 72 | ConstantBufferPerFrame perFrameData; 73 | DirectX::XMFLOAT3A lightPosition; 74 | ID3D11InputLayout* inputLayout; 75 | ID3D11VertexShader* vertexShader; 76 | ID3D11PixelShader* pixelShader; 77 | ID3D11BlendState* alphaBlendState; 78 | 79 | ID3D11Buffer* vertexBuffer; 80 | ID3D11Buffer* indexBuffer; 81 | unsigned long numVertices; 82 | unsigned long numFaces; 83 | 84 | CustomVertex* vertexBufferCPU; 85 | CustomVertex* srcVertexBufferCPU; 86 | std::vector vertexAnim; 87 | std::vector boneAnim; 88 | unsigned long numFrames; 89 | unsigned long frame; 90 | int numBones; 91 | 92 | protected: 93 | HorseObject(); 94 | }; 95 | 96 | #endif //HORSE_OBJECT_H 97 | -------------------------------------------------------------------------------- /Object.h: -------------------------------------------------------------------------------- 1 | #ifndef OBJECT_H 2 | #define OBJECT_H 3 | #pragma once 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | struct Object 11 | { 12 | public: 13 | using SharedPtr = std::shared_ptr; 14 | using WeakPtr = std::weak_ptr; 15 | using UniquePtr = std::unique_ptr; 16 | 17 | protected: 18 | WeakPtr self; 19 | WeakPtr parent; 20 | WeakPtr root; 21 | std::vector children; 22 | bool isVisible; 23 | 24 | public: 25 | static SharedPtr CreateInstance() 26 | { 27 | SharedPtr s(new Object); 28 | s->self = s; 29 | return s; 30 | } 31 | virtual ~Object() 32 | { 33 | } 34 | 35 | public: 36 | bool IsVisible() const 37 | { 38 | return isVisible; 39 | } 40 | virtual void Show() 41 | { 42 | isVisible = true; 43 | } 44 | virtual void Hide() 45 | { 46 | isVisible = false; 47 | } 48 | 49 | public: 50 | int NumChildren() const 51 | { 52 | return static_cast(children.size()); 53 | } 54 | SharedPtr Child(int id) 55 | { 56 | return children[id]; 57 | } 58 | 59 | public: 60 | void AddChild(SharedPtr child) 61 | { 62 | children.push_back(child); 63 | child->parent = self; 64 | child->SetRoot(parent.lock() == nullptr ? self.lock() : root.lock()); 65 | } 66 | void SetRoot(SharedPtr r) 67 | { 68 | if (root.lock() == r) 69 | { 70 | return; 71 | } 72 | root = r; 73 | for (auto it = children.begin(); it != children.end(); ++it) 74 | { 75 | (*it)->SetRoot(r); 76 | } 77 | } 78 | 79 | public: 80 | virtual bool OnInit(ID3D11Device* device, ID3D11DeviceContext* deviceContext, const UINT width, const UINT height) 81 | { 82 | for (auto it = children.begin(); it != children.end(); ++it) 83 | { 84 | (*it)->OnInit(device, deviceContext, width, height); 85 | } 86 | return true; 87 | } 88 | virtual void OnDestroy() 89 | { 90 | for (auto it = children.begin(); it != children.end(); ++it) 91 | { 92 | (*it)->OnDestroy(); 93 | } 94 | children.clear(); 95 | parent.reset(); 96 | root.reset(); 97 | self.reset(); 98 | } 99 | virtual void OnRender(ID3D11Device* device, ID3D11DeviceContext* deviceContext) 100 | { 101 | for (auto it = children.begin(); it != children.end(); ++it) 102 | { 103 | (*it)->OnRender(device, deviceContext); 104 | } 105 | } 106 | virtual void OnResize(ID3D11Device* device, ID3D11DeviceContext* deviceContext, const UINT width, const UINT height) 107 | { 108 | for (auto it = children.begin(); it != children.end(); ++it) 109 | { 110 | (*it)->OnResize(device, deviceContext, width, height); 111 | } 112 | } 113 | virtual void OnUpdate(ID3D11Device* device, ID3D11DeviceContext* deviceContext, float elapsed) 114 | { 115 | for (auto it = children.begin(); it != children.end(); ++it) 116 | { 117 | (*it)->OnUpdate(device, deviceContext, elapsed); 118 | } 119 | } 120 | 121 | protected: 122 | Object() 123 | : isVisible(true) 124 | { 125 | } 126 | private: 127 | Object(const Object& src); 128 | void operator =(const Object& src); 129 | }; 130 | 131 | #endif //OBJECT_H 132 | -------------------------------------------------------------------------------- /SampleApp.h: -------------------------------------------------------------------------------- 1 | #ifndef SAMPLE_APP_H 2 | #define SAMPLE_APP_H 3 | #pragma once 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include "Object.h" 12 | 13 | class SampleApp 14 | { 15 | public: 16 | struct Config 17 | { 18 | UINT swapChainCount; 19 | DXGI_FORMAT swapChainFormat; 20 | DXGI_FORMAT depthStencilFormat; 21 | UINT multiSampleCount; 22 | UINT multiSampleQuality; 23 | UINT width; 24 | UINT height; 25 | wchar_t* title; 26 | FLOAT clearColorR; 27 | FLOAT clearColorG; 28 | FLOAT clearColorB; 29 | FLOAT clearColorA; 30 | 31 | Config() 32 | : swapChainCount(2), 33 | swapChainFormat(DXGI_FORMAT_R8G8B8A8_UNORM), 34 | depthStencilFormat(DXGI_FORMAT_D24_UNORM_S8_UINT), 35 | multiSampleCount(1), 36 | multiSampleQuality(0), 37 | width(1280), 38 | height(720), 39 | title(L"BasicApp"), 40 | clearColorR(0.392f), 41 | clearColorG(0.584f), 42 | clearColorB(0.929f), 43 | clearColorA(1.0f) 44 | { 45 | } 46 | }; 47 | 48 | // 49 | // field 50 | protected: 51 | static const UINT SWAPCHAIN_BUFFER_COUNT = 2; 52 | static const DXGI_FORMAT SWAPCHAIN_BUFFER_FORMAT = DXGI_FORMAT_R8G8B8A8_UNORM; 53 | static const DXGI_FORMAT DEPTHSTENCIL_TEXTURE_FORMAT = DXGI_FORMAT_R24G8_TYPELESS; 54 | static const DXGI_FORMAT DEPTHSTENCIL_VIEW_FORMAT = DXGI_FORMAT_D24_UNORM_S8_UINT; 55 | static const DXGI_FORMAT DEPTHSTENCIL_RESOURCE_FORMAT = DXGI_FORMAT_R24_UNORM_X8_TYPELESS; 56 | 57 | static SampleApp* s_pThis; 58 | HINSTANCE hInstance; 59 | HWND hMainWnd; 60 | D3D_DRIVER_TYPE driverType; 61 | D3D_FEATURE_LEVEL featureLevel; 62 | UINT multiSampleCount; 63 | UINT multiSampleQuality; 64 | UINT multiSampleMaxQuality; 65 | UINT swapChainCount; 66 | DXGI_FORMAT swapChainFormat; 67 | DXGI_FORMAT depthStencilFormat; 68 | ID3D11Device* d3dDevice; 69 | ID3D11DeviceContext* d3dDeviceContext; 70 | IDXGISwapChain* swapChain; 71 | ID3D11RenderTargetView* renderTargetView; 72 | ID3D11DepthStencilView* depthStencilView; 73 | ID3D11Texture2D* renderTargetTexture; 74 | ID3D11Texture2D* depthStencilTexture; 75 | ID3D11ShaderResourceView* renderTargetShaderResourceView; 76 | ID3D11ShaderResourceView* depthStencilShaderResourceView; 77 | FLOAT clearColor[4]; 78 | UINT wndWidth; 79 | UINT wndHeight; 80 | FLOAT aspectRatio; 81 | std::wstring wndTitle; 82 | LARGE_INTEGER prevCounter; 83 | LONGLONG counterPerFrame; 84 | std::vector object; 85 | 86 | public: 87 | bool InitializeApp(); 88 | void TerminateApp(); 89 | bool OpenWindow(); 90 | void CloseWindow(); 91 | bool InitializeD3D11(); 92 | void TerminateD3D11(); 93 | void OnTerminate(); 94 | int MainLoop(); 95 | bool OnInit(); 96 | void OnRender(); 97 | void OnResize(const UINT w, const UINT h); 98 | void OnUpdate(LONGLONG elapsed); 99 | void AddObject(Object::SharedPtr obj); 100 | 101 | public: 102 | bool CreateDefaultRenderTarget(); 103 | bool CreateDefaultDepthStencil(); 104 | void ReleaseDefaultRenderTarget(); 105 | void ReleaseDefaultDepthStencil(); 106 | 107 | static LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wp, LPARAM lp); 108 | 109 | public: 110 | SampleApp(const Config& config); 111 | virtual ~SampleApp(); 112 | 113 | int Run(); 114 | }; 115 | 116 | #endif //SAMPLE_APP_H 117 | -------------------------------------------------------------------------------- /util.cpp: -------------------------------------------------------------------------------- 1 | #include "util.h" 2 | #include 3 | 4 | static const char* delim = " /\t\n"; 5 | static char* context = nullptr; 6 | 7 | using namespace DirectX; 8 | 9 | bool ReadVector3(XMFLOAT3& v, char* buf) 10 | { 11 | // local definition 12 | // 13 | #define READ_VECTOR3_TOKEN(ELEMENT) tok = strtok_s(buf, delim, &context); \ 14 | if (tok == nullptr) { return false; } \ 15 | v.ELEMENT = static_cast(std::atof(tok)); 16 | // 17 | char* tok = nullptr; 18 | READ_VECTOR3_TOKEN(x); 19 | READ_VECTOR3_TOKEN(y); 20 | READ_VECTOR3_TOKEN(z); 21 | return true; 22 | } 23 | 24 | bool LoadObjFile(std::vector& position, std::vector& index, const std::wstring& filePath, float scale) 25 | { 26 | char buf[1024]; 27 | char* tok = nullptr; 28 | 29 | FILE* fin = nullptr; 30 | _wfopen_s(&fin, filePath.data(), L"r"); 31 | if (fin == nullptr) 32 | { 33 | return false; 34 | } 35 | 36 | position.clear(); 37 | index.clear(); 38 | 39 | while (std::fgets(buf, 1024, fin) != nullptr) 40 | { 41 | tok = strtok_s(buf, delim, &context); 42 | if (tok == nullptr) 43 | { 44 | } 45 | else if (tok[0] == '#') 46 | { 47 | continue; 48 | } 49 | else if (strcmp(tok, "v") == 0) 50 | { 51 | XMFLOAT3 p; 52 | if (!ReadVector3(p, NULL)) 53 | { 54 | break; 55 | } 56 | position.push_back(XMFLOAT3A(p.x * scale, p.y * scale, p.z * scale)); 57 | } 58 | else if (strcmp(tok, "vt") == 0) 59 | { 60 | continue; 61 | } 62 | else if (strcmp(tok, "f") == 0) 63 | { 64 | std::vector tmp; 65 | while (tok = strtok_s(NULL, delim, &context), tok != nullptr) 66 | { 67 | tmp.push_back(static_cast(atol(tok) - 1)); 68 | } 69 | switch (tmp.size()) 70 | { 71 | case 6: 72 | index.push_back(tmp[0]); 73 | index.push_back(tmp[2]); 74 | index.push_back(tmp[4]); 75 | break; 76 | default: 77 | fclose(fin); 78 | position.clear(); 79 | index.clear(); 80 | return false; 81 | break; 82 | } 83 | } 84 | else if (strcmp(tok, "g") == 0) 85 | { 86 | continue; 87 | } 88 | else 89 | { 90 | continue; 91 | } 92 | } 93 | fclose(fin); 94 | return true; 95 | } 96 | 97 | bool ComputeNormal(std::vector& normal, const std::vector& position, const std::vector& index) 98 | { 99 | if (position.empty() || index.empty()) 100 | { 101 | return false; 102 | } 103 | std::vector nv(position.size(), XMFLOAT3A(0, 0, 0)); 104 | for (auto it = index.begin(); it != index.end(); it += 3) 105 | { 106 | const XMVECTOR v0 = XMLoadFloat3A(&position[*it]); 107 | const XMVECTOR v1 = XMLoadFloat3A(&position[*(it + 1)]); 108 | const XMVECTOR v2 = XMLoadFloat3A(&position[*(it + 2)]); 109 | 110 | XMVECTOR n = XMVector3Cross(XMVectorSubtract(v1, v0), XMVectorSubtract(v2, v0)); 111 | n = XMVector3Normalize(n); 112 | 113 | XMStoreFloat3A(&nv[*it], XMVectorAdd(XMLoadFloat3A(&nv[*it]), n)); 114 | XMStoreFloat3A(&nv[*(it + 1)], XMVectorAdd(XMLoadFloat3A(&nv[*(it + 1)]), n)); 115 | XMStoreFloat3A(&nv[*(it + 2)], XMVectorAdd(XMLoadFloat3A(&nv[*(it + 2)]), n)); 116 | } 117 | normal.resize(position.size()); 118 | for (size_t v = 0; v < position.size(); ++v) 119 | { 120 | XMVECTOR n = XMLoadFloat3A(&nv[v]); 121 | n = XMVector3Normalize(n); 122 | XMFLOAT3A na; 123 | XMStoreFloat3A(&na, n); 124 | normal[v] = na; 125 | } 126 | return true; 127 | } 128 | -------------------------------------------------------------------------------- /RigidTransform.h: -------------------------------------------------------------------------------- 1 | #ifndef RIGID_TRANSFORM_H 2 | #define RIGID_TRANSFORM_H 3 | #pragma once 4 | 5 | #include 6 | 7 | class RigidTransform 8 | { 9 | public: 10 | DirectX::XMFLOAT4A& Rotation() 11 | { 12 | return rotation; 13 | } 14 | const DirectX::XMFLOAT4A& Rotation() const 15 | { 16 | return rotation; 17 | } 18 | DirectX::XMFLOAT3A& Translation() 19 | { 20 | return translation; 21 | } 22 | const DirectX::XMFLOAT3A& Translation() const 23 | { 24 | return translation; 25 | } 26 | 27 | public: 28 | RigidTransform() 29 | : rotation(0, 0, 0, 1.0f), 30 | translation(0, 0, 0) 31 | { 32 | } 33 | RigidTransform(const RigidTransform& src) 34 | { 35 | rotation = src.rotation; 36 | translation = src.translation; 37 | } 38 | RigidTransform(const DirectX::XMFLOAT4A& r, const DirectX::XMFLOAT3A& t) 39 | { 40 | rotation = r; 41 | translation = t; 42 | } 43 | explicit RigidTransform(const DirectX::XMFLOAT4X4A& m) 44 | { 45 | translation = DirectX::XMFLOAT3A(m._41, m._42, m._43); 46 | DirectX::XMMATRIX xm = DirectX::XMLoadFloat4x4A(&m); 47 | DirectX::XMVECTOR rv = DirectX::XMQuaternionRotationMatrix(xm); 48 | if (DirectX::XMVectorGetW(rv) < 0) 49 | { 50 | rv = DirectX::XMVectorNegate(rv); 51 | } 52 | DirectX::XMStoreFloat4A(&rotation, rv); 53 | } 54 | ~RigidTransform() 55 | { 56 | } 57 | 58 | public: 59 | RigidTransform& operator =(const RigidTransform& src) 60 | { 61 | rotation = src.rotation; 62 | translation = src.translation; 63 | return *this; 64 | } 65 | RigidTransform& operator =(const DirectX::XMFLOAT4X4A& m) 66 | { 67 | translation = DirectX::XMFLOAT3A(m._41, m._42, m._43); 68 | DirectX::XMMATRIX xm = DirectX::XMLoadFloat4x4A(&m); 69 | DirectX::XMVECTOR rv = DirectX::XMQuaternionRotationMatrix(xm); 70 | if (DirectX::XMVectorGetW(rv) < 0) 71 | { 72 | rv = DirectX::XMVectorNegate(rv); 73 | } 74 | DirectX::XMStoreFloat4A(&rotation, rv); 75 | return *this; 76 | } 77 | void Set(const DirectX::XMFLOAT4A& r, const DirectX::XMFLOAT3A& t) 78 | { 79 | rotation = r; 80 | translation = t; 81 | } 82 | DirectX::XMVECTOR TransformCoord(DirectX::CXMVECTOR v) const 83 | { 84 | DirectX::XMVECTOR u = DirectX::XMVector3Rotate(v, DirectX::XMLoadFloat4A(&rotation)); 85 | return DirectX::XMVectorAdd(DirectX::XMLoadFloat3A(&translation), u); 86 | } 87 | 88 | public: 89 | static RigidTransform Identity() 90 | { 91 | return RigidTransform(); 92 | } 93 | static RigidTransform Inverse(const RigidTransform& src) 94 | { 95 | RigidTransform is; 96 | DirectX::XMVECTOR xv = DirectX::XMLoadFloat4A(&src.rotation); 97 | DirectX::XMStoreFloat4A(&is.rotation, DirectX::XMQuaternionConjugate(xv)); 98 | xv = DirectX::XMLoadFloat3A(&src.translation); 99 | DirectX::XMStoreFloat3A(&is.translation, DirectX::XMVectorNegate(xv)); 100 | return is; 101 | } 102 | 103 | public: 104 | DirectX::XMFLOAT4X4A ToMatrix4x4() const 105 | { 106 | DirectX::XMMATRIX m = DirectX::XMMatrixAffineTransformation(DirectX::XMVectorSet(1.0f, 1.0f, 1.0f, 1.0f), 107 | DirectX::XMVectorZero(), 108 | XMLoadFloat4A(&rotation), 109 | XMLoadFloat3A(&translation)); 110 | DirectX::XMFLOAT4X4A r; 111 | DirectX::XMStoreFloat4x4A(&r, m); 112 | return r; 113 | } 114 | static RigidTransform FromMatrix4x4(const DirectX::XMFLOAT4X4A& m) 115 | { 116 | RigidTransform at; 117 | at.translation = DirectX::XMFLOAT3A(m._41, m._42, m._43); 118 | DirectX::XMMATRIX xm = DirectX::XMLoadFloat4x4A(&m); 119 | DirectX::XMVECTOR rv = DirectX::XMQuaternionRotationMatrix(xm); 120 | if (DirectX::XMVectorGetW(rv) < 0) 121 | { 122 | rv = DirectX::XMVectorNegate(rv); 123 | } 124 | DirectX::XMStoreFloat4A(&at.rotation, rv); 125 | return at; 126 | } 127 | 128 | private: 129 | DirectX::XMFLOAT4A rotation; 130 | DirectX::XMFLOAT3A translation; 131 | }; 132 | 133 | #endif //RIGID_TRANSFORM_H 134 | -------------------------------------------------------------------------------- /ssdr.vcxproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | x64 7 | 8 | 9 | Release 10 | x64 11 | 12 | 13 | 14 | {4C49F59B-C04D-43A9-B5AD-C796FD3A81DD} 15 | Win32Proj 16 | ssdr 17 | 18 | 19 | 20 | Application 21 | true 22 | v120 23 | Unicode 24 | 25 | 26 | Application 27 | false 28 | v120 29 | true 30 | Unicode 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | true 44 | 45 | 46 | false 47 | 48 | 49 | 50 | Use 51 | Level3 52 | Disabled 53 | WIN32;_DEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions) 54 | true 55 | stdafx.h 56 | 57 | 58 | Console 59 | true 60 | %(AdditionalDependencies) 61 | 62 | 63 | 64 | 65 | 66 | 67 | Level3 68 | Use 69 | MaxSpeed 70 | true 71 | true 72 | WIN32;NDEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions) 73 | true 74 | stdafx.h 75 | 76 | 77 | 78 | 79 | Console 80 | true 81 | true 82 | true 83 | %(AdditionalDependencies) 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | Create 112 | Create 113 | 114 | 115 | 116 | 117 | true 118 | true 119 | 120 | 121 | 122 | 123 | 124 | -------------------------------------------------------------------------------- /SampleApp.cpp: -------------------------------------------------------------------------------- 1 | #include "SampleApp.h" 2 | #include 3 | 4 | #ifndef ELOG 5 | #define ELOG( x, ... ); \ 6 | fprintf( stderr, "[File:%s, Line:%d] "x"\n", __FILE__, __LINE__, ##__VA_ARGS__ ); \ 7 | assert( false ); 8 | #endif 9 | 10 | #define SAFE_RELEASE(p) if (p != nullptr) { p->Release(); p = nullptr; } 11 | 12 | SampleApp* SampleApp::s_pThis = nullptr; 13 | 14 | SampleApp::SampleApp(const Config& config) 15 | : hInstance(nullptr), 16 | hMainWnd(nullptr), 17 | driverType(D3D_DRIVER_TYPE_NULL), 18 | featureLevel(D3D_FEATURE_LEVEL_11_0), 19 | multiSampleCount(config.multiSampleCount), 20 | multiSampleQuality(config.multiSampleQuality), 21 | swapChainCount(config.swapChainCount), 22 | swapChainFormat(config.swapChainFormat), 23 | depthStencilFormat(config.depthStencilFormat), 24 | d3dDevice(nullptr), 25 | d3dDeviceContext(nullptr), 26 | swapChain(nullptr), 27 | renderTargetView(nullptr), 28 | depthStencilView(nullptr), 29 | renderTargetTexture(nullptr), 30 | depthStencilTexture(nullptr), 31 | renderTargetShaderResourceView(nullptr), 32 | depthStencilShaderResourceView(nullptr), 33 | wndWidth(config.width), 34 | wndHeight(config.height), 35 | wndTitle(config.title) 36 | { 37 | clearColor[0] = config.clearColorR; 38 | clearColor[1] = config.clearColorG; 39 | clearColor[2] = config.clearColorB; 40 | clearColor[3] = config.clearColorA; 41 | 42 | aspectRatio = static_cast(wndWidth) / static_cast(wndHeight); 43 | } 44 | 45 | 46 | SampleApp::~SampleApp() 47 | { 48 | TerminateApp(); 49 | } 50 | 51 | bool SampleApp::OpenWindow() 52 | { 53 | HINSTANCE hInst = GetModuleHandle(nullptr); 54 | s_pThis = this; 55 | 56 | WNDCLASSEX wc; 57 | wc.cbSize = sizeof(WNDCLASSEX); 58 | wc.style = CS_HREDRAW | CS_VREDRAW; 59 | wc.lpfnWndProc = WndProc; 60 | wc.cbClsExtra = 0; 61 | wc.cbWndExtra = 0; 62 | wc.hInstance = hInst; 63 | wc.hIcon = LoadIcon(hInst, IDI_APPLICATION); 64 | wc.hCursor = LoadCursor(NULL, IDC_ARROW); 65 | wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1); 66 | wc.lpszMenuName = nullptr; 67 | wc.lpszClassName = wndTitle.c_str(); 68 | wc.hIconSm = LoadIcon(hInst, IDI_APPLICATION); 69 | 70 | if (!RegisterClassEx(&wc)) 71 | { 72 | ELOG("Error : RegisterClassEx() Failed.\n"); 73 | return false; 74 | } 75 | hInstance = hInst; 76 | RECT rc = { 0, 0, wndWidth, wndHeight }; 77 | AdjustWindowRect(&rc, WS_OVERLAPPEDWINDOW, FALSE); 78 | 79 | hMainWnd = CreateWindow( 80 | wndTitle.c_str(), 81 | wndTitle.c_str(), 82 | WS_OVERLAPPEDWINDOW, 83 | CW_USEDEFAULT, 84 | CW_USEDEFAULT, 85 | rc.right - rc.left, 86 | rc.bottom - rc.top, 87 | nullptr, 88 | nullptr, 89 | hInst, 90 | nullptr 91 | ); 92 | if (hMainWnd == NULL) 93 | { 94 | ELOG("Error : CreateWindow() Failed."); 95 | return false; 96 | } 97 | ShowWindow(hMainWnd, SW_SHOWNORMAL); 98 | return true; 99 | } 100 | 101 | void SampleApp::CloseWindow() 102 | { 103 | if (hInstance != NULL) 104 | { 105 | UnregisterClass(wndTitle.c_str(), hInstance); 106 | } 107 | wndTitle.clear(); 108 | s_pThis = nullptr; 109 | } 110 | 111 | bool SampleApp::InitializeD3D11() 112 | { 113 | HRESULT hr = S_OK; 114 | 115 | RECT rc; 116 | GetClientRect(hMainWnd, &rc); 117 | UINT w = rc.right - rc.left; 118 | UINT h = rc.bottom - rc.top; 119 | wndWidth = w; 120 | wndHeight = h; 121 | 122 | aspectRatio = static_cast(w) / static_cast(h); 123 | 124 | UINT createDeviceFlags = 0; 125 | #if defined(DEBUG) || defined(_DEBUG) 126 | createDeviceFlags |= D3D11_CREATE_DEVICE_DEBUG; 127 | #endif 128 | 129 | D3D_DRIVER_TYPE driverTypes[] = { 130 | D3D_DRIVER_TYPE_HARDWARE, 131 | D3D_DRIVER_TYPE_WARP, 132 | D3D_DRIVER_TYPE_REFERENCE, 133 | }; 134 | UINT numDriverTytpes = sizeof(driverTypes) / sizeof(driverTypes[0]); 135 | 136 | D3D_FEATURE_LEVEL featureLevels[] = { 137 | D3D_FEATURE_LEVEL_11_1, 138 | D3D_FEATURE_LEVEL_11_0, 139 | D3D_FEATURE_LEVEL_10_1, 140 | D3D_FEATURE_LEVEL_10_0, 141 | }; 142 | UINT numFeatureLevels = sizeof(featureLevels) / sizeof(featureLevels[0]); 143 | 144 | DXGI_SWAP_CHAIN_DESC sd; 145 | ZeroMemory(&sd, sizeof(DXGI_SWAP_CHAIN_DESC)); 146 | sd.BufferCount = swapChainCount; 147 | sd.BufferDesc.Width = 0; 148 | sd.BufferDesc.Height = 0; 149 | sd.BufferDesc.Format = swapChainFormat; 150 | sd.BufferDesc.RefreshRate.Numerator = 60; 151 | sd.BufferDesc.RefreshRate.Denominator = 1; 152 | sd.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT | DXGI_USAGE_SHADER_INPUT; 153 | sd.OutputWindow = hMainWnd; 154 | sd.SampleDesc.Count = multiSampleCount; 155 | sd.SampleDesc.Quality = multiSampleQuality; 156 | sd.Windowed = TRUE; 157 | 158 | for (UINT idx = 0; idx < numDriverTytpes; ++idx) 159 | { 160 | driverType = driverTypes[idx]; 161 | hr = D3D11CreateDeviceAndSwapChain( 162 | nullptr, 163 | driverType, 164 | NULL, 165 | createDeviceFlags, 166 | featureLevels, 167 | numFeatureLevels, 168 | D3D11_SDK_VERSION, 169 | &sd, 170 | &swapChain, 171 | &d3dDevice, 172 | &featureLevel, 173 | &d3dDeviceContext 174 | ); 175 | 176 | if (SUCCEEDED(hr)) 177 | { 178 | break; 179 | } 180 | } 181 | if (FAILED(hr)) 182 | { 183 | ELOG("Error : D3D11CreateDeviceAndSwapChain() Failed."); 184 | return false; 185 | } 186 | hr = d3dDevice->CheckMultisampleQualityLevels(swapChainFormat, multiSampleCount, &multiSampleMaxQuality); 187 | if (FAILED(hr)) 188 | { 189 | ELOG("Error : D3D11Device::CheckMultiSampleQualityLevels() Failed."); 190 | return false; 191 | } 192 | if (!CreateDefaultRenderTarget()) 193 | { 194 | ELOG("Error : CreateDefaultRenderTarget() Failed."); 195 | return false; 196 | } 197 | if (!CreateDefaultDepthStencil()) 198 | { 199 | ELOG("Error : CreateDefaultDepthStencil() Failed."); 200 | return false; 201 | } 202 | 203 | d3dDeviceContext->OMSetRenderTargets(1, &renderTargetView, depthStencilView); 204 | 205 | D3D11_VIEWPORT vp; 206 | vp.Width = static_cast(w); 207 | vp.Height = static_cast(h); 208 | vp.MinDepth = 0.0f; 209 | vp.MaxDepth = 1.0f; 210 | vp.TopLeftX = 0; 211 | vp.TopLeftY = 0; 212 | d3dDeviceContext->RSSetViewports(1, &vp); 213 | return OnInit(); 214 | } 215 | 216 | void SampleApp::TerminateD3D11() 217 | { 218 | if (d3dDeviceContext != nullptr) 219 | { 220 | d3dDeviceContext->ClearState(); 221 | d3dDeviceContext->Flush(); 222 | } 223 | OnTerminate(); 224 | ReleaseDefaultRenderTarget(); 225 | ReleaseDefaultDepthStencil(); 226 | SAFE_RELEASE(swapChain); 227 | SAFE_RELEASE(d3dDeviceContext); 228 | SAFE_RELEASE(d3dDevice); 229 | } 230 | 231 | bool SampleApp::InitializeApp() 232 | { 233 | if (!OpenWindow()) 234 | { 235 | ELOG("Error : InitWnd() Failed."); 236 | return false; 237 | } 238 | if (!InitializeD3D11()) 239 | { 240 | ELOG("Error : InitD3D11() Failed."); 241 | return false; 242 | } 243 | 244 | LARGE_INTEGER pcf; 245 | QueryPerformanceFrequency(&pcf); 246 | counterPerFrame = pcf.QuadPart / 30; 247 | QueryPerformanceCounter(&prevCounter); 248 | 249 | return true; 250 | } 251 | 252 | void SampleApp::TerminateApp() 253 | { 254 | TerminateD3D11(); 255 | CloseWindow(); 256 | } 257 | 258 | bool SampleApp::CreateDefaultRenderTarget() 259 | { 260 | HRESULT hr = S_OK; 261 | hr = swapChain->GetBuffer(0, __uuidof(ID3D11Texture2D), reinterpret_cast(&renderTargetTexture)); 262 | if (FAILED(hr)) 263 | { 264 | ELOG("Error : IDXGISwapChain::GetBuffer() Failed"); 265 | return false; 266 | } 267 | hr = d3dDevice->CreateRenderTargetView(renderTargetTexture, nullptr, &renderTargetView); 268 | if (FAILED(hr)) 269 | { 270 | ELOG("Error : ID3D11Device::CreateRenderTargetView() Failed."); 271 | return false; 272 | } 273 | hr = d3dDevice->CreateShaderResourceView(renderTargetTexture, nullptr, &renderTargetShaderResourceView); 274 | if (FAILED(hr)) 275 | { 276 | ELOG("Error : ID3D11Device::CreateShaderResourceView() Failed."); 277 | return false; 278 | } 279 | return true; 280 | } 281 | 282 | void SampleApp::ReleaseDefaultRenderTarget() 283 | { 284 | SAFE_RELEASE(renderTargetShaderResourceView); 285 | SAFE_RELEASE(renderTargetView); 286 | SAFE_RELEASE(renderTargetTexture); 287 | } 288 | 289 | bool SampleApp::CreateDefaultDepthStencil() 290 | { 291 | HRESULT hr = S_OK; 292 | 293 | DXGI_FORMAT textureFormat = depthStencilFormat; 294 | DXGI_FORMAT resourceFormat = depthStencilFormat; 295 | 296 | switch (depthStencilFormat) 297 | { 298 | case DXGI_FORMAT_D16_UNORM: 299 | textureFormat = DXGI_FORMAT_R16_TYPELESS; 300 | resourceFormat = DXGI_FORMAT_R16_UNORM; 301 | break; 302 | case DXGI_FORMAT_D24_UNORM_S8_UINT: 303 | textureFormat = DXGI_FORMAT_R24G8_TYPELESS; 304 | resourceFormat = DXGI_FORMAT_R24_UNORM_X8_TYPELESS; 305 | break; 306 | case DXGI_FORMAT_D32_FLOAT: 307 | textureFormat = DXGI_FORMAT_R32_TYPELESS; 308 | resourceFormat = DXGI_FORMAT_R32_FLOAT; 309 | break; 310 | case DXGI_FORMAT_D32_FLOAT_S8X24_UINT: 311 | textureFormat = DXGI_FORMAT_R32G8X24_TYPELESS; 312 | resourceFormat = DXGI_FORMAT_R32_FLOAT_X8X24_TYPELESS; 313 | break; 314 | } 315 | 316 | D3D11_TEXTURE2D_DESC td; 317 | ZeroMemory(&td, sizeof(D3D11_TEXTURE2D_DESC)); 318 | td.Width = wndWidth; 319 | td.Height = wndHeight; 320 | td.MipLevels = 1; 321 | td.ArraySize = 1; 322 | td.Format = textureFormat; 323 | td.SampleDesc.Count = multiSampleCount; 324 | td.SampleDesc.Quality = multiSampleQuality; 325 | td.Usage = D3D11_USAGE_DEFAULT; 326 | td.BindFlags = D3D11_BIND_DEPTH_STENCIL | D3D11_BIND_SHADER_RESOURCE; 327 | td.CPUAccessFlags = 0; 328 | td.MiscFlags = 0; 329 | 330 | hr = d3dDevice->CreateTexture2D(&td, nullptr, &depthStencilTexture); 331 | if (FAILED(hr)) 332 | { 333 | ELOG("Error : ID3D11Device::CreateTexture2D() Failed."); 334 | return false; 335 | } 336 | 337 | D3D11_DEPTH_STENCIL_VIEW_DESC dsvd; 338 | ZeroMemory(&dsvd, sizeof(D3D11_DEPTH_STENCIL_VIEW_DESC)); 339 | dsvd.Format = depthStencilFormat; 340 | if (multiSampleCount == 0) 341 | { 342 | dsvd.ViewDimension = D3D11_DSV_DIMENSION_TEXTURE2D; 343 | dsvd.Texture2D.MipSlice = 0; 344 | } 345 | else 346 | { 347 | dsvd.ViewDimension = D3D11_DSV_DIMENSION_TEXTURE2DMS; 348 | } 349 | 350 | hr = d3dDevice->CreateDepthStencilView(depthStencilTexture, &dsvd, &depthStencilView); 351 | if (FAILED(hr)) 352 | { 353 | ELOG("Error : ID3D11Device::CreateDepthStencilView() Failed."); 354 | return false; 355 | } 356 | 357 | D3D11_SHADER_RESOURCE_VIEW_DESC srvd; 358 | ZeroMemory(&srvd, sizeof(D3D11_SHADER_RESOURCE_VIEW_DESC)); 359 | srvd.Format = resourceFormat; 360 | 361 | if (multiSampleCount == 0) 362 | { 363 | srvd.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D; 364 | srvd.Texture2D.MostDetailedMip = 0; 365 | srvd.Texture2D.MipLevels = 1; 366 | } 367 | else 368 | { 369 | srvd.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2DMS; 370 | } 371 | 372 | hr = d3dDevice->CreateShaderResourceView(depthStencilTexture, &srvd, &depthStencilShaderResourceView); 373 | if (FAILED(hr)) 374 | { 375 | ELOG("Error : ID3D11Device::CreateShaderResourceView() Failed."); 376 | return false; 377 | } 378 | return true; 379 | } 380 | 381 | void SampleApp::ReleaseDefaultDepthStencil() 382 | { 383 | SAFE_RELEASE(depthStencilShaderResourceView); 384 | SAFE_RELEASE(depthStencilView); 385 | SAFE_RELEASE(depthStencilTexture); 386 | } 387 | 388 | bool SampleApp::OnInit() 389 | { 390 | bool retval = true; 391 | std::for_each(object.begin(), object.end(), [&](Object::SharedPtr o) 392 | { 393 | if (!o->OnInit(d3dDevice, d3dDeviceContext, wndWidth, wndHeight)) 394 | { 395 | ELOG("Error : Object::OnInit() Failed."); 396 | retval = false; 397 | } 398 | }); 399 | return retval; 400 | } 401 | 402 | void SampleApp::OnTerminate() 403 | { 404 | std::for_each(object.begin(), object.end(), [&](Object::SharedPtr o) 405 | { 406 | o->OnDestroy(); 407 | o.reset(); 408 | }); 409 | } 410 | 411 | void SampleApp::OnRender() 412 | { 413 | assert(renderTargetView != nullptr); 414 | assert(depthStencilView != nullptr); 415 | 416 | d3dDeviceContext->ClearRenderTargetView(renderTargetView, clearColor); 417 | d3dDeviceContext->ClearDepthStencilView(depthStencilView, D3D11_CLEAR_DEPTH | D3D11_CLEAR_STENCIL, 1.0f, 0); 418 | std::for_each(object.begin(), object.end(), [&](Object::SharedPtr o) 419 | { 420 | o->OnRender(d3dDevice, d3dDeviceContext); 421 | }); 422 | swapChain->Present(0, 0); 423 | } 424 | 425 | void SampleApp::OnResize(const UINT w, const UINT h) 426 | { 427 | if (swapChain && d3dDeviceContext) 428 | { 429 | wndWidth = w; 430 | wndHeight = h; 431 | aspectRatio = static_cast(w) / static_cast(h); 432 | 433 | ID3D11RenderTargetView* pNull = nullptr; 434 | d3dDeviceContext->OMSetRenderTargets(1, &pNull, nullptr); 435 | ReleaseDefaultRenderTarget(); 436 | ReleaseDefaultDepthStencil(); 437 | 438 | HRESULT hr = S_OK; 439 | hr = swapChain->ResizeBuffers(swapChainCount, 0, 0, swapChainFormat, 0); 440 | if (FAILED(hr)) 441 | { 442 | ELOG("Error : IDXGISwapChain::ResizeBuffer() Failed."); 443 | } 444 | 445 | if (!CreateDefaultRenderTarget()) 446 | { 447 | ELOG("Error : CreateDefaultRenderTarget() Failed."); 448 | } 449 | if (!CreateDefaultDepthStencil()) 450 | { 451 | ELOG("Error : CreateDefaultDepthStencil() Failed."); 452 | } 453 | d3dDeviceContext->OMSetRenderTargets(1, &renderTargetView, depthStencilView); 454 | 455 | D3D11_VIEWPORT vp; 456 | vp.Width = static_cast(w); 457 | vp.Height = static_cast(h); 458 | vp.MinDepth = 0.0f; 459 | vp.MaxDepth = 1.0f; 460 | vp.TopLeftX = 0; 461 | vp.TopLeftY = 0; 462 | d3dDeviceContext->RSSetViewports(1, &vp); 463 | } 464 | std::for_each(object.begin(), object.end(), [&](Object::SharedPtr o) 465 | { 466 | o->OnResize(d3dDevice, d3dDeviceContext, w, h); 467 | }); 468 | } 469 | 470 | void SampleApp::OnUpdate(LONGLONG elapsed) 471 | { 472 | std::for_each(object.begin(), object.end(), [&](Object::SharedPtr o) 473 | { 474 | o->OnUpdate(d3dDevice, d3dDeviceContext, static_cast(elapsed) / static_cast(counterPerFrame * 30)); 475 | }); 476 | } 477 | 478 | int SampleApp::MainLoop() 479 | { 480 | MSG msg = { 0 }; 481 | 482 | while (WM_QUIT != msg.message) 483 | { 484 | if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) 485 | { 486 | TranslateMessage(&msg); 487 | DispatchMessage(&msg); 488 | } 489 | else 490 | { 491 | LARGE_INTEGER pc; 492 | QueryPerformanceCounter(&pc); 493 | if (pc.QuadPart - prevCounter.QuadPart >= counterPerFrame) 494 | { 495 | LONGLONG elapsed = pc.QuadPart - prevCounter.QuadPart; 496 | prevCounter = pc; 497 | OnUpdate(elapsed); 498 | OnRender(); 499 | } 500 | } 501 | } 502 | 503 | return (int)msg.wParam; 504 | } 505 | 506 | int SampleApp::Run() 507 | { 508 | int retcode = -1; 509 | if (InitializeApp()) 510 | { 511 | retcode = MainLoop(); 512 | } 513 | TerminateApp(); 514 | return retcode; 515 | } 516 | 517 | LRESULT CALLBACK SampleApp::WndProc(HWND hWnd, UINT msg, WPARAM wp, LPARAM lp) 518 | { 519 | PAINTSTRUCT ps; 520 | HDC hdc; 521 | 522 | switch (msg) 523 | { 524 | case WM_PAINT: 525 | hdc = BeginPaint(hWnd, &ps); 526 | EndPaint(hWnd, &ps); 527 | break; 528 | case WM_DESTROY: 529 | PostQuitMessage(0); 530 | break; 531 | case WM_SIZE: 532 | s_pThis->OnResize(static_cast(LOWORD(lp)), static_cast(HIWORD(lp))); 533 | break; 534 | default: 535 | break; 536 | } 537 | return DefWindowProc(hWnd, msg, wp, lp); 538 | } 539 | 540 | void SampleApp::AddObject(Object::SharedPtr obj) 541 | { 542 | if (std::find(object.begin(), object.end(), obj) == object.end()) 543 | { 544 | object.push_back(obj); 545 | } 546 | } 547 | -------------------------------------------------------------------------------- /HorseObject.cpp: -------------------------------------------------------------------------------- 1 | #include "HorseObject.h" 2 | #include 3 | #include "util.h" 4 | #include "SSDR.h" 5 | 6 | using namespace DirectX; 7 | 8 | HRESULT CompileShaderFromFile(std::wstring fileName, char* entryPoint, char* shaderModel, ID3DBlob*& blob) 9 | { 10 | HRESULT hr = S_OK; 11 | DWORD dwShaderFlags = D3DCOMPILE_ENABLE_STRICTNESS; 12 | 13 | #ifdef _DEBUG 14 | dwShaderFlags |= D3DCOMPILE_DEBUG; 15 | #else 16 | dwShaderFlags |= D3DCOMPILE_OPTIMIZATION_LEVEL3; 17 | #endif 18 | 19 | ID3DBlob* errorBlob = nullptr; 20 | hr = D3DCompileFromFile( 21 | fileName.c_str(), 22 | nullptr, 23 | D3D_COMPILE_STANDARD_FILE_INCLUDE, 24 | entryPoint, 25 | shaderModel, 26 | dwShaderFlags, 27 | 0, 28 | &blob, 29 | &errorBlob 30 | ); 31 | if (FAILED(hr)) 32 | { 33 | if (errorBlob != nullptr) 34 | { 35 | OutputDebugStringA(static_cast(errorBlob->GetBufferPointer())); 36 | } 37 | } 38 | if (errorBlob != nullptr) 39 | { 40 | errorBlob->Release(); 41 | } 42 | return hr; 43 | } 44 | 45 | D3D11_INPUT_ELEMENT_DESC HorseObject::customVertexLayout[5] = { 46 | { "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0 }, 47 | { "NORMAL", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 16, D3D11_INPUT_PER_VERTEX_DATA, 0 }, 48 | { "BLENDWEIGHT", 0, DXGI_FORMAT_R32G32B32A32_FLOAT, 0, 32, D3D11_INPUT_PER_VERTEX_DATA, 0 }, 49 | { "BLENDINDICES", 0, DXGI_FORMAT_R32G32B32A32_UINT, 0, 48, D3D11_INPUT_PER_VERTEX_DATA, 0 }, 50 | { "COLOR", 0, DXGI_FORMAT_R32G32B32A32_FLOAT, 0, 64, D3D11_INPUT_PER_VERTEX_DATA, 0 } 51 | }; 52 | 53 | HorseObject::HorseObject() 54 | : constantBufferPerFrame(nullptr), 55 | constantBufferSkinningBone(nullptr), 56 | constantBufferPerObj(nullptr), 57 | lightPosition(5.0f, 5.0f, 0.0f), 58 | inputLayout(nullptr), 59 | vertexShader(nullptr), pixelShader(nullptr), alphaBlendState(nullptr), 60 | vertexBuffer(nullptr), indexBuffer(nullptr), numVertices(0), numFaces(0), 61 | vertexBufferCPU(nullptr), srcVertexBufferCPU(nullptr), numFrames(0), frame(0) 62 | { 63 | } 64 | 65 | HorseObject::~HorseObject() 66 | { 67 | } 68 | 69 | HRESULT HorseObject::InitShader(ID3D11Device* device) 70 | { 71 | HRESULT hr = S_OK; 72 | 73 | // alpha blend state 74 | D3D11_BLEND_DESC blendDesc; 75 | ZeroMemory(&blendDesc, sizeof(D3D11_BLEND_DESC)); 76 | blendDesc.AlphaToCoverageEnable = FALSE; 77 | blendDesc.IndependentBlendEnable = FALSE; 78 | for (int i = 0; i < 8; ++i) 79 | { 80 | blendDesc.RenderTarget[i].BlendEnable = TRUE; 81 | blendDesc.RenderTarget[i].SrcBlend = D3D11_BLEND_SRC_ALPHA; 82 | blendDesc.RenderTarget[i].DestBlend = D3D11_BLEND_INV_SRC_ALPHA; 83 | blendDesc.RenderTarget[i].BlendOp = D3D11_BLEND_OP_ADD; 84 | blendDesc.RenderTarget[i].SrcBlendAlpha = D3D11_BLEND_ONE; 85 | blendDesc.RenderTarget[i].DestBlendAlpha = D3D11_BLEND_ZERO; 86 | blendDesc.RenderTarget[i].BlendOpAlpha = D3D11_BLEND_OP_ADD; 87 | blendDesc.RenderTarget[i].RenderTargetWriteMask = D3D11_COLOR_WRITE_ENABLE_ALL; 88 | } 89 | hr = device->CreateBlendState(&blendDesc, &alphaBlendState); 90 | if (FAILED(hr)) 91 | { 92 | return hr; 93 | } 94 | 95 | // per-frame constant buffer 96 | D3D11_BUFFER_DESC bufferDesc; 97 | ZeroMemory(&bufferDesc, sizeof(D3D11_BUFFER_DESC)); 98 | bufferDesc.ByteWidth = sizeof(ConstantBufferPerFrame); 99 | bufferDesc.Usage = D3D11_USAGE_DEFAULT; 100 | bufferDesc.BindFlags = D3D11_BIND_CONSTANT_BUFFER; 101 | bufferDesc.CPUAccessFlags = 0; 102 | hr = device->CreateBuffer(&bufferDesc, nullptr, &constantBufferPerFrame); 103 | if (FAILED(hr)) 104 | { 105 | assert(false && "ID3D11Device::CreateBuffer() Failed."); 106 | return false; 107 | } 108 | 109 | // matrix palette 110 | ZeroMemory(&bufferDesc, sizeof(D3D11_BUFFER_DESC)); 111 | bufferDesc.ByteWidth = sizeof(ConstantBufferSkinningMatrix); 112 | bufferDesc.Usage = D3D11_USAGE_DEFAULT; 113 | bufferDesc.BindFlags = D3D11_BIND_CONSTANT_BUFFER; 114 | bufferDesc.CPUAccessFlags = 0; 115 | hr = device->CreateBuffer(&bufferDesc, nullptr, &constantBufferSkinningBone); 116 | if (FAILED(hr)) 117 | { 118 | assert(false && "ID3D11Device::CreateBuffer() Failed."); 119 | return hr; 120 | } 121 | 122 | // per-object constant buffer 123 | ZeroMemory(&bufferDesc, sizeof(D3D11_BUFFER_DESC)); 124 | bufferDesc.ByteWidth = sizeof(ConstantBufferPerObj); 125 | bufferDesc.Usage = D3D11_USAGE_DEFAULT; 126 | bufferDesc.BindFlags = D3D11_BIND_CONSTANT_BUFFER; 127 | bufferDesc.CPUAccessFlags = 0; 128 | hr = device->CreateBuffer(&bufferDesc, nullptr, &constantBufferPerObj); 129 | if (FAILED(hr)) 130 | { 131 | assert(false && "ID3D11Device::CreateBuffer() Failed."); 132 | return hr; 133 | } 134 | 135 | // vertex shader 136 | ID3DBlob* blob = nullptr; 137 | hr = CompileShaderFromFile(L"./ssdr.fx", "LambertSkinVS", "vs_5_0", blob); 138 | if (FAILED(hr)) 139 | { 140 | if (blob != nullptr) 141 | { 142 | blob->Release(); 143 | } 144 | return hr; 145 | } 146 | hr = device->CreateVertexShader(blob->GetBufferPointer(), blob->GetBufferSize(), nullptr, &vertexShader); 147 | if (FAILED(hr)) 148 | { 149 | assert(false && "CompileShaderFromFile() Failed"); 150 | return false; 151 | } 152 | 153 | // vertex layout 154 | UINT numElements = ARRAYSIZE(customVertexLayout); 155 | hr = device->CreateInputLayout(customVertexLayout, numElements, blob->GetBufferPointer(), blob->GetBufferSize(), &inputLayout); 156 | if (blob != nullptr) 157 | { 158 | blob->Release(); 159 | } 160 | if (FAILED(hr)) 161 | { 162 | assert(false && "ID3D11Device::CreateInputLayout() Failed."); 163 | return false; 164 | } 165 | 166 | // pixel shader 167 | hr = CompileShaderFromFile(L"./ssdr.fx", "LambertPS", "ps_5_0", blob); 168 | if (FAILED(hr)) 169 | { 170 | if (blob != nullptr) 171 | { 172 | blob->Release(); 173 | } 174 | return hr; 175 | } 176 | hr = device->CreatePixelShader(blob->GetBufferPointer(), blob->GetBufferSize(), nullptr, &pixelShader); 177 | if (FAILED(hr)) 178 | { 179 | assert(false && "ID3D11Device::CreateVertexShader() Failed."); 180 | if (blob != nullptr) 181 | { 182 | blob->Release(); 183 | } 184 | return hr; 185 | } 186 | if (blob != nullptr) 187 | { 188 | blob->Release(); 189 | } 190 | return hr; 191 | } 192 | 193 | HRESULT HorseObject::LoadModel(ID3D11Device* device, const wchar_t* filePath, const XMFLOAT4A& color) 194 | { 195 | HRESULT hr = S_OK; 196 | 197 | std::vector position, normal; 198 | std::vector index; 199 | LoadObjFile(position, index, filePath, 1.0f); 200 | ComputeNormal(normal, position, index); 201 | 202 | numVertices = static_cast(position.size()); 203 | numFaces = static_cast(index.size() / 3); 204 | 205 | D3D11_BUFFER_DESC bd; 206 | D3D11_SUBRESOURCE_DATA initData; 207 | ZeroMemory(&bd, sizeof(D3D11_BUFFER_DESC)); 208 | bd.Usage = D3D11_USAGE_DEFAULT; 209 | bd.ByteWidth = sizeof(CustomVertex) * numVertices; 210 | bd.BindFlags = D3D11_BIND_VERTEX_BUFFER; 211 | bd.CPUAccessFlags = 0; 212 | ZeroMemory(&initData, sizeof(D3D11_SUBRESOURCE_DATA)); 213 | vertexBufferCPU = new CustomVertex[numVertices]; 214 | ZeroMemory(vertexBufferCPU, sizeof(CustomVertex) * numVertices); 215 | srcVertexBufferCPU = new CustomVertex[numVertices]; 216 | ZeroMemory(srcVertexBufferCPU, sizeof(CustomVertex) * numVertices); 217 | initData.pSysMem = vertexBufferCPU; 218 | for (unsigned long v = 0; v < numVertices; ++v) 219 | { 220 | vertexBufferCPU[v].position = position[v]; 221 | vertexBufferCPU[v].normal = normal[v]; 222 | srcVertexBufferCPU[v].normal = normal[v]; 223 | for (int i = 0; i < CustomVertex::NumInfluences; ++i) 224 | { 225 | vertexBufferCPU[v].indices[i] = 0; 226 | vertexBufferCPU[v].weight[i] = 0; 227 | srcVertexBufferCPU[v].indices[i] = 0; 228 | srcVertexBufferCPU[v].weight[i] = 0; 229 | } 230 | vertexBufferCPU[v].color = color; 231 | srcVertexBufferCPU[v].color = XMFLOAT4A(color.x, color.y, color.z, 0.5f); 232 | vertexBufferCPU[v].weight[0] = 1.0f; 233 | } 234 | 235 | hr = device->CreateBuffer(&bd, &initData, &vertexBuffer); 236 | if (FAILED(hr)) 237 | { 238 | assert(false && "ID3D11Device::CreateBuffer() Failed."); 239 | return false; 240 | } 241 | 242 | ZeroMemory(&bd, sizeof(D3D11_BUFFER_DESC)); 243 | bd.Usage = D3D11_USAGE_DEFAULT; 244 | bd.ByteWidth = sizeof(DWORD)* numFaces * 3; 245 | bd.BindFlags = D3D11_BIND_INDEX_BUFFER; 246 | bd.CPUAccessFlags = 0; 247 | 248 | ZeroMemory(&initData, sizeof(D3D11_SUBRESOURCE_DATA)); 249 | std::unique_ptr indexBuf(new DWORD[numFaces * 3]); 250 | initData.pSysMem = indexBuf.get(); 251 | for (unsigned long v = 0; v < numFaces * 3; ++v) 252 | { 253 | indexBuf[v] = index[v]; 254 | } 255 | hr = device->CreateBuffer(&bd, &initData, &indexBuffer); 256 | if (FAILED(hr)) 257 | { 258 | assert(false && "ID3D11Device::CreateBuffer() Failed."); 259 | return false; 260 | } 261 | 262 | return hr; 263 | } 264 | 265 | bool HorseObject::LoadAnim(const wchar_t* filePath) 266 | { 267 | bool retval = true; 268 | wchar_t pathBuf[1024]; 269 | numFrames = 1; 270 | for (;; ++numFrames) 271 | { 272 | swprintf_s(pathBuf, filePath, numFrames); 273 | if (GetFileAttributesW(pathBuf) == -1) 274 | { 275 | --numFrames; 276 | break; 277 | } 278 | } 279 | vertexAnim.resize(numFrames * numVertices); 280 | 281 | std::vector position, normal; 282 | std::vector index; 283 | for (unsigned long f = 0; f < numFrames; ++f) 284 | { 285 | swprintf_s(pathBuf, filePath, f + 1); 286 | retval = LoadObjFile(position, index, pathBuf, 1.0f); 287 | if (!retval) 288 | { 289 | break; 290 | } 291 | for (unsigned long v = 0; v < numVertices; ++v) 292 | { 293 | vertexAnim[f * numVertices + v] = position[v]; 294 | } 295 | } 296 | if (!retval) 297 | { 298 | vertexAnim.clear(); 299 | } 300 | return retval; 301 | } 302 | 303 | bool HorseObject::OnInit(ID3D11Device* device, ID3D11DeviceContext* deviceContext, const UINT width, const UINT height) 304 | { 305 | HRESULT hr = InitShader(device); 306 | if (FAILED(hr)) 307 | { 308 | assert(false && "HorseObject::InitShader() Failed."); 309 | return false; 310 | } 311 | 312 | // projection matrix 313 | FLOAT aspectRatio = static_cast(width) / static_cast(height); 314 | XMMATRIX projMatrix = XMMatrixPerspectiveFovLH(XM_PIDIV4, aspectRatio, 0.001f, 1000.0f); 315 | XMStoreFloat4x4A(&perFrameData.proj, XMMatrixTranspose(projMatrix)); 316 | 317 | LoadModel(device, L"./data/horse-gallop-reference.obj", XMFLOAT4A(0.5f, 0.5f, 0.5f, 1.0f)); 318 | LoadAnim(L"./data/horse-gallop-%02d.obj"); 319 | 320 | // SSDR 321 | // 322 | SSDR::Input ssdrIn; 323 | ssdrIn.numVertices = numVertices; 324 | ssdrIn.numExamples = numFrames; 325 | ssdrIn.bindModel.resize(numVertices); 326 | for (unsigned long v = 0; v < numVertices; ++v) 327 | { 328 | ssdrIn.bindModel[v] = vertexBufferCPU[v].position; 329 | } 330 | ssdrIn.sample.resize(numFrames * numVertices); 331 | for (unsigned long s = 0; s < numFrames; ++s) 332 | { 333 | for (unsigned long v = 0; v < numVertices; ++v) 334 | { 335 | ssdrIn.sample[s * numVertices + v] = vertexAnim[s * numVertices + v]; 336 | } 337 | } 338 | 339 | SSDR::Parameter ssdrParam; 340 | ssdrParam.numIndices = CustomVertex::NumInfluences; 341 | ssdrParam.numMinBones = 16; 342 | ssdrParam.numMaxIterations = 30; 343 | 344 | SSDR::Output ssdrOut; 345 | SSDR::Decompose(ssdrOut, ssdrIn, ssdrParam); 346 | 347 | for (unsigned long v = 0; v < numVertices; ++v) 348 | { 349 | vertexBufferCPU[v].position = ssdrIn.bindModel[v]; 350 | for (int i = 0; i < CustomVertex::NumInfluences; ++i) 351 | { 352 | vertexBufferCPU[v].indices[i] = ssdrOut.index[v * ssdrParam.numIndices + i]; 353 | vertexBufferCPU[v].weight[i] = ssdrOut.weight[v * ssdrParam.numIndices + i]; 354 | } 355 | } 356 | deviceContext->UpdateSubresource(vertexBuffer, 0, nullptr, vertexBufferCPU, 0, 0); 357 | 358 | numBones = ssdrOut.numBones; 359 | boneAnim.resize(ssdrIn.numExamples * ssdrOut.numBones); 360 | for (int s = 0; s < ssdrIn.numExamples; ++s) 361 | { 362 | for (int b = 0; b < ssdrOut.numBones; ++b) 363 | { 364 | boneAnim[s * ssdrOut.numBones + b] = ssdrOut.boneTrans[s * ssdrOut.numBones + b]; 365 | } 366 | } 367 | 368 | fprintf(stderr, "%d\n", numBones); 369 | 370 | return Object::OnInit(device, deviceContext, width, height); 371 | } 372 | 373 | void HorseObject::OnResize(ID3D11Device* device, ID3D11DeviceContext* deviceContext, const UINT width, const UINT height) 374 | { 375 | FLOAT aspectRatio = static_cast(width) / static_cast(height); 376 | XMMATRIX projMatrix = XMMatrixPerspectiveFovLH(XM_PIDIV4, aspectRatio, 0.001f, 1000.0f); 377 | XMStoreFloat4x4A(&perFrameData.proj, XMMatrixTranspose(projMatrix)); 378 | } 379 | 380 | void HorseObject::ColorVerticesByError(int frame, float upperBound) 381 | { 382 | for (int v = 0; v < numVertices; ++v) 383 | { 384 | XMVECTOR pos = XMVectorZero(); 385 | for (long i = 0; i < CustomVertex::NumInfluences; ++i) 386 | { 387 | const RigidTransform& rt = boneAnim[numBones * frame + vertexBufferCPU[v].indices[i]]; 388 | XMVECTOR xv = XMLoadFloat3A(&vertexBufferCPU[v].position); 389 | pos += vertexBufferCPU[v].weight[i] * rt.TransformCoord(xv); 390 | } 391 | XMVECTOR err = XMVector3Length(pos - XMLoadFloat3A(&vertexAnim[numVertices * frame + v])); 392 | float l = XMVectorGetX(err) / upperBound; 393 | if (l > 1.0f) l = 1.0f; 394 | vertexBufferCPU[v].color = XMFLOAT4A(1.0f, 1.0f - l, 1.0f - l, vertexBufferCPU[v].color.w); 395 | } 396 | } 397 | 398 | void HorseObject::OnUpdate(ID3D11Device* device, ID3D11DeviceContext* deviceContext, float elapsed) 399 | { 400 | frame = (frame + 1) % numFrames; 401 | 402 | // per-frame constant buffer 403 | // 404 | // view matrix 405 | XMVECTOR cameraPos = XMVectorSet(1.3f, 0.5f, 0, 1.0f); 406 | XMVECTOR cameraTgt = XMVectorSet(0, 0.5f, 0, 1.0f); 407 | XMVECTOR cameraUp = XMVectorSet(0, 1.0f, 0, 1.0f); 408 | XMMATRIX viewMatrix = XMMatrixLookAtLH(cameraPos, cameraTgt, cameraUp); 409 | XMStoreFloat4x4A(&perFrameData.view, XMMatrixTranspose(viewMatrix)); 410 | // light color 411 | perFrameData.lightColor = XMFLOAT4A(1.0f, 1.0f, 1.0f, 1.0f); 412 | deviceContext->UpdateSubresource(constantBufferPerFrame, 0, nullptr, &perFrameData, 0, 0); 413 | 414 | ConstantBufferSkinningMatrix cbs; 415 | for (int i = 0; i < numBones; ++i) 416 | { 417 | XMFLOAT4X4A m = boneAnim[frame * numBones + i].ToMatrix4x4(); 418 | XMStoreFloat4x4A(cbs.pallet + i, XMMatrixTranspose(XMLoadFloat4x4A(&m))); 419 | } 420 | XMStoreFloat4x4A(cbs.pallet + numBones, XMMatrixIdentity()); 421 | deviceContext->UpdateSubresource(constantBufferSkinningBone, 0, nullptr, &cbs, 0, 0); 422 | 423 | ColorVerticesByError(frame, 0.05f); 424 | 425 | ConstantBufferPerObj cbo; 426 | XMMATRIX invModelTransform = XMMatrixIdentity(); 427 | XMStoreFloat4x4(&cbo.world, XMMatrixTranspose(invModelTransform)); 428 | XMStoreFloat3A(&cbo.localEyePos, XMVector3TransformCoord(cameraPos, invModelTransform)); 429 | XMStoreFloat3A(&cbo.localLightPos, XMVector3TransformCoord(XMVectorSetW(XMLoadFloat3A(&lightPosition), 1.0f), invModelTransform)); 430 | cbo.ambientColor = XMFLOAT4A(0.4f, 0.4f, 0.4f, 1.0f); 431 | cbo.specExpon = 1.0f; 432 | deviceContext->UpdateSubresource(constantBufferPerObj, 0, nullptr, &cbo, 0, 0); 433 | 434 | for (unsigned long v = 0; v < numVertices; ++v) 435 | { 436 | srcVertexBufferCPU[v].position = vertexAnim[frame * numVertices + v]; 437 | srcVertexBufferCPU[v].indices[0] = numBones; 438 | srcVertexBufferCPU[v].weight[0] = 1.0; 439 | } 440 | 441 | Object::OnUpdate(device, deviceContext, elapsed); 442 | } 443 | 444 | void HorseObject::OnRender(ID3D11Device* device, ID3D11DeviceContext* deviceContext) 445 | { 446 | // per-frame constant buffer 447 | deviceContext->VSSetConstantBuffers(0, 1, &constantBufferPerFrame); 448 | deviceContext->PSSetConstantBuffers(0, 1, &constantBufferPerFrame); 449 | 450 | // matrix palette 451 | deviceContext->VSSetConstantBuffers(2, 1, &constantBufferSkinningBone); 452 | deviceContext->PSSetConstantBuffers(2, 1, &constantBufferSkinningBone); 453 | 454 | float blendFactor[4] = { 0.0f, 0.0f, 0.0f, 0.0f }; 455 | deviceContext->OMSetBlendState(alphaBlendState, blendFactor, 0xffffffff); 456 | deviceContext->IASetInputLayout(inputLayout); 457 | deviceContext->VSSetShader(vertexShader, nullptr, 0); 458 | deviceContext->GSSetShader(nullptr, nullptr, 0); 459 | deviceContext->PSSetShader(pixelShader, nullptr, 0); 460 | 461 | if (vertexBuffer != nullptr && indexBuffer != nullptr) 462 | { 463 | // per-object constant buffer 464 | deviceContext->VSSetConstantBuffers(1, 1, &constantBufferPerObj); 465 | deviceContext->PSSetConstantBuffers(1, 1, &constantBufferPerObj); 466 | 467 | // vertex & index buffer 468 | UINT stride = sizeof(CustomVertex); 469 | UINT offset = 0; 470 | deviceContext->IASetVertexBuffers(0, 1, &vertexBuffer, &stride, &offset); 471 | deviceContext->IASetIndexBuffer(indexBuffer, DXGI_FORMAT_R32_UINT, 0); 472 | deviceContext->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST); 473 | 474 | deviceContext->UpdateSubresource(vertexBuffer, 0, nullptr, vertexBufferCPU, 0, 0); 475 | deviceContext->DrawIndexed(numFaces * 3, 0, 0); 476 | 477 | //deviceContext->UpdateSubresource(vertexBuffer, 0, nullptr, srcVertexBufferCPU, 0, 0); 478 | //deviceContext->DrawIndexed(numFaces * 3, 0, 0); 479 | } 480 | 481 | Object::OnRender(device, deviceContext); 482 | } 483 | 484 | void HorseObject::OnDestroy() 485 | { 486 | if (vertexBufferCPU != nullptr) 487 | { 488 | delete[] vertexBufferCPU; 489 | vertexBufferCPU = nullptr; 490 | } 491 | if (vertexBuffer != nullptr) 492 | { 493 | vertexBuffer->Release(); 494 | vertexBuffer = nullptr; 495 | } 496 | if (indexBuffer != nullptr) 497 | { 498 | indexBuffer->Release(); 499 | indexBuffer = nullptr; 500 | } 501 | if (constantBufferPerFrame != nullptr) 502 | { 503 | constantBufferPerFrame->Release(); 504 | constantBufferPerFrame = nullptr; 505 | } 506 | if (constantBufferPerObj != nullptr) 507 | { 508 | constantBufferPerObj->Release(); 509 | constantBufferPerObj = nullptr; 510 | } 511 | if (constantBufferSkinningBone != nullptr) 512 | { 513 | constantBufferSkinningBone->Release(); 514 | constantBufferSkinningBone = nullptr; 515 | } 516 | if (inputLayout != nullptr) 517 | { 518 | inputLayout->Release(); 519 | inputLayout = nullptr; 520 | } 521 | if (vertexShader != nullptr) 522 | { 523 | vertexShader->Release(); 524 | vertexShader = nullptr; 525 | } 526 | if (pixelShader != nullptr) 527 | { 528 | pixelShader->Release(); 529 | pixelShader = nullptr; 530 | } 531 | if (alphaBlendState != nullptr) 532 | { 533 | alphaBlendState->Release(); 534 | alphaBlendState = nullptr; 535 | } 536 | Object::OnDestroy(); 537 | } 538 | --------------------------------------------------------------------------------