Code: Select all
#include <irrlicht.h>
#include <iostream>
using namespace irr;
#pragma comment(lib, "Irrlicht.lib")
IrrlichtDevice* device = 0;
bool UseHighLevelShaders = false;
class MyShaderCallBack : public video::IShaderConstantSetCallBack
{
public:
virtual void OnSetConstants(video::IMaterialRendererServices* services, s32 userData)
{
video::IVideoDriver* driver = services->getVideoDriver();
// set transposed world matrix
core::matrix4 tWorld = driver->getTransform(video::ETS_WORLD).getTransposed();
services->setVertexShaderConstant(&tWorld.M[0], 0, 4);
// The viewpoint is at (0., 0., 0.) in eye space.
// Turning this into a vector [0 0 0 1] and multiply it by
// the inverse of the view matrix, the resulting vector is the
// object space location of the camera.
f32 floats[4] =
{
0,0,0,1
};
core::matrix4 minv = driver->getTransform(video::ETS_VIEW);
minv.makeInverse();
minv.multiplyWith1x4Matrix(floats);
services->setVertexShaderConstant(floats, 16, 1);
// set transposed worldViewProj matrix
core::matrix4 worldViewProj;
worldViewProj = driver->getTransform(video::ETS_PROJECTION);
worldViewProj *= driver->getTransform(video::ETS_VIEW);
worldViewProj *= driver->getTransform(video::ETS_WORLD);
core::matrix4 tr = worldViewProj.getTransposed();
services->setVertexShaderConstant(&tr.M[0], 8, 4);
// here we've got to fetch the fixed function lights from the driver
// and set them as constants
/*services->setVertexShaderConstant(
reinterpret_cast<f32*>(5), 18, 1);*/
int cnt = driver->getDynamicLightCount();
for (int i=0; i<2; ++i)
{
video::SLight light;
if (i<cnt)
light = driver->getDynamicLight(i);
else
{
light.DiffuseColor.set(0,0,0); // make light dark
light.Radius = 1.0f;
}
light.DiffuseColor.a = 1.0f/(light.Radius*light.Radius); // set attenuation
services->setVertexShaderConstant(
reinterpret_cast<f32*>(&light.Position), 12+(i*2), 1);
services->setVertexShaderConstant(
reinterpret_cast<f32*>(&light.DiffuseColor), 13+(i*2), 1);
}
f32 factor = 1;
f32 c6[] =
{
factor, factor, factor, factor
};
services->setPixelShaderConstant(c6, 0, 1);
f32 time =device->getTimer()->getTime()/1000;
services->setVertexShaderConstant(reinterpret_cast<f32*>(&time), 18, 4);
}
};
int main()
{
// let user select driver type
video::E_DRIVER_TYPE driverType = video::EDT_DIRECT3D9;
printf("Please select the driver you want for this example:\n"\
" (a) Direct3D 9.0c\n (b) Direct3D 8.1\n (c) OpenGL 1.5\n"\
" (d) Software Renderer\n (e) Apfelbaum Software Renderer\n"\
" (f) NullDevice\n (otherKey) exit\n\n");
char i;
std::cin >> i;
switch(i)
{
case 'a':
driverType = video::EDT_DIRECT3D9;
break;
case 'b':
driverType = video::EDT_DIRECT3D8;
break;
case 'c':
driverType = video::EDT_OPENGL;
break;
case 'd':
driverType = video::EDT_SOFTWARE;
break;
case 'e':
driverType = video::EDT_SOFTWARE2;
break;
case 'f':
driverType = video::EDT_NULL;
break;
default:
return 1;
}
// ask the user if we should use high level shaders for this example
if (driverType == video::EDT_DIRECT3D9 ||
driverType == video::EDT_OPENGL)
{
printf("Please press 'y' if you want to use high level shaders.\n");
std::cin >> i;
if (i == 'y')
UseHighLevelShaders = true;
}
// create device
device = createDevice(driverType, core::dimension2d<s32>(800,800));
if (device == 0)
return 1; // could not create selected driver.
video::IVideoDriver* driver = device->getVideoDriver();
scene::ISceneManager* smgr = device->getSceneManager();
gui::IGUIEnvironment* gui = device->getGUIEnvironment();
const char OPENGL_NORMAL_MAP_VSH[] =
"!!ARBvp1.0\n"\
"#input\n"\
"# 0-3: transposed world matrix;\n"\
"#;12: Light01 position \n"\
"#;13: x,y,z: Light01 color; .w: 1/LightRadius² \n"\
"#;14: Light02 position \n"\
"#;15: x,y,z: Light02 color; .w: 1/LightRadius² \n"\
"#;16: Eye position \n"\
"\n"\
"ATTRIB InPos = vertex.position;\n"\
"ATTRIB InColor = vertex.color;\n"\
"ATTRIB InNormal = vertex.normal;\n"\
"ATTRIB InTexCoord = vertex.texcoord[0];\n"\
"ATTRIB InTangent = vertex.texcoord[1];\n"\
"ATTRIB InBinormal = vertex.texcoord[2];\n"\
"\n"\
"#output\n"\
"OUTPUT OutPos = result.position;\n"\
"OUTPUT OutLightColor1 = result.color.primary;\n"\
"OUTPUT OutLightColor2 = result.color.secondary;\n"\
"OUTPUT OutTexCoord = result.texcoord[0];\n"\
"OUTPUT OutLightVector1 = result.texcoord[1];\n"\
"OUTPUT OutLightVector2 = result.texcoord[2];\n"\
"OUTPUT OutEyeVector = result.texcoord[3];\n"\
"OUTPUT projcoord = result.texcoord[4];\n"\
"\n"\
"PARAM MVP[4] = { state.matrix.mvp }; # modelViewProjection matrix.\n"\
"PARAM c[7] = { { 1.3, -0.07, 0.07, 0.15915494 },\n"\
" program.local[18],\n"\
"{ 0.25, 0, 0.5, 1 },\n"\
"{ 24.980804, -24.980804, -60.145809, 60.145809 },\n"\
"{ 85.453789, -85.453789, -64.939354, 64.939354 },\n"\
"{ 19.739208, -19.739208, -1, 1 },\n"\
"{ -9, 0.75, 10, -0.050000001 } };\n"\
"TEMP R0;\n"\
"TEMP R1;\n"\
"TEMP R2;\n"\
"TEMP R3;\n"\
"TEMP R4;\n"\
"MOV R0.x, c[2].z;\n"\
"MUL R0.y, c[1].x, R0.x;\n"\
"MAD R0.z, vertex.position.x, c[6].w, R0.y;\n"\
"MUL R0.x, vertex.position.z, c[0].z;\n"\
"MAD R0.y, vertex.position.x, c[0], R0.x;\n"\
"MOV R0.x, c[0];\n"\
"MAD R0.x, c[1], R0, R0.y;\n"\
"MUL R0.y, R0.z, c[0].w;\n"\
"ADD R0.y, R0, -c[2].x;\n"\
"MUL R0.x, R0, c[0].w;\n"\
"ADD R0.x, R0, -c[2];\n"\
"FRC R0.w, R0.x;\n"\
"FRC R1.w, R0.y;\n"\
"ADD R0.xyz, -R1.w, c[2].yzww;\n"\
"MUL R0.xyz, R0, R0;\n"\
"MAD R3.xyz, R0, c[3].xyxw, c[3].zwzw;\n"\
"MAD R3.xyz, R3, R0, c[4].xyxw;\n"\
"MAD R3.xyz, R3, R0, c[4].zwzw;\n"\
"MAD R3.xyz, R3, R0, c[5].xyxw;\n"\
"MAD R3.xyz, R3, R0, c[5].zwzw;\n"\
"SGE R0.xy, R1.w, c[6];\n"\
"SLT R0.z, R1.w, c[2].x;\n"\
"ADD R1.xyz, -R0.w, c[2].yzww;\n"\
"MUL R1.xyz, R1, R1;\n"\
"MUL R2.xyz, R1, c[3].xyxw;\n"\
"ADD R2.xyz, R2, c[3].zwzw;\n"\
"MAD R2.xyz, R2, R1, c[4].xyxw;\n"\
"MAD R2.xyz, R2, R1, c[4].zwzw;\n"\
"MOV R4.yz, R0.xxyw;\n"\
"MOV R4.x, R0.z;\n"\
"MOV R0.xz, R4;\n"\
"DP3 R0.y, R4, c[5].zwzw;\n"\
"DP3 R1.w, R3, -R0;\n"\
"MAD R0.xyz, R2, R1, c[5].xyxw;\n"\
"MAD R0.xyz, R0, R1, c[5].zwzw;\n"\
"SGE R1.xy, R0.w, c[6];\n"\
"SLT R1.z, R0.w, c[2].x;\n"\
"MOV R2.x, R1.z;\n"\
"MOV R2.yz, R1.xxyw;\n"\
"MAD R1.w, R1, c[2].z, c[2].z;\n"\
"MOV R1.xz, R2;\n"\
"DP3 R1.y, R2, c[5].zwzw;\n"\
"DP3 R0.x, R0, -R1;\n"\
"MAD R0.y, R1.w, c[6].z, vertex.position;\n"\
"MAD R0.x, R0, c[2].z, c[2].z;\n"\
"TEMP POSADD;\n"\
"MAD POSADD.y, R0.x, c[6].z, R0;\n"\
"MUL POSADD.y,POSADD.y, 3;\n"\
"TEMP Temp;\n"\
"TEMP TempColor;\n"\
"TEMP TempNormal;\n"\
"TEMP TempTangent;\n"\
"TEMP TempBinormal;\n"\
"TEMP TempLightVector1;\n"\
"TEMP TempLightVector2;\n"\
"TEMP TempEyeVector;\n"\
"TEMP TempTransLightV1;\n"\
"TEMP TempTransLightV2;\n"\
"\n"\
"TEMP YPOS;\n"\
"TEMP OutPos1;\n"\
"# transform position to clip space \n"\
"DP4 OutPos1.x, MVP[0], InPos;\n"\
"DP4 YPOS.y, MVP[1], InPos;\n"\
"DP4 OutPos1.z, MVP[2], InPos;\n"\
"DP4 OutPos1.w, MVP[3], InPos;\n"\
"ADD OutPos1.y,YPOS.y,POSADD.y;\n"\
"ADD TempBinormal,OutPos1,1;\n"\
"MUL TempBinormal.y,TempBinormal.y,-1;\n"\
"MUL projcoord,TempBinormal,.5;\n"\
"MOV OutPos,OutPos1;\n"\
"\n"\
"# transform normal \n"\
"DP3 TempNormal.x, InNormal.x, program.local[0];\n"\
"DP3 TempNormal.y, InNormal.y, program.local[1]; \n"\
"DP3 TempNormal.z, InNormal.z, program.local[2];\n"\
"\n"\
"# transform tangent \n"\
"DP3 TempTangent.x, InTangent.x, program.local[0];\n"\
"DP3 TempTangent.y, InTangent.y, program.local[1]; \n"\
"DP3 TempTangent.z, InTangent.z, program.local[2];\n"\
"\n"\
"# transform binormal \n"\
"DP3 TempBinormal.x, InBinormal.x, program.local[0];\n"\
"DP3 TempBinormal.y, InBinormal.y, program.local[1]; \n"\
"DP3 TempBinormal.z, InBinormal.z, program.local[2];\n"\
"\n"\
"# vertex into world position \n"\
"DP4 Temp.x, InPos, program.local[0];\n"\
"DP4 Temp.y, InPos, program.local[1];\n"\
"DP4 Temp.z, InPos, program.local[2];\n"\
"DP4 Temp.w, InPos, program.local[3];\n"\
"\n"\
"# eye vector \n"\
"SUB Temp, program.local[16], Temp; \n"\
/*"# transform the eye vector with U, V, W \n"\
"DP3 TempEyeVector.x, TempTangent, Temp; \n"\
"DP3 TempEyeVector.y, TempBinormal, Temp; \n"\
"DP3 TempEyeVector.z, TempNormal, Temp; \n"\
"\n"\*/
"# transform the eye vector with U, V, W \n"\
"MOV TempEyeVector, Temp; \n"\
/*"MOV TempEyeVector.y, Temp; \n"\
"MOV TempEyeVector.z, Temp; \n"\
"\n"\*/
"# normalize eye vector \n"\
"DP3 TempEyeVector.w, TempEyeVector, TempEyeVector; \n"\
"RSQ TempEyeVector.w, TempEyeVector.w; \n"\
"MUL TempEyeVector, TempEyeVector, TempEyeVector.w;\n"\
"MOV OutLightVector1,TempEyeVector;\n"\
"MOV OutLightVector2,TempNormal;\n"\
"MUL TempEyeVector, TempEyeVector, {1,-1,-1,1}; # flip x \n"\
"\n"\
"\n"\
"# move light and eye vectors out\n"\
"MAD OutEyeVector, TempEyeVector, {0.5,0.5,0.5,0.5}, {0.5,0.5,0.5,0.5}; \n"\
"\n"\
"# move out texture coordinates and original alpha value\n"\
"MOV OutTexCoord, InTexCoord; \n"\
"MOV OutLightColor1.w, InColor.w; \n"\
"\n"\
"END\n";
// Irrlicht Engine OpenGL render path normal map pixel shader
// I guess it could be optimized a bit, because I wrote it in D3D ASM and
// transfered it 1:1 to OpenGL
const char OPENGL_NORMAL_MAP_PSH[] =
"!!ARBfp1.0\n"\
"\n"\
"#Input\n"\
"ATTRIB inTexCoord = fragment.texcoord[0]; \n"\
"ATTRIB light1Vector = fragment.texcoord[1]; \n"\
"ATTRIB light2Vector = fragment.texcoord[2]; \n"\
"ATTRIB eyeVector = fragment.texcoord[3]; \n"\
"ATTRIB projt = fragment.texcoord[4]; \n"\
"ATTRIB light1Color = fragment.color.primary; \n"\
"ATTRIB light2Color = fragment.color.secondary; \n"\
"\n"\
"#Output\n"\
"OUTPUT outColor = result.color;\n"\
"TEMP temp;\n"\
"TEMP temp2;\n"\
"TEMP colorMapColor;\n"\
"TEMP normalMapColor;\n"\
"\n"\
"PARAM height_scale = program.local[0]; \n"\
"# fetch color and normal map; \n"\
"TEX normalMapColor, inTexCoord, texture[1], 2D; \n"\
//"MAD normalMapColor, normalMapColor, {2,2,2,2}, {-1,-1,-1,-1}; \n"\
"TEMP Tempnr;\n"\
"TEMP Tempner;\n"\
"MUL Tempnr,normalMapColor,light2Vector;\n"\
/*"DP4 Tempner.x,Tempnr,Tempnr;\n"\
"RSQ Tempner.x,Tempner.x;\n"\
"MUL Tempnr,Tempnr,Tempner.x;\n"\*/
"\n"\
"\n"\
"# extract eye vector (so substract 0.5f and multiply by 2)\n"\
"MAD temp, eyeVector, {2,2,2,2}, {-1,-1,-1,-1};\n"\
"\n"\
"# height = height * scale \n"\
"MUL normalMapColor, normalMapColor, height_scale;\n"\
"\n"\
"# calculate new texture coord: height * eye + oldTexCoord\n"\
"MAD temp, temp, normalMapColor.wwww, inTexCoord;\n"\
"\n"\
"TEMP tempfren;\n"\
"TEMP refl;\n"\
"TEMP projf;\n"\
"MUL projf, projt,temp; \n"\
//"MIN projf,projf,0;\n"\//
"MAX projf,projf,0.2;\n"\
"TXP refl, projf, texture[2], 2D; \n"\
"DP3 tempfren.x, Tempnr, light1Vector; \n"\
"RCP tempfren.x,tempfren.x; \n"\
"MUL tempfren.x,.1,tempfren.x;\n"\
"MUL refl,refl,tempfren.x;\n"\
"# fetch new textures \n"\
"MAD temp, temp, normalMapColor.wwww, .5;\n"\
"TXP colorMapColor, temp, texture[0], 2D; \n"\
"# luminance * base color; \n"\
"MUL outColor, refl,1; \n"\
"MOV outColor.a, light1Color.a; #write interpolated vertex alpha value\n"\
"\n"\
"END\n";
// create materials
video::IGPUProgrammingServices* gpu = driver->getGPUProgrammingServices();
s32 newMaterialType1 = 0;
s32 newMaterialType2 = 0;
if (gpu)
{
MyShaderCallBack* mc = new MyShaderCallBack();
// create the shaders depending on if the user wanted high level
// or low level shaders:
// create material from high level shaders (hlsl or glsl)
newMaterialType1 = gpu->addShaderMaterial(OPENGL_NORMAL_MAP_VSH,
OPENGL_NORMAL_MAP_PSH, mc, video::EMT_TRANSPARENT_ADD_COLOR);
mc->drop();
}
smgr->getParameters()->setParameter(
scene::MY3D_TEXTURE_PATH, "./data");
scene::ISceneNode* test_scene = smgr->addOctTreeSceneNode(smgr->getMesh("./data/temple.my3d"));
test_scene->setPosition( irr::core::vector3df(0,0,0) );
test_scene->setScale( irr::core::vector3df(0.5,0.5,0.5) );
test_scene->setRotation( irr::core::vector3df(0,0,0) );
test_scene->setMaterialFlag(video::EMF_LIGHTING, false);
// create test scene node 1, with the new created material type 1
video::ITexture* rt = 0;
rt = driver->createRenderTargetTexture(core::dimension2d<s32>(512,512));
scene::IAnimatedMesh* mesh;
mesh = smgr->addHillPlaneMesh("myHill",
core::dimension2d<f32>(20,20),
core::dimension2d<s32>(40,40), 0, 0,
core::dimension2d<f32>(0,0),
core::dimension2d<f32>(3,3));
scene::ISceneNode* waternode = smgr->addMeshSceneNode(mesh->getMesh(0));
waternode->setPosition(core::vector3df(-50,280,0));
waternode->setScale(core::vector3df(2,2,2));
waternode->setMaterialTexture(1, driver->getTexture("../../media/particle.tga"));
waternode->setMaterialType((video::E_MATERIAL_TYPE)newMaterialType1);
// add a scene node with no shader
scene::ISceneNode*node ;
node = smgr->addTestSceneNode(50);
node->setPosition(core::vector3df(0,50,25));
node->setMaterialTexture(0, driver->getTexture("../../media/wall.bmp"));
smgr->addTextSceneNode(gui->getBuiltInFont(), L"NO SHADER",
video::SColor(255,255,255,255), node);
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"));
driver->setTextureCreationFlag(video::ETCF_CREATE_MIP_MAPS, true);
// add a camera and disable the mouse cursor
scene::ICameraSceneNode* cam = smgr->addCameraSceneNodeFPS(0, 100.0f, 100.0f);
//cam->setPosition(core::vector3df(-100,50,100));
cam->setTarget(core::vector3df(0,0,0));
device->getCursorControl()->setVisible(false);
scene::ICameraSceneNode* watercam = smgr->addCameraSceneNodeFPS(0, 100.0f, 100.0f);
/*
Now draw everything. That's all.
*/
video::ITexture* colorMap = driver->getTexture("rockwall.bmp");
video::ITexture* normalMap = driver->getTexture("rockwall_height1.bmp");
driver->makeNormalMapTexture(normalMap, 10.0f);
waternode->setMaterialTexture(0, colorMap);
waternode->setMaterialTexture(1, normalMap);
waternode->setMaterialTexture(2, rt);
int lastFPS = -1;
while(device->run())
if (device->isWindowActive())
{
core::vector3df waterpos=waternode->getPosition();
f32 Ypos=cam->getPosition().Y-waterpos.Y;
watercam->setPosition(core::vector3df(cam->getPosition().X,Ypos,cam->getPosition().Z));
watercam->setRotation(core::vector3df(cam->getRotation().X*-1,cam->getRotation().Y,cam->getRotation().Z));
// draw scene into render target
smgr->setActiveCamera(cam);
driver->beginScene(true, true, video::SColor(255,0,0,0));
// set render target texture
driver->setRenderTarget(rt, false, true, video::SColor(0,0,0,255));
// make cube invisible and set fixed camera as active camera
waternode->setVisible(false);
smgr->setActiveCamera(watercam);
watercam->setInputReceiverEnabled(false);
// draw whole scene into render buffer
smgr->drawAll();
// set back old render target
driver->setRenderTarget(0);
// make the cube visible and set the user controlled camera as active one
waternode->setVisible(true);
smgr->setActiveCamera(cam);
smgr->drawAll();
driver->endScene();
int fps = driver->getFPS();
if (lastFPS != fps)
{
core::stringw str = L"Irrlicht Engine - Vertex and pixel shader example [";
str += driver->getName();
str += "] FPS:";
str += fps;
device->setWindowCaption(str.c_str());
lastFPS = fps;
}
}
device->drop();
return 0;
}