SHOW:
|
|
- or go back to the newest paste.
1 | #ifdef _MSC_VER | |
2 | // We'll also define this to stop MSVC complaining about sprintf(). | |
3 | #define _CRT_SECURE_NO_WARNINGS | |
4 | #pragma comment(lib, "Irrlicht_d.lib") | |
5 | - | float4x4 viewProjection; |
5 | + | #endif |
6 | ||
7 | - | struct VS_INPUT |
7 | + | #include <irrlicht.h> |
8 | #include <driverChoice.h> | |
9 | - | float4 vPosition: POSITION; |
9 | + | |
10 | - | float3 vNormal : NORMAL; |
10 | + | using namespace irr; |
11 | - | float4 color : COLOR; |
11 | + | |
12 | - | float2 texCoord : TEXCOORD0; |
12 | + | using namespace core; |
13 | - | float4 W0 : TEXCOORD1; |
13 | + | using namespace scene; |
14 | - | float4 W1 : TEXCOORD2; |
14 | + | using namespace video; |
15 | - | float4 W2 : TEXCOORD3; |
15 | + | using namespace io; |
16 | - | float4 W3 : TEXCOORD4; |
16 | + | using namespace gui; |
17 | - | //float4 Stemp : TEXCOORD5; |
17 | + | |
18 | struct StarInst | |
19 | { | |
20 | irr::core::matrix4 Transformation; | |
21 | - | struct VS_OUTPUT |
21 | + | //irr::f32 Temperature; |
22 | //irr::f32 Temperature1; | |
23 | - | float4 Position :POSITION; // vertex position |
23 | + | //irr::f32 Temperature2; |
24 | - | float2 tcoord : TEXCOORD1; |
24 | + | //irr::f32 Temperature3; |
25 | bool operator==(const StarInst &other) const | |
26 | { | |
27 | - | VS_OUTPUT vsmain(VS_INPUT Inputs) |
27 | + | if ((this->Transformation == other.Transformation) /*&& (this->Temperature == other.Temperature)*/) |
28 | return true; | |
29 | - | VS_OUTPUT tout; |
29 | + | |
30 | - | float4x4 transformation = float4x4(Inputs.W0, Inputs.W1, Inputs.W2, Inputs.W3); |
30 | + | |
31 | - | float4 pos = mul(Inputs.vPosition, transformation); |
31 | + | return false; |
32 | - | tout.Position = mul(pos, viewProjection); |
32 | + | } |
33 | - | tout.tcoord = Inputs.texCoord; |
33 | + | |
34 | ||
35 | - | return tout; |
35 | + | |
36 | - | } |
36 | + | class ShaderCB : public video::IShaderConstantSetCallBack |
37 | { | |
38 | - | Texture2D tex1 : register(t0); |
38 | + | public: |
39 | - | //TODO find out why only s1 works and not s0? |
39 | + | ShaderCB(irr::video::E_DRIVER_TYPE currentdriver) |
40 | - | SamplerState sampler1 : register(s1); |
40 | + | : firstUpdate(true) |
41 | { | |
42 | - | float4 psmain(VS_OUTPUT input) : SV_Target |
42 | + | Currentdriver = currentdriver; |
43 | } | |
44 | - | return tex1.Sample(sampler1, input.tcoord); |
44 | + | |
45 | void OnSetConstants(video::IMaterialRendererServices* services, s32 userData) | |
46 | { | |
47 | if (firstUpdate) | |
48 | { | |
49 | viewProjectionId = services->getVertexShaderConstantID("viewProjection"); | |
50 | firstUpdate = false; | |
51 | } | |
52 | ||
53 | core::matrix4 viewProjection; | |
54 | viewProjection = services->getVideoDriver()->getTransform(video::ETS_PROJECTION); | |
55 | viewProjection *= services->getVideoDriver()->getTransform(video::ETS_VIEW); | |
56 | services->setVertexShaderConstant(viewProjectionId, viewProjection.pointer(), 16); | |
57 | ||
58 | //setPixelShaderConstant | |
59 | } | |
60 | ||
61 | private: | |
62 | irr::video::E_DRIVER_TYPE Currentdriver; | |
63 | bool firstUpdate; | |
64 | ||
65 | s32 viewProjectionId; | |
66 | }; | |
67 | ||
68 | class InstanceManager : public scene::ISceneNode | |
69 | { | |
70 | ||
71 | /* | |
72 | First, we declare some member variables: | |
73 | The Node array, the mesh buffer, the mesh and the material instanced scenenode | |
74 | we also need to keep track of the shader callback. | |
75 | */ | |
76 | video::SMaterial Material; | |
77 | IMeshBuffer* bBuffer; | |
78 | IMesh* aMesh; | |
79 | ShaderCB* callback; | |
80 | /*Variable to handle shader instancing*/ | |
81 | IMesh* bMesh; | |
82 | bool fakeinstancing; | |
83 | //CMeshBuffer dupBuffer; | |
84 | /* | |
85 | We treat the instance manager as a scene node so we don't really have to care about it in the future | |
86 | */ | |
87 | core::aabbox3d<f32> mbb; | |
88 | public: | |
89 | ||
90 | InstanceManager(scene::ISceneNode* parent, scene::ISceneManager* mgr, s32 id, bool Fakeinstancing) | |
91 | : scene::ISceneNode(parent, mgr, id)//, dupBuffer( irr::video::E_INDEX_TYPE::EIT_16BIT) | |
92 | { | |
93 | fakeinstancing = false; | |
94 | ||
95 | //lodused =0; | |
96 | ||
97 | ||
98 | //scene::ISceneNode* bg= mgr->addCubeSceneNode(50000,0,ID_IsNotPickable); | |
99 | //bg->setMaterialFlag(irr::video::E_MATERIAL_FLAG::EMF_LIGHTING,false); | |
100 | //bg->setMaterialFlag(irr::video::E_MATERIAL_FLAG::EMF_BACK_FACE_CULLING,false); | |
101 | ||
102 | //shader | |
103 | s32 mtrlShader = -1; | |
104 | ||
105 | callback = new ShaderCB(mgr->getVideoDriver()->getDriverType()); | |
106 | ||
107 | if (mgr->getVideoDriver()->getDriverType() == EDT_OPENGL) | |
108 | mtrlShader = SceneManager->getVideoDriver()->getGPUProgrammingServices()->addHighLevelShaderMaterialFromFiles("media/shaders/instancing.vert", "", video::EVST_VS_2_0, | |
109 | "media/shaders/instancing.frag", "", video::EPST_PS_2_0, callback, video::EMT_SOLID); | |
110 | else if (mgr->getVideoDriver()->getDriverType() == EDT_DIRECT3D9) | |
111 | mtrlShader = SceneManager->getVideoDriver()->getGPUProgrammingServices()->addHighLevelShaderMaterialFromFiles("../../media/InstancingFVF.hlsl", "vsmain", video::EVST_VS_3_0, | |
112 | "../../media/InstancingFVF.hlsl", "psmain", video::EPST_PS_3_0, callback, video::EMT_SOLID); | |
113 | else if (mgr->getVideoDriver()->getDriverType() == EDT_DIRECT3D11) | |
114 | mtrlShader = SceneManager->getVideoDriver()->getGPUProgrammingServices()->addHighLevelShaderMaterialFromFiles("../../media/InstancingFVF.hlsl", "vsmain", video::EVST_VS_4_0, | |
115 | "../../media/InstancingFVF.hlsl", "psmain", video::EPST_PS_4_0, callback, video::EMT_SOLID); | |
116 | ||
117 | callback->drop(); | |
118 | ||
119 | aMesh = SceneManager->getGeometryCreator()->createSphereMesh(2); | |
120 | Material.Lighting = false; | |
121 | Material.setTexture(0, SceneManager->getVideoDriver()->getTexture("../../media/wall.jpg")); | |
122 | Material.MaterialType = (video::E_MATERIAL_TYPE)mtrlShader; | |
123 | //Material.BackfaceCulling = false; | |
124 | ||
125 | IVertexDescriptor* index = mgr->getVideoDriver()->getVertexDescriptor("BaseInstanceIndex"); | |
126 | ||
127 | if (!index) | |
128 | { | |
129 | IVertexDescriptor* stdv = mgr->getVideoDriver()->getVertexDescriptor(0); | |
130 | index = mgr->getVideoDriver()->addVertexDescriptor("BaseInstanceIndex"); | |
131 | ||
132 | for (u32 i = 0; i < stdv->getAttributeCount(); i++) | |
133 | { | |
134 | index->addAttribute(stdv->getAttribute(i)->getName(), stdv->getAttribute(i)->getElementCount(), stdv->getAttribute(i)->getSemantic(), stdv->getAttribute(i)->getType(), 0); | |
135 | } | |
136 | ||
137 | index->addAttribute("InstancingIndex1", 4, EVAS_TEXCOORD1, EVAT_FLOAT, 1); | |
138 | index->addAttribute("InstancingIndex2", 4, EVAS_TEXCOORD2, EVAT_FLOAT, 1); | |
139 | index->addAttribute("InstancingIndex3", 4, EVAS_TEXCOORD3, EVAT_FLOAT, 1); | |
140 | index->addAttribute("InstancingIndex4", 4, EVAS_TEXCOORD4, EVAT_FLOAT, 1); | |
141 | //index->addAttribute("InstancingIndex5", 4, EVAS_TEXCOORD5, EVAT_FLOAT, 1); | |
142 | } | |
143 | ||
144 | //dupBuffer.SetvertexDescriptor(Instanced2tcoords); | |
145 | IVertexBuffer* InstanceIndex = new CVertexBuffer<StarInst>(index); | |
146 | ||
147 | bBuffer = aMesh->getMeshBuffer(0); | |
148 | ||
149 | mgr->getVideoDriver()->setMinHardwareBufferVertexCount(0); | |
150 | bBuffer->setHardwareMappingHint(scene::EHM_STATIC); | |
151 | bBuffer->getVertexBuffer()->setVertexDescriptor(index); | |
152 | InstanceIndex->setHardwareMappingHint(scene::EHM_DYNAMIC); | |
153 | bBuffer->addVertexBuffer(InstanceIndex); | |
154 | ||
155 | InstanceIndex->drop(); | |
156 | } | |
157 | ||
158 | /*The node array is put here to be public only for the purpose of the demo in the future a function coud take care of this without having it public*/ | |
159 | ||
160 | core::array<ISceneNode*> totalNodeArray; | |
161 | ||
162 | ||
163 | /*Create an empty scenenode and return the pointer to the user | |
164 | this empty scene node is used for irrlicht and the user to manage the instance | |
165 | Each instance can be manipulated individualy through thier own empty scenenode*/ | |
166 | ISceneNode* AddInstance(vector3df pos, f32 scale, vector3df rotation) | |
167 | { | |
168 | ISceneNode* empty = SceneManager->addEmptySceneNode(); | |
169 | //empty->grab(); | |
170 | //empty->setParent(NULL); | |
171 | empty->setPosition(pos); | |
172 | empty->setScale(vector3df(scale)); | |
173 | empty->setRotation(rotation); | |
174 | totalNodeArray.push_back(empty); | |
175 | return empty; | |
176 | } | |
177 | /* | |
178 | we always register this for rendering since visibility is handeled in the sub node | |
179 | */ | |
180 | virtual void OnRegisterSceneNode() | |
181 | { | |
182 | SceneManager->registerNodeForRendering(this); | |
183 | ||
184 | ISceneNode::OnRegisterSceneNode(); | |
185 | } | |
186 | ||
187 | /* | |
188 | In the render() method most of the interesting stuff happens: The manager goes through the node array and upload thier matrices to the shader callback | |
189 | In OpenGL we render per batches of 248 and in dx per batches of 62 this is due to the amount of variable register availible being diferent in both drivers | |
190 | in the future if a vertex texture patch is accepted both could be made to render every node in a single draw call and fetch thier matrices from a texture | |
191 | */ | |
192 | virtual void OnAnimate(u32 timeMs) | |
193 | { | |
194 | ISceneNode::OnAnimate(timeMs); | |
195 | ||
196 | bBuffer->getVertexBuffer(1)->clear(); | |
197 | mbb.reset(0,0,0); | |
198 | ||
199 | const SViewFrustum* frust = SceneManager->getActiveCamera()->getViewFrustum(); | |
200 | for (u32 i = 0; i<totalNodeArray.size(); i++) | |
201 | { | |
202 | //totalNodeArray[i]->OnAnimate(timeMs); | |
203 | bool cliped = false; | |
204 | for (s32 e = 0; e<scene::SViewFrustum::VF_PLANE_COUNT; ++e) | |
205 | if ((frust->planes[e].classifyPointRelation(totalNodeArray[i]->getAbsolutePosition())) == core::EIntersectionRelation3D::ISREL3D_FRONT) | |
206 | { | |
207 | // cliped = true; | |
208 | break; | |
209 | } | |
210 | if (!cliped) | |
211 | { | |
212 | StarInst currinst; | |
213 | currinst.Transformation = totalNodeArray[i]->getAbsoluteTransformation(); | |
214 | bBuffer->getVertexBuffer(1)->addVertex(&currinst); | |
215 | mbb.addInternalPoint(totalNodeArray[i]->getAbsolutePosition()); | |
216 | } | |
217 | } | |
218 | bBuffer->getVertexBuffer(1)->setDirty(); | |
219 | ||
220 | // std::cout<<bBuffer->getVertexBuffer(1)->getVertexCount()<<std::endl; | |
221 | } | |
222 | ||
223 | virtual void render() | |
224 | { | |
225 | SceneManager->getVideoDriver()->setTransform(video::ETS_WORLD, AbsoluteTransformation); | |
226 | SceneManager->getVideoDriver()->setMaterial(Material); | |
227 | int nRemainingBoxes = totalNodeArray.size(); | |
228 | ||
229 | ||
230 | // if (fakeinstancing == false) | |
231 | ||
232 | SceneManager->getVideoDriver()->drawInstancedMeshBuffer(bBuffer); | |
233 | ||
234 | video::SMaterial m; | |
235 | m.Lighting = false; | |
236 | SceneManager->getVideoDriver()->setMaterial(m); | |
237 | ||
238 | for (u32 i = 0; i < totalNodeArray.size(); ++i) | |
239 | { | |
240 | core::aabbox3df box = aMesh->getBoundingBox(); | |
241 | totalNodeArray[i]->getAbsoluteTransformation().transformBoxEx(box); | |
242 | SceneManager->getVideoDriver()->draw3DBox( box, video::SColor(255, 255, 255, 255)); | |
243 | } | |
244 | ||
245 | SceneManager->getVideoDriver()->draw3DBox(mbb, video::SColor(255, 255, 255, 255)); | |
246 | // else | |
247 | // SceneManager->getVideoDriver()->drawMeshBuffer(&dupBuffer); | |
248 | ||
249 | } | |
250 | ||
251 | /* | |
252 | Here we return the bounding box for the whole instance batch to make sure the node does not get culled wen there is still even a single instance in the view fulstrum | |
253 | */ | |
254 | ||
255 | virtual const core::aabbox3d<f32>& getBoundingBox() const | |
256 | { | |
257 | return mbb; | |
258 | } | |
259 | ||
260 | virtual u32 getMaterialCount() const | |
261 | { | |
262 | return 1; | |
263 | } | |
264 | ||
265 | virtual video::SMaterial& getMaterial(u32 i) | |
266 | { | |
267 | return Material; | |
268 | } | |
269 | }; | |
270 | ||
271 | int main() | |
272 | { | |
273 | ||
274 | video::E_DRIVER_TYPE driverType = driverChoiceConsole(); | |
275 | if (driverType == video::EDT_COUNT) | |
276 | return 1; | |
277 | bool usefakeinst = false; | |
278 | bool animate = false; | |
279 | char i; | |
280 | ||
281 | printf("Please press 'y' if you want to use Shader Instancing.\n"); | |
282 | std::cin >> i; | |
283 | if (i == 'y') | |
284 | { | |
285 | usefakeinst = true; | |
286 | } | |
287 | printf("Please press 'y' if you want each instance to be animated.\n"); | |
288 | std::cin >> i; | |
289 | if (i == 'y') | |
290 | { | |
291 | animate = true; | |
292 | } | |
293 | // create device and exit if creation failed | |
294 | ||
295 | IrrlichtDevice * device = createDevice(driverType, core::dimension2d<u32>(800, 600), 32u, false); | |
296 | ||
297 | if (device == 0) | |
298 | return 1; // could not create selected driver. | |
299 | ||
300 | /* The creation was successful, now we set the event receiver and | |
301 | store pointers to the driver and to the gui environment. */ | |
302 | ||
303 | ||
304 | device->setWindowCaption(L"Irrlicht Engine - Hardware Instancing Demo"); | |
305 | ||
306 | video::IVideoDriver* driver = device->getVideoDriver(); | |
307 | scene::ISceneManager* smgr = device->getSceneManager(); | |
308 | IGUIEnvironment* env = device->getGUIEnvironment(); | |
309 | InstanceManager* InstancingTest = new InstanceManager(smgr->getRootSceneNode(), smgr, -1, usefakeinst); | |
310 | ||
311 | //!save transformation in one EmptySceneNode which doesn't render itself | |
312 | f32 scale = 1.5f; | |
313 | for (f32 i = 0; i<5; i++) | |
314 | for (f32 j = 1; j<5; j++) | |
315 | for (f32 k = 0; k<10; k++) | |
316 | { | |
317 | ||
318 | scene::ISceneNode* empty = InstancingTest->AddInstance(vector3df(i*scale, j*scale, k*scale), scale, vector3df(rand() % 360, rand() % 360, rand() % 360)); | |
319 | if (animate) | |
320 | { | |
321 | scene::ISceneNodeAnimator* anim = | |
322 | smgr->createFlyCircleAnimator(vector3df(i*scale, j*scale, k*scale), rand() / 20, rand()*0.0000001); | |
323 | if (anim) | |
324 | { | |
325 | empty->addAnimator(anim); | |
326 | anim->drop(); | |
327 | } | |
328 | } | |
329 | ||
330 | } | |
331 | ||
332 | scene::ICameraSceneNode* cam = smgr->addCameraSceneNodeFPS(); | |
333 | cam->setFarValue(2000); | |
334 | ||
335 | device->getCursorControl()->setVisible(false); | |
336 | ||
337 | InstancingTest->drop(); | |
338 | ||
339 | s32 lastFPS = -1; | |
340 | while (device->run()) | |
341 | { | |
342 | if (device->isWindowActive()) | |
343 | { | |
344 | driver->beginScene(true, true, SColor(255, 122, 122, 122)); | |
345 | ||
346 | smgr->drawAll(); | |
347 | env->drawAll(); | |
348 | ||
349 | driver->endScene(); | |
350 | ||
351 | int fps = driver->getFPS(); | |
352 | ||
353 | if (lastFPS != fps) | |
354 | { | |
355 | core::stringw str = L"fps: "; | |
356 | str += fps; | |
357 | str += ", poly: "; | |
358 | str += driver->getPrimitiveCountDrawn(); | |
359 | str += ", Node count:"; | |
360 | str += InstancingTest->totalNodeArray.size(); | |
361 | device->setWindowCaption(str.c_str()); | |
362 | lastFPS = fps; | |
363 | } | |
364 | } | |
365 | } | |
366 | ||
367 | device->drop(); | |
368 | ||
369 | return 0; | |
370 | } |