Code: Select all
#ifdef _MSC_VER
// We'll also define this to stop MSVC complaining about sprintf().
#define _CRT_SECURE_NO_WARNINGS
#pragma comment(lib, "Irrlicht.lib")
#endif
#include <irrlicht.h>
#include <driverChoice.h>
struct StarInst
{
irr::core::matrix4 Transformation;
irr::f32 Temperature;
irr::f32 Temperature1;
irr::f32 Temperature2;
irr::f32 Temperature3;
bool operator==(const StarInst &other) const
{
if((this->Transformation == other.Transformation)&&(this->Temperature == other.Temperature))
return true;
return false;
}
};
using namespace irr;
using namespace core;
using namespace scene;
using namespace video;
using namespace io;
using namespace gui;
struct ShaderCB : public video::IShaderConstantSetCallBack
{
ShaderCB(irr::video::E_DRIVER_TYPE currentdriver);
void OnSetConstants(video::IMaterialRendererServices* services,
s32 userData);
irr::video::E_DRIVER_TYPE Currentdriver;
};
void ShaderCB::OnSetConstants(video::IMaterialRendererServices* services,
s32 userData)
{
core::matrix4 viewProjection;
viewProjection = services->getVideoDriver()->getTransform(video::ETS_PROJECTION);
viewProjection *= services->getVideoDriver()->getTransform(video::ETS_VIEW);
services->setVertexShaderConstant("viewProjection", viewProjection.pointer(), 16);
//setPixelShaderConstant
}
ShaderCB::ShaderCB(irr::video::E_DRIVER_TYPE currentdriver)
{
Currentdriver=currentdriver;
}
class InstanceManager : public scene::ISceneNode
{
/*
First, we declare some member variables:
The Node array, the mesh buffer, the mesh and the material instanced scenenode
we also need to keep track of the shader callback.
*/
video::SMaterial Material;
IMeshBuffer* bBuffer;
IMesh* aMesh;
ShaderCB* callback;
/*Variable to handle shader instancing*/
IMesh* bMesh;
bool fakeinstancing;
//CMeshBuffer dupBuffer;
/*
We treat the instance manager as a scene node so we don't really have to care about it in the future
*/
core::aabbox3d<f32> mbb;
public:
InstanceManager(scene::ISceneNode* parent, scene::ISceneManager* mgr, s32 id, bool Fakeinstancing)
: scene::ISceneNode(parent, mgr, id)//, dupBuffer( irr::video::E_INDEX_TYPE::EIT_16BIT)
{
fakeinstancing = false;
//lodused =0;
//scene::ISceneNode* bg= mgr->addCubeSceneNode(50000,0,ID_IsNotPickable);
//bg->setMaterialFlag(irr::video::E_MATERIAL_FLAG::EMF_LIGHTING,false);
//bg->setMaterialFlag(irr::video::E_MATERIAL_FLAG::EMF_BACK_FACE_CULLING,false);
//shader
s32 mtrlShader,mtrlShader2;
callback = new ShaderCB(mgr->getVideoDriver()->getDriverType());
if (mgr->getVideoDriver()->getDriverType() == EDT_OPENGL)
mtrlShader = SceneManager->getVideoDriver()->getGPUProgrammingServices()->addHighLevelShaderMaterialFromFiles("media/shaders/instancing.vert", "", video::EVST_VS_2_0,
"media/shaders/instancing.frag", "", video::EPST_PS_2_0,callback, video::EMT_SOLID);
else if (mgr->getVideoDriver()->getDriverType() == EDT_DIRECT3D9)
mtrlShader = SceneManager->getVideoDriver()->getGPUProgrammingServices()->addHighLevelShaderMaterialFromFiles("../../media/InstancingFVF.hlsl", "vsmain", video::EVST_VS_3_0,
"../../media/InstancingFVF.hlsl", "psmain", video::EPST_PS_3_0,callback, video::EMT_SOLID);
else if (mgr->getVideoDriver()->getDriverType() == EDT_DIRECT3D11)
mtrlShader = SceneManager->getVideoDriver()->getGPUProgrammingServices()->addHighLevelShaderMaterialFromFiles("media/shaders/InstancingFVF.hlsl", "vsmain", video::EVST_VS_4_0,
"media/shaders/InstancingFVF.hlsl", "psmain", video::EPST_PS_4_0,callback, video::EMT_SOLID);
callback->drop();
mbb.addInternalPoint(5000*2,5000*2,5000*2);
mbb.addInternalPoint(-5000*2,-5000*2,-5000*2);
aMesh = SceneManager->getGeometryCreator()->createSphereMesh(0.5,8,8);
Material.Lighting = false;
Material.setTexture(0, SceneManager->getVideoDriver()->getTexture("../../media/wall.jpg"));
Material.MaterialType = (video::E_MATERIAL_TYPE)mtrlShader;
//Material.BackfaceCulling = false;
IVertexDescriptor* index = mgr->getVideoDriver()->getVertexDescriptor("BaseInstanceIndex");
if(!index)
{
IVertexDescriptor* stdv = mgr->getVideoDriver()->getVertexDescriptor(0);
mgr->getVideoDriver()->addVertexDescriptor("BaseInstanceIndex");
index = mgr->getVideoDriver()->getVertexDescriptor("BaseInstanceIndex");
for (int i = 0; i < stdv->getAttributeCount(); i++)
{
index->addAttribute(stdv->getAttribute(i)->getName(), stdv->getAttribute(i)->getElementCount(), stdv->getAttribute(i)->getSemantic(), stdv->getAttribute(i)->getType(), 0);
}
index->addAttribute("InstancingIndex1",4,EVAS_TEXCOORD1,EVAT_FLOAT,1);
index->addAttribute("InstancingIndex2",4,EVAS_TEXCOORD2,EVAT_FLOAT,1);
index->addAttribute("InstancingIndex3",4,EVAS_TEXCOORD3,EVAT_FLOAT,1);
index->addAttribute("InstancingIndex4",4,EVAS_TEXCOORD4,EVAT_FLOAT,1);
index->addAttribute("InstancingIndex5",4,EVAS_TEXCOORD5,EVAT_FLOAT,1);
}
//dupBuffer.SetvertexDescriptor(Instanced2tcoords);
IVertexBuffer* InscanceIndex = new CVertexBuffer<StarInst>(index);
bBuffer = aMesh->getMeshBuffer(0);
bBuffer->getVertexBuffer(0)->setVertexDescriptor(index);
mgr->getVideoDriver()->setMinHardwareBufferVertexCount(bBuffer->getVertexBuffer()->getVertexCount()-1);
bBuffer->setHardwareMappingHint(scene::EHM_STATIC);
InscanceIndex->setHardwareMappingHint(scene::EHM_DYNAMIC);
bBuffer->setHardwareMappingHint(EHM_STATIC);
bBuffer->addVertexBuffer(InscanceIndex);
bBuffer->getVertexBuffer(0)->setHardwareMappingHint(EHM_STATIC);
bBuffer->getVertexBuffer(1)->setDirty();
/*
IMesh* bMesh = mgr->getMeshManipulator()->createMeshWith2TCoords(aMesh);
IMeshBuffer* cBuffer = bMesh->getMeshBuffer(0);
//!create dupBuffer with bBuffer repeated NUM_BATCH_INSTANCES times
/*
if (mgr->getVideoDriver()->getDriverType() == EDT_OPENGL)
for (int k=0;k<248;k++)
{
S3DVertex2TCoords* verts = (S3DVertex2TCoords*)cBuffer->getVertices();
for (u32 i=0; i<bBuffer->getVertexCount(); i++)
{
verts[i].TCoords2.X = k;//assign the index of instance that each vertex belongs to
}
dupBuffer.append(verts,bBuffer->getVertexCount(),cBuffer->getIndices(),bBuffer->getIndexCount());
dupBuffer.setHardwareMappingHint(scene::EHM_STATIC);
}
else if (mgr->getVideoDriver()->getDriverType() == EDT_DIRECT3D9)
{
for (int k=0;k<62;k++)
{
S3DVertex2TCoords* verts = (S3DVertex2TCoords*)cBuffer->getVertices();
for (u32 i=0; i<bBuffer->getVertexCount(); i++)
{
verts[i].TCoords2.X = k;//assign the index of instance that each vertex belongs to
}
dupBuffer.append(verts,bBuffer->getVertexCount(),cBuffer->getIndices(),bBuffer->getIndexCount());
dupBuffer.setHardwareMappingHint(scene::EHM_STATIC);
}
}
else if(mgr->getVideoDriver()->getDriverType() == EDT_DIRECT3D11)
{
for (int k=0;k<62;k++)
{
S3DVertex2TCoords* verts = (S3DVertex2TCoords*)cBuffer->getVertices();
for (u32 i=0; i<bBuffer->getVertexCount(); i++)
{
verts[i].TCoords2.X = k;//assign the index of instance that each vertex belongs to
}
dupBuffer.append(verts,bBuffer->getVertexCount(),cBuffer->getIndices(),bBuffer->getIndexCount());
dupBuffer.setHardwareMappingHint(scene::EHM_STATIC);
}
}
*/
}
/*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*/
core::array<ISceneNode*> totalNodeArray;
/*Create an empty scenenode and return the pointer to the user
this empty scene node is used for irrlicht and the user to manage the instance
Each instance can be manipulated individualy through thier own empty scenenode*/
ISceneNode* AddInstance(vector3df pos, f32 scale,vector3df Rotation )
{
ISceneNode* empty = SceneManager->addEmptySceneNode();
empty->setPosition(pos);
empty->setScale(vector3df(scale));
empty->setRotation(Rotation);
totalNodeArray.push_back(empty);
return empty;
}
/*
we always register this for rendering since visibility is handeled in the sub node
*/
virtual void OnRegisterSceneNode()
{
SceneManager->registerNodeForRendering(this);
ISceneNode::OnRegisterSceneNode();
}
/*
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
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
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
*/
virtual void OnAnimate(u32 timeMs)
{
//ISceneNode::OnAnimate(timeMs);
bBuffer->getVertexBuffer(1)->clear();
const SViewFrustum* frust = SceneManager->getActiveCamera()->getViewFrustum();
for (int i=0;i<totalNodeArray.size(); i++)
{
int cliped=0;
for (s32 e=0; e<scene::SViewFrustum::VF_PLANE_COUNT; ++e)
if((frust->planes[e].classifyPointRelation(totalNodeArray[i]->getAbsolutePosition())) == core::EIntersectionRelation3D::ISREL3D_FRONT)
{
// cliped =1;
break;
}
if(cliped ==false)
{
StarInst currinst;
currinst.Transformation= totalNodeArray[i]->getAbsoluteTransformation();
bBuffer->getVertexBuffer(1)->addVertex(&currinst);
mbb.addInternalPoint(totalNodeArray[i]->getAbsolutePosition());
}
}
bBuffer->getVertexBuffer(1)->setDirty();
// std::cout<<bBuffer->getVertexBuffer(1)->getVertexCount()<<std::endl;
}
virtual void render()
{
SceneManager->getVideoDriver()->setMaterial(Material);
int nRemainingBoxes = totalNodeArray.size();
// if (fakeinstancing == false)
SceneManager->getVideoDriver()->drawInstancedMeshBuffer(bBuffer);
// else
// SceneManager->getVideoDriver()->drawMeshBuffer(&dupBuffer);
}
/*
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
*/
virtual const core::aabbox3d<f32>& getBoundingBox() const
{
return mbb;
}
virtual u32 getMaterialCount() const
{
return 1;
}
virtual video::SMaterial& getMaterial(u32 i)
{
return Material;
}
};
bool initIrrlicht(s32 w, s32 h, bool opengl = true, s32 bpp=32, bool fullscreen=false, bool stentil = false);
int main()
{
video::E_DRIVER_TYPE driverType=driverChoiceConsole();
if (driverType==video::EDT_COUNT)
return 1;
bool usefakeinst = false;
bool animate = false;
char i;
printf("Please press 'y' if you want to use Shader Instancing.\n");
std::cin >> i;
if (i == 'y')
{
usefakeinst = true;
}
printf("Please press 'y' if you want each instance to be animated.\n");
std::cin >> i;
if (i == 'y')
{
animate = true;
}
// create device and exit if creation failed
IrrlichtDevice * device = createDevice(driverType, core::dimension2d<u32>(800, 600),32u,false);
if (device == 0)
return 1; // could not create selected driver.
/* The creation was successful, now we set the event receiver and
store pointers to the driver and to the gui environment. */
device->setWindowCaption(L"Irrlicht Engine - Hardware Instancing Demo");
video::IVideoDriver* driver = device->getVideoDriver();
scene::ISceneManager* smgr = device->getSceneManager();
IGUIEnvironment* env = device->getGUIEnvironment();
InstanceManager* InstancingTest = new InstanceManager(smgr->getRootSceneNode(),smgr,-1,usefakeinst);
//!save transformation in one EmptySceneNode which doesn't render itself
f32 scale = 1.5f;
for (u32 i=0;i<20;i++)
for (u32 j=1;j<40;j++)
for (u32 k=0;k<20;k++)
{
scene::ISceneNode* empty = InstancingTest->AddInstance(vector3df(i*scale,j*scale,k*scale),scale,vector3df(rand()%360,rand()%360,rand()%360));
if (animate== true)
{
scene::ISceneNodeAnimator* anim =
smgr->createFlyCircleAnimator(vector3df(i*scale,j*scale,k*scale),rand()/20,rand()*0.0000001);
if (anim)
{
empty->addAnimator(anim);
anim->drop();
}
}
}
smgr->addCubeSceneNode();
scene::ICameraSceneNode* cam = smgr->addCameraSceneNodeFPS();
cam->setFarValue(2000);
device->getCursorControl()->setVisible(false);
s32 lastFPS = -1;
while(device->run())
{
if (device->isWindowActive())
{
driver->beginScene(true, true, SColor(255,122,122,122));
smgr->drawAll();
{
}
env->drawAll();
driver->endScene();
int fps = driver->getFPS();
if (lastFPS != fps)
{
core::stringw str = L"fps: ";
str += fps;
str += ", poly: ";
str += driver->getPrimitiveCountDrawn();
str += ", Node count:";
str += InstancingTest->totalNodeArray.size();
device->setWindowCaption(str.c_str());
lastFPS = fps;
}
}
}
device->drop();
return 0;
}
I have not yet found why but I have the very same code running inside my project and there it's working