/src/ogre/OgreMain/include/OgreInstanceBatchVTF.h
Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | ----------------------------------------------------------------------------- |
3 | | This source file is part of OGRE |
4 | | (Object-oriented Graphics Rendering Engine) |
5 | | For the latest info, see http://www.ogre3d.org/ |
6 | | |
7 | | Copyright (c) 2000-2014 Torus Knot Software Ltd |
8 | | |
9 | | Permission is hereby granted, free of charge, to any person obtaining a copy |
10 | | of this software and associated documentation files (the "Software"), to deal |
11 | | in the Software without restriction, including without limitation the rights |
12 | | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
13 | | copies of the Software, and to permit persons to whom the Software is |
14 | | furnished to do so, subject to the following conditions: |
15 | | |
16 | | The above copyright notice and this permission notice shall be included in |
17 | | all copies or substantial portions of the Software. |
18 | | |
19 | | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
20 | | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
21 | | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
22 | | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
23 | | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
24 | | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN |
25 | | THE SOFTWARE. |
26 | | ----------------------------------------------------------------------------- |
27 | | */ |
28 | | #ifndef __BaseInstanceBatchVTF_H__ |
29 | | #define __BaseInstanceBatchVTF_H__ |
30 | | |
31 | | #include "OgreInstanceBatch.h" |
32 | | #include "OgreTexture.h" |
33 | | #include "OgreHeaderPrefix.h" |
34 | | |
35 | | namespace Ogre |
36 | | { |
37 | | /** \addtogroup Core |
38 | | * @{ |
39 | | */ |
40 | | /** \addtogroup Scene |
41 | | * @{ |
42 | | */ |
43 | | |
44 | | /** Instancing implementation using vertex texture through Vertex Texture Fetch (VTF) |
45 | | This implementation has the following advantages: |
46 | | - Supports huge amount of instances per batch |
47 | | - Supports skinning even with huge ammounts of instances per batch |
48 | | - Doesn't need shader constants registers. |
49 | | - Best suited for skinned entities |
50 | | |
51 | | But beware the disadvantages: |
52 | | - VTF is only fast on modern GPUs (ATI Radeon HD 2000+, GeForce 8+ series onwards) |
53 | | - On GeForce 6/7 series VTF is too slow |
54 | | - VTF isn't (controversely) supported on old ATI X1800 hardware |
55 | | - Only one bone weight per vertex is supported |
56 | | - GPUs with low memory bandwidth (i.e. laptops and integrated GPUs) |
57 | | may perform even worse than no instancing |
58 | | |
59 | | Whether this performs great or bad depends on the hardware. It improved up to 4x performance on |
60 | | a Intel Core 2 Quad Core X9650 GeForce 8600 GTS, and in an Intel Core 2 Duo P7350 ATI |
61 | | Mobility Radeon HD 4650, but went 0.75x slower on an AthlonX2 5000+ integrated nForce 6150 SE |
62 | | Each BaseInstanceBatchVTF has it's own texture, which occupies memory in VRAM. |
63 | | Approx VRAM usage can be computed by doing 12 bytes * 3 * numInstances * numBones |
64 | | Use flag IM_VTFBESTFIT to avoid wasting VRAM (but may reduce amount of instances per batch). |
65 | | |
66 | | The material requires at least a texture unit stage named @c InstancingVTF |
67 | | |
68 | | */ |
69 | | class _OgreExport BaseInstanceBatchVTF : public InstanceBatch |
70 | | { |
71 | | protected: |
72 | | typedef std::vector<uint8> HWBoneIdxVec; |
73 | | typedef std::vector<float> HWBoneWgtVec; |
74 | | typedef std::vector<Matrix4> Matrix4Vec; |
75 | | |
76 | | size_t mMatricesPerInstance; //number of bone matrices per instance |
77 | | size_t mNumWorldMatrices; //Num bones * num instances |
78 | | TexturePtr mMatrixTexture; //The VTF |
79 | | |
80 | | //Used when all matrices from each instance must be in the same row (i.e. HW Instancing). |
81 | | //A few pixels are wasted, but resizing the texture puts the danger of not sampling the |
82 | | //right pixel... (in theory it should work, but in practice doesn't) |
83 | | size_t mWidthFloatsPadding; |
84 | | size_t mMaxFloatsPerLine; |
85 | | |
86 | | size_t mRowLength; |
87 | | size_t mWeightCount; |
88 | | //Temporary array used to store 3x4 matrices before they are converted to dual quaternions |
89 | | Matrix3x4f* mTempTransformsArray3x4; |
90 | | |
91 | | // The state of the usage of bone matrix lookup |
92 | | bool mUseBoneMatrixLookup; |
93 | | size_t mMaxLookupTableInstances; |
94 | | |
95 | | bool mUseBoneDualQuaternions; |
96 | | bool mForceOneWeight; |
97 | | bool mUseOneWeight; |
98 | | |
99 | | /** Clones the base material so it can have it's own vertex texture, and also |
100 | | clones it's shadow caster materials, if it has any |
101 | | */ |
102 | | void cloneMaterial( const MaterialPtr &material ); |
103 | | |
104 | | /** Retrieves bone data from the original sub mesh and puts it into an appropriate buffer, |
105 | | later to be read when creating the vertex semantics. |
106 | | Assumes outBoneIdx has enough space (base submesh vertex count) |
107 | | */ |
108 | | void retrieveBoneIdx( VertexData *baseVertexData, HWBoneIdxVec &outBoneIdx ); |
109 | | |
110 | | /** @see retrieveBoneIdx() |
111 | | Assumes outBoneIdx has enough space (twice the base submesh vertex count, one for each weight) |
112 | | Assumes outBoneWgt has enough space (twice the base submesh vertex count, one for each weight) |
113 | | */ |
114 | | void retrieveBoneIdxWithWeights(VertexData *baseVertexData, HWBoneIdxVec &outBoneIdx, HWBoneWgtVec &outBoneWgt); |
115 | | |
116 | | /** Setups the material to use a vertex texture */ |
117 | | void setupMaterialToUseVTF( TextureType textureType, MaterialPtr &material ) const; |
118 | | |
119 | | /** Creates the vertex texture */ |
120 | | void createVertexTexture( const SubMesh* baseSubMesh ); |
121 | | |
122 | | /** Creates 2 TEXCOORD semantics that will be used to sample the vertex texture */ |
123 | | virtual void createVertexSemantics( VertexData *thisVertexData, VertexData *baseVertexData, |
124 | | const HWBoneIdxVec &hwBoneIdx, const HWBoneWgtVec &hwBoneWgt) = 0; |
125 | | |
126 | | size_t convert3x4MatricesToDualQuaternions(Matrix3x4f* matrices, size_t numOfMatrices, float* outDualQuaternions); |
127 | | |
128 | | /** Keeps filling the VTF with world matrix data */ |
129 | | void updateVertexTexture(void); |
130 | | |
131 | | /** Affects VTF texture's width dimension */ |
132 | | virtual bool matricesTogetherPerRow() const = 0; |
133 | | |
134 | | /** update the lookup numbers for entities with shared transforms */ |
135 | | virtual void updateSharedLookupIndexes(); |
136 | | |
137 | | /** @see InstanceBatch::generateInstancedEntity() */ |
138 | | InstancedEntity* generateInstancedEntity(size_t num) override; |
139 | | |
140 | | public: |
141 | | BaseInstanceBatchVTF( InstanceManager *creator, MeshPtr &meshReference, const MaterialPtr &material, |
142 | | size_t instancesPerBatch, const Mesh::IndexMap *indexToBoneMap, |
143 | | const String &batchName); |
144 | | virtual ~BaseInstanceBatchVTF(); |
145 | | |
146 | | /** @see InstanceBatch::buildFrom */ |
147 | | void buildFrom( const SubMesh *baseSubMesh, const RenderOperation &renderOperation ) override; |
148 | | |
149 | | //Renderable overloads |
150 | | void getWorldTransforms( Matrix4* xform ) const override; |
151 | | |
152 | | /** Overloaded to be able to updated the vertex texture */ |
153 | | void _updateRenderQueue(RenderQueue* queue) override; |
154 | | |
155 | | /** Sets the state of the usage of bone matrix lookup |
156 | | |
157 | | Under default condition each instance entity is assigned a specific area in the vertex |
158 | | texture for bone matrix data. When turned on the amount of area in the vertex texture |
159 | | assigned for bone matrix data will be relative to the amount of unique animation states. |
160 | | Instanced entities sharing the same animation state will share the same area in the matrix. |
161 | | The specific position of each entity is placed in the vertex data and added in a second phase |
162 | | in the shader. |
163 | | |
164 | | Note this feature only works in VTF_HW for now. |
165 | | This value needs to be set before adding any instanced entities |
166 | | */ |
167 | 0 | void setBoneMatrixLookup(bool enable, size_t maxLookupTableInstances) { assert(mInstancedEntities.empty()); |
168 | 0 | mUseBoneMatrixLookup = enable; mMaxLookupTableInstances = maxLookupTableInstances; } |
169 | | |
170 | | /** Tells whether to use bone matrix lookup |
171 | | @see setBoneMatrixLookup() |
172 | | */ |
173 | 0 | bool useBoneMatrixLookup() const { return mUseBoneMatrixLookup; } |
174 | | |
175 | 0 | void setBoneDualQuaternions(bool enable) { assert(mInstancedEntities.empty()); |
176 | 0 | mUseBoneDualQuaternions = enable; mRowLength = (mUseBoneDualQuaternions ? 2 : 3); } |
177 | | |
178 | 0 | bool useBoneDualQuaternions() const { return mUseBoneDualQuaternions; } |
179 | | |
180 | 0 | void setForceOneWeight(bool enable) { assert(mInstancedEntities.empty()); |
181 | 0 | mForceOneWeight = enable; } |
182 | | |
183 | 0 | bool forceOneWeight() const { return mForceOneWeight; } |
184 | | |
185 | 0 | void setUseOneWeight(bool enable) { assert(mInstancedEntities.empty()); |
186 | 0 | mUseOneWeight = enable; } |
187 | | |
188 | 0 | bool useOneWeight() const { return mUseOneWeight; } |
189 | | |
190 | | /** @see InstanceBatch::useBoneWorldMatrices() */ |
191 | 0 | bool useBoneWorldMatrices() const override { return !mUseBoneMatrixLookup; } |
192 | | |
193 | | /** @return the maximum amount of shared transform entities when using lookup table*/ |
194 | 0 | virtual size_t getMaxLookupTableInstances() const { return mMaxLookupTableInstances; } |
195 | | |
196 | | }; |
197 | | |
198 | | class _OgreExport InstanceBatchVTF : public BaseInstanceBatchVTF |
199 | | { |
200 | | |
201 | | void setupVertices( const SubMesh* baseSubMesh ) override; |
202 | | void setupIndices( const SubMesh* baseSubMesh ) override; |
203 | | |
204 | | /** Creates 2 TEXCOORD semantics that will be used to sample the vertex texture */ |
205 | | void createVertexSemantics( VertexData *thisVertexData, VertexData *baseVertexData, |
206 | | const HWBoneIdxVec &hwBoneIdx, const HWBoneWgtVec &hwBoneWgt ) override; |
207 | | |
208 | 0 | bool matricesTogetherPerRow() const override { return false; } |
209 | | public: |
210 | | InstanceBatchVTF( InstanceManager *creator, MeshPtr &meshReference, const MaterialPtr &material, |
211 | | size_t instancesPerBatch, const Mesh::IndexMap *indexToBoneMap, |
212 | | const String &batchName); |
213 | | virtual ~InstanceBatchVTF(); |
214 | | |
215 | | /** @see InstanceBatch::calculateMaxNumInstances */ |
216 | | size_t calculateMaxNumInstances( const SubMesh *baseSubMesh, uint16 flags ) const override; |
217 | | }; |
218 | | } |
219 | | |
220 | | #include "OgreHeaderSuffix.h" |
221 | | |
222 | | #endif |