#include <iostream> #include <irrlicht.h> #include "driverChoice.h" using namespace irr; #ifdef _IRR_WINDOWS_ #pragma comment(lib, "irrlicht.lib") //#pragma comment(linker, "/subsystem:windows /ENTRY:mainCRTStartup") #endif IrrlichtDevice* device = 0; bool UseHighLevelShaders = false; //为了传递数据,继承video::IShaderConstantSetCallBack创建一个类 class MyShaderCallBack :public video::IShaderConstantSetCallBack { public: //需要重写唯一的方法 virtual void OnSetConstants( video::IMaterialRendererServices* services, s32 userData) { video::IVideoDriver* driver = services->getVideoDriver(); /** *mInvWorld矩阵,0 *mWorldViewProj矩阵,4 *mLightPos,8 *mLightColor,9 *mTransWorld,10 *都根据状态写两种方法 */ //mInvWorld core::matrix4 invWorld = driver->getTransform(video::ETS_WORLD); invWorld.makeInverse();//求逆? if (UseHighLevelShaders) services->setVertexShaderConstant("mInvWorld", invWorld.pointer(), 16); else services->setVertexShaderConstant(invWorld.pointer(), 0/*寄存器*/, 4/*被设置的寄存器数量,每个寄存器可以存储4个浮点数*/); //clipmatrix core::matrix4 worldViewProj; worldViewProj = driver->getTransform(video::ETS_PROJECTION); worldViewProj *= driver->getTransform(video::ETS_VIEW); worldViewProj *= driver->getTransform(video::ETS_WORLD); if (UseHighLevelShaders) services->setVertexShaderConstant("mWorldViewProj", worldViewProj.pointer(), 16); else services->setVertexShaderConstant(worldViewProj.pointer(), 4, 4); //mlightpos,使用摄像机的坐标 core::vector3df pos = device->getSceneManager()->getActiveCamera()->getAbsolutePosition(); if (UseHighLevelShaders) services->setVertexShaderConstant("mLightPos", reinterpret_cast<f32*>(&pos), 3); else services->setVertexShaderConstant( reinterpret_cast<f32*>(&pos),8, 1); //mlightcol video::SColorf col(0.0f, 1.0f, 1.0f, 0.0f); if (UseHighLevelShaders) services->setVertexShaderConstant("mLightColor", reinterpret_cast<f32*>(&col), 4);//这里之前错了,写错1 else services->setVertexShaderConstant(reinterpret_cast<f32*>(&col),9, 1); //mTransWorld core::matrix4 world = driver->getTransform(video::ETS_WORLD); world = world.getTransposed();//转置,列主? if (UseHighLevelShaders) services->setVertexShaderConstant("mTransWorld", world.pointer(), 16); else services->setVertexShaderConstant(world.pointer(), 10, 4); } }; int main(int argc, char** argv) { video::E_DRIVER_TYPE drivertype = driverChoiceConsole(); if (drivertype == video::EDT_COUNT) return 1; if (drivertype == video::EDT_OPENGL || drivertype == video::EDT_DIRECT3D9) { char i; printf("Please press 'y' if you want to use high level shaders.\n"); std::cin >> i; if (i == 'y') UseHighLevelShaders = true; } device =createDevice(drivertype, core::dimension2d<u32>(720, 455), 32, false, true, false, 0); if (!device) return 1; device->setWindowCaption(L"10shapders"); video::IVideoDriver *driver = device->getVideoDriver(); scene::ISceneManager *smgr = device->getSceneManager(); gui::IGUIEnvironment *guiev = device->getGUIEnvironment(); /** *1.加载 *如果使用Direct3D,加载顶点和像素shader程序, *如果使用OpenGL,加载RGB fragment 和顶点程序 */ io::path vsFileName;//vertex shader io::path psFileName;//pixel shader switch (drivertype) { case video::EDT_DIRECT3D8: { vsFileName = "../media/d3d8.vsh"; psFileName = "../media/d3d8.psh"; } break; case video::EDT_DIRECT3D9: { if (UseHighLevelShaders) { psFileName = "../media/d3d9.hlsl"; vsFileName = psFileName;//放在同一个文件中 } else { vsFileName = "../media/d3d9.vsh"; psFileName = "../media/d3d9.psh"; } } break; case video::EDT_OPENGL: { if (UseHighLevelShaders) { vsFileName = "../media/opengl.vert"; psFileName = "../media/opengl.frag"; } else { vsFileName = "../media/opengl.vsh"; psFileName = "../media/opengl.psh"; } } break; } /** *2.检查硬件是否支持,如果硬件不支持,则设置相应的文件名为0 *用处:当硬件只支持某一种着色器,则仍可以发挥支持的部分的功能 *当建立材质,若不检查,硬件若不能完全支持shader,则不能创建 *反之,仍可以用支持的部分建立 */ if (!driver->queryFeature(video::EVDF_PIXEL_SHADER_1_1) &&//Direct3d像素着色器 !driver->queryFeature(video::EVDF_ARB_FRAGMENT_PROGRAM_1))//opengl片元着色器 { device->getLogger()->log("WARNING:Pixel shaders disabled "\ "because of missing driver/hardware support"); psFileName = ""; } if (!driver->queryFeature(video::EVDF_VERTEX_SHADER_1_1) &&//Direct3d顶点着色器 !driver->queryFeature(video::EVDF_ARB_VERTEX_PROGRAM_1))//opengl顶点着色器 { device->getLogger()->log("WARNING:Vertex shaders disabled "\ "because of missing driver/hardware support"); vsFileName = ""; } /** *3.创建新的材质 *在Irrlicht引擎中材质种类是32位的值,比如:video::EMT_SOLID *获取值:通过IGPUProgrammingServices调用addShaderMaterialFromFiles()获得 *参数介绍: *name 包含shader的文件名 *IShaderConstantSetCallBack类的指针 回调函数,传递参数,不传,设0 *base material 基础材质 * *如果将shader写在string里,可以调用addShaderMaterial() * *这里创建两个不同材质: *固态的:EMT_SOLID,透明的:EMT_TRANSPARENT_ADD_COLOR */ video::IGPUProgrammingServices* gpu = driver->getGPUProgrammingServices(); s32 newMaterialType1 = 0; s32 newMaterialType2 = 0; if (gpu) { //回调函数 MyShaderCallBack* mc = new MyShaderCallBack(); //根据shaders的版本不同,设置 //不同之处在于,高级语言写的shader需要设置入口和编译版本 //高级版本还有几何着色器 if (UseHighLevelShaders) { //有多个重载函数 newMaterialType1 = gpu->addHighLevelShaderMaterialFromFiles( vsFileName,/*vertexShaderProgram*/ "vertexMain",/*vertexShaderEntryPointName,入口,默认main*/ video::EVST_VS_1_1,/*vsCompileTarget*/ psFileName,/*pixelShaderProgram*/ "pixelMain",/*入口*/ video::EPST_PS_1_1,/*psCompileTarget*/ mc, video::EMT_SOLID, 0/*userData*/ ); newMaterialType2 = gpu->addHighLevelShaderMaterialFromFiles( vsFileName,/*vertexShaderProgram*/ "vertexMain",/*vertexShaderEntryPointName,入口,默认main*/ video::EVST_VS_1_1,/*vsCompileTarget*/ psFileName,/*pixelShaderProgram*/ "pixelMain",/*入口*/ video::EPST_PS_1_1,/*psCompileTarget*/ mc, video::EMT_TRANSPARENT_ADD_COLOR, 0/*userData*/); } else { //低级的shader,asm,arb_asm写的 newMaterialType1 = gpu->addShaderMaterialFromFiles( vsFileName, psFileName, mc, video::EMT_SOLID); newMaterialType2 = gpu->addShaderMaterialFromFiles( vsFileName, psFileName, mc, video::EMT_TRANSPARENT_ADD_COLOR); } mc->drop(); } /** *4.测试新材质 *添加了一个立方体,设置不同的材质, *设置一个文本节点显示此立方体所用的材质 *为立方体添加一个场景节点和动画 */ //4.1节点1,使用新材质1 scene::ISceneNode* node = smgr->addCubeSceneNode(50); node->setPosition(core::vector3df(0, 0, 0)); node->setMaterialTexture(0, driver->getTexture("../media/wall.bmp")); node->setMaterialFlag(video::EMF_LIGHTING, false); node->setMaterialType((video::E_MATERIAL_TYPE)newMaterialType1); //添加文本节点 smgr->addTextSceneNode(guiev->getBuiltInFont(), L"PS&VS&EMT_SOLID", video::SColor(255, 255, 255, 255), node); //添加动画 scene::ISceneNodeAnimator* anim = smgr->createRotationAnimator( core::vector3df(0, 0.3f, 0)); node->addAnimator(anim); anim->drop(); //4.2节点2,使用新材质2 node = smgr->addCubeSceneNode(50); node->setPosition(core::vector3df(0, -10, 50)); node->setMaterialTexture(0, driver->getTexture("../media/wall.bmp")); node->setMaterialFlag(video::EMF_LIGHTING, false); node->setMaterialType((video::E_MATERIAL_TYPE)newMaterialType2); //添加文本 smgr->addTextSceneNode(guiev->getBuiltInFont(), L"PS&VS&EMT_TRANSPARENT", video::SColor(255, 255, 255, 255), node); anim = smgr->createRotationAnimator( core::vector3df(0, 0.3f, 0)); node->addAnimator(anim); anim->drop(); //4.3不使用shader node = smgr->addCubeSceneNode(50); node->setPosition(core::vector3df(0, 50, 25)); node->setMaterialTexture(0, driver->getTexture("../media/wall.bmp")); node->setMaterialFlag(video::EMF_LIGHTING, false); smgr->addTextSceneNode(guiev->getBuiltInFont(), L"NOSHADER", video::SColor(255, 255, 255, 255), node); /** *5.添加天空盒子 *先关闭mipmap */ driver->setTextureCreationFlag(video::ETCF_CREATE_MIP_MAPS, false); smgr->addSkyBoxSceneNode( driver->getTexture("../media//irrlicht2_up.jpg"), driver->getTexture("../media//irrlicht2_dn.jpg"), driver->getTexture("../media//irrlicht2_lf.jpg"), driver->getTexture("../media//irrlicht2_rt.jpg"), driver->getTexture("../media//irrlicht2_ft.jpg"), driver->getTexture("../media//irrlicht2_bk.jpg") ); //开启mipmap driver->setTextureCreationFlag(video::ETCF_CREATE_MIP_MAPS, true); // smgr->addCameraSceneNode(0, core::vector3df(0, 30, -40), core::vector3df(0, 5, 0)); smgr->addCameraSceneNodeFPS(); int lastFPS = -1; while (device->run()) { driver->beginScene(true, true, video::SColor(255, 100, 101, 140)); smgr->drawAll(); guiev->drawAll(); driver->endScene(); int fps = driver->getFPS(); if (lastFPS != fps) { core::stringw str = L"Campfire FX example ["; str += driver->getName(); str += "]FPS.", str += fps; device->setWindowCaption(str.c_str()); lastFPS = fps; } } device->drop(); return 0; }