View difference between Paste ID: 678ha0mA and ujsqyeqs
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
}