Panther wrote:
If anyone has an idea how to make the mirror "perfect" please let me know. Meanwhile, it is still useful for most applications (the reflection is believeable when you don't put objects right beside it).
I thought about that problem some time ago, and in my opinion getting a "perfect" mirror is simple. You need a second camera looking onto the mirror, but from the other side. And everything between this second cam and the mirror needs to be clipped. That second cam is rendered to a texture, and that texture is drawn onto the mirror, but with other UVs...
I am trying to execute this code on 1.4.1 realese of irrlicht but the mirror is not getting displayed on screen,
I have tried this code on 1.2 realese of irrlicht and its working fine.
Because of some reasons i can not use the 1.2 release on my project.
If anybody can suggest something on this will be very helpful.
That's because virtual methods are only overriding their original interfaces when the signatures match exactly. Otherwise, the basic implementation is used, which leads to wrong results.
Except void OnPreRender() i can,t figure out any changes
So posting the whole code:
// Mirror.cpp - version 2 - This is a simple example that uses the Irrlicht 3D Engine to create a mirror effect
#define _CRT_SECURE_NO_DEPRECATE 1 //suppress stupid swprintf warning! (for VC++ 2005)
#include <stdio.h>
#include <wchar.h>
#include <irrlicht.h>
#include <windows.h>
#include <stdlib.h>
#include <math.h>
#include "irrMath.h"
#include "irrTypes.h"
using namespace irr;
#pragma comment(lib, "Irrlicht.lib")
virtual irr::f32 acosd(irr::f32 input) //arc-cosine in degrees, uses f32 type (instead of "double")
{
double value = acos((double)input) * 180.0 / 3.14159265358979; //Converts from radians back to degrees
return (irr::f32)value;
}
virtual irr::f32 angle(core::vector3df v1, core::vector3df v2) //angle between two vectors
{
if ((len(v1) == 0) || (len(v2) == 0))
{
return 0; //avoid division by zero!
} else {
return (irr::f32)acosd(v1.dotProduct(v2) / (len(v1) * len(v2)));
}
}
virtual void setRotationUp(core::vector3df rotationVector, scene::ICameraSceneNode* renderCamera)
{
// If you just use setRotation(), then the whole image rotates (real mirrors don't do this)!
// If you were rotating a television, the whole image would rotate. But not a mirror.
// Unfortunately, this does cause some "jitter" in the image (not sure why - looks like it is being drawn twice).
core::vector3df upV;
upV = core::vector3df(0, 1, 0); //fixedCam->getUpVector();
upV.rotateYZBy(rotationVector.X, core::vector3df(0, 0, 0));
upV.rotateXZBy(-rotationVector.Y, core::vector3df(0, 0, 0));
upV.rotateXYBy(rotationVector.Z, core::vector3df(0, 0, 0));
renderCamera->setUpVector(upV);
setRotation(rotationVector);
}
dwarfVector = nodeLookingAtMirror->getPosition() - getPosition(); // Store the node's vector to the mirror
mirrorV1 = Vertices[0].Pos - Vertices[3].Pos; // Get a vector on the surface of the mirror
mirrorV1.rotateYZBy(getRotation().X, core::vector3df(0, 0, 0));
mirrorV1.rotateXZBy(-getRotation().Y, core::vector3df(0, 0, 0));
mirrorV1.rotateXYBy(getRotation().Z, core::vector3df(0, 0, 0));
mirrorV2 = Vertices[2].Pos - Vertices[1].Pos; // Get another vector on the surface of the mirror
mirrorV2.rotateYZBy(getRotation().X, core::vector3df(0, 0, 0));
mirrorV2.rotateXZBy(-getRotation().Y, core::vector3df(0, 0, 0));
mirrorV2.rotateXYBy(getRotation().Z, core::vector3df(0, 0, 0));
mirrorNormal = mirrorV1.crossProduct(mirrorV2); // Use the above 2 vectors to find the mirror's Normal
mirrorNormal = mirrorNormal.normalize(); // Normalize the Normal (to a length of 1).
myAngle = angle(dwarfVector, mirrorNormal);
dP = 2.0f * mirrorNormal.dotProduct(dwarfVector); // Calculate the "dot product" - used to find the reflection vector below
reflectionVector = core::vector3df(dP, dP, dP) * mirrorNormal - dwarfVector; // Standard formula for a reflection vector!
reflectionVector.setLength(100.0f);
if (frontSide != oldFrontSide) // This flips the image horizontally, so the image is reversed, like a real mirror.
{
tempX = Vertices[0].TCoords.X; // Set the texture coordinates so the image is reversed on front side
tempY = Vertices[0].TCoords.Y;
Vertices[0].TCoords.X = Vertices[2].TCoords.X;
Vertices[0].TCoords.Y = Vertices[2].TCoords.Y;
Vertices[2].TCoords.X = tempX;
Vertices[2].TCoords.Y = tempY;
if (getRotation().X > 90.0f) //This flips the image, so if the user flips the mirror vertically, it still shows the ground on the bottom
setRotation(core::vector3df(getRotation().X - 180.0f, getRotation().Y, getRotation().Z));
if (getRotation().X < -90.0f) //This flips the image, so if the user flips the mirror vertically, it still shows the ground on the bottom
setRotation(core::vector3df(getRotation().X + 180.0f, getRotation().Y, getRotation().Z));
return reflectionVector;
}
};
CMirror* mirror = 0;
class MyEventReceiver : public IEventReceiver
{
public:
virtual bool OnEvent( const SEvent &event)
{
core::vector3df mirVector;
if (cube != 0 && event.EventType == irr::EET_KEY_INPUT_EVENT&&
!event.KeyInput.PressedDown)
{
switch(event.KeyInput.Key)
{
case KEY_ESCAPE: //Quit the program
{
quit = true;
return true;
}
case KEY_COMMA: // rotate mirror left
{
mirVector = mirror->getRotation();
mirVector.Y += 6.0f; //Rotate a little
mirror->setRotationUp(mirVector, fixedCam);
return true;
}
case KEY_PERIOD: // rotate mirror right
{
mirVector = mirror->getRotation();
mirVector.Y -= 6.0f; //Rotate a little
mirror->setRotationUp(mirVector, fixedCam);
return true;
}
case KEY_KEY_P: // rotate mirror +Z
{
mirVector = mirror->getRotation();
mirVector.Z += 6.0f; // Rotate a little
mirror->setRotationUp(mirVector, fixedCam);
return true;
}
case KEY_KEY_L: // rotate mirror -Z
{
mirVector = mirror->getRotation();
mirVector.Z -= 6.0f; // Rotate a little
mirror->setRotationUp(mirVector, fixedCam);
return true;
}
case KEY_KEY_O: // rotate mirror +X
{
mirVector = mirror->getRotation();
mirVector.X += 6.0f; //Rotate a little
mirror->setRotationUp(mirVector, fixedCam);
return true;
}
case KEY_KEY_K: // rotate mirror -X
{
mirVector = mirror->getRotation();
mirVector.X -= 6.0f; //Rotate a little
mirror->setRotationUp(mirVector, fixedCam);
return true;
}
}
}
return false;
}
};
int main()
{
MyEventReceiver receiver;
quit = false;
// If your window is not square, the mirror's reflection will have a slight lensing
// effect around the sides. For example, 800x800 will give you a nice reflection.
// But 1024x768 will make the mirror behave as if it's slightly concave mirror.
// This effect is not pronounced, and for most applications, is probably acceptable.
// Note: OPENGL seems to perform slower than DIRECT3D8 with a mirror, for some reason.
//device = createDevice(video::EDT_OPENGL, core::dimension2d<s32>(1024, 768),
// 16, false, false, false, &receiver);
device = createDevice(video::EDT_DIRECT3D9, core::dimension2d<s32>(800, 800),
16, false, false, false, &receiver);
// Add a Camera
camera = smgr->addCameraSceneNodeFPS(0,100.0f,750.0f); //Adds a camera
camera->setPosition(core::vector3df(4100, 100, 7500));
camera->setFarValue(12000.0f);
//Add a Dwarf in (to represent the player)
scene::IAnimatedMesh* meshDwarf = smgr->getMesh("../media/dwarf.x");
dwarf = smgr->addAnimatedMeshSceneNode(meshDwarf);
dwarf->setPosition(core::vector3df(camera->getPosition().X, camera->getPosition().Y - 80.0f, camera->getPosition().Z)); // Make the dwarf stay with the camera
dwarf->setMaterialFlag(video::EMF_LIGHTING, true);
dwarf->setAnimationSpeed(10);
//------ Add a Terrain in --------------------------------------------------------------------------------
scene::ITerrainSceneNode* terrain = smgr->addTerrainSceneNode(
"../media/terrain-heightmap.bmp");
terrain->setScale(core::vector3df(40, 4.4f, 40)); // To make the terrain look bigger, we change the scale factor of it to (40, 4.4, 40).
terrain->setMaterialFlag(video::EMF_LIGHTING, true);
// The first texture will be repeated only once over the whole terrain, and the second one (detail map) 20 times.
terrain->setMaterialTexture(0, driver->getTexture("../media/terrain-texture.jpg"));
terrain->setMaterialTexture(1, driver->getTexture("../media/detailmap3.jpg"));
terrain->setMaterialType(video::EMT_DETAIL_MAP);
terrain->scaleTexture(1.0f, 20.0f);
terrain->setMaterialFlag(video::EMF_NORMALIZE_NORMALS, true);
// Triangle selector for terrain (so we can create a collision response animator below
scene::ITriangleSelector* selector
= smgr->createTerrainTriangleSelector(terrain, 0);
terrain->setTriangleSelector(selector);
selector->drop();
// Create a skybox (so we can see clouds, etc)
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);
//------- End of Terrain --------------------------------------------------------------------------------
// We create a collision response animator and attach it to the camera, so that the camera will not be
// able to fly through the terrain.
scene::ISceneNodeAnimator* anim2 = smgr->createCollisionResponseAnimator(
selector, camera, core::vector3df(30,60,30),
core::vector3df(0,0,0),
core::vector3df(0,0,0));
camera->addAnimator(anim2);
anim2->drop();
driver->setAmbientLight(video::SColor(0,255,255,255)); // Let there be light!
// Create a cube to place in front of the mirror (to look at)
cube = smgr->addCubeSceneNode();//
//cube->setPosition(core::vector3df(4100, 100, 7500));
cube->setPosition(core::vector3df(camera->getPosition().X + 150.0f, camera->getPosition().Y, camera->getPosition().Z));
cube->setScale(core::vector3df(6.0f, 6.0f, 6.0f));
cube->setMaterialFlag(video::EMF_LIGHTING, true);
cube->setMaterialTexture(0, driver->getTexture("../../media/wall.jpg"));
// Create a CMirror to be used as a mirror
mirror = new CMirror(smgr->getRootSceneNode(), smgr, 999, device);
mirror->setPosition(core::vector3df(camera->getPosition().X + 200.0f, camera->getPosition().Y, camera->getPosition().Z + 300.0f));
mirror->setRotation(core::vector3df(0, 0, 0));
mirror->setMaterialFlag(video::EMF_NORMALIZE_NORMALS, true); // Only really necessary if the scale isn't (1,1,1)
mirror->setMaterialFlag(video::EMF_LIGHTING, false);
video::ITexture* rt = 0; // create render target (used to "render-to-texture" for the mirror)
if (driver->queryFeature(video::EVDF_RENDER_TO_TARGET)) //If the driver can handle Render-To-Target, then...
{
rt = driver->createRenderTargetTexture(core::dimension2d<s32>(256,256));
mirror->setMaterialTexture(0, rt); // set material of mirror to render target
fixedCam = smgr->addCameraSceneNode(0, mirror->getPosition(), // add fixed camera..
dwarf->getPosition()); //..looking at anything (doesn't matter)
}
else // create problem text if device doesn't support render-to-texture
{
gui::IGUISkin* skin = guiEnv->getSkin();
gui::IGUIFont* font = guiEnv->getFont("../media/fonthaettenschweiler.bmp");
if (font)
skin->setFont(font);
gui::IGUIStaticText* text = guiEnv->addStaticText(
L"Your hardware or this renderer is not able to use the "\
L"render to texture feature. RTT Disabled.",
core::rect<s32>(150,20,470,60));
text->setOverrideColor(video::SColor(100,255,255,255));
}
// Set other variables before the drawing loop
device->getCursorControl()->setVisible(false); // disable mouse cursor
int lastFPS = -1;
while(device->run() && !quit)
if (device->isWindowActive())
{
dwarf->setPosition(core::vector3df(camera->getPosition().X, camera->getPosition().Y - 80.0f, camera->getPosition().Z)); // Make the dwarf stay with the camera
dwarf->setRotation(core::vector3df(0, camera->getRotation().Y + 180.0f, 0)); //Make the dwarf turn with the camera
if (rt) // draw scene into render target
{
driver->setRenderTarget(rt, true, true, video::SColor(0,0,0,255)); // set render target texture (the mirror's texture)
mirror->setVisible(false); // make mirror invisible (so it doesn't get painted over)
smgr->setActiveCamera(fixedCam); // set fixed camera as active camera
fixedCam->setTarget(myReflectionVector + mirror->getPosition()); // make the mirror's camera "look" in the direction of the reflection
smgr->drawAll(); // draw whole scene into render buffer
driver->setRenderTarget(0); // set back old render target
mirror->setVisible(true); // make the mirror visible again
smgr->setActiveCamera(camera); // set the user controlled camera as active one
}
smgr->drawAll(); // draw the 3d scene
guiEnv->drawAll(); // draw the gui (if anything to draw - could contain the RTT warning above)
driver->endScene();
int fps = driver->getFPS(); // This section displays the frames-per-second on the window
if (lastFPS != fps)
{
wchar_t tmp[1024];
swprintf(tmp, 1024, L"Mirror Example - Irrlicht Engine [%s] fps:%d",
driver->getName(), fps);
device->setWindowCaption(tmp);
lastFPS = fps;
}
}
I did debugging of the code on both 1.4.1 and 1.2 version of irrlicht 3d engine
and found the in 1.2 that OnPreRender() function is getting called from smgr->drawAll() but in case of 1.4.1 realese it,s not getting called it might me because of this mirror is not displayed on screen
virtual irr::f32 acosd(irr::f32 input) //arc-cosine in degrees, uses f32 type (instead of "double")
{
double value = acos((double)input) * 180.0 / 3.14159265358979; //Converts from radians back to degrees
return (irr::f32)value;
}
virtual irr::f32 angle(core::vector3df v1, core::vector3df v2) //angle between two vectors
{
if ((len(v1) == 0) || (len(v2) == 0))
{
return 0; //avoid division by zero!
} else {
return (irr::f32)acosd(v1.dotProduct(v2) / (len(v1) * len(v2)));
}
}
virtual void setRotationUp(core::vector3df rotationVector, scene::ICameraSceneNode* renderCamera)
{
// If you just use setRotation(), then the whole image rotates (real mirrors don't do this)!
// If you were rotating a television, the whole image would rotate. But not a mirror.
// Unfortunately, this does cause some "jitter" in the image (not sure why - looks like it is being drawn twice).
core::vector3df upV;
upV = core::vector3df(0, 1, 0); //fixedCam->getUpVector();
upV.rotateYZBy(rotationVector.X, core::vector3df(0, 0, 0));
upV.rotateXZBy(-rotationVector.Y, core::vector3df(0, 0, 0));
upV.rotateXYBy(rotationVector.Z, core::vector3df(0, 0, 0));
renderCamera->setUpVector(upV);
setRotation(rotationVector);
}
dwarfVector = nodeLookingAtMirror->getPosition() - getPosition(); // Store the node's vector to the mirror
mirrorV1 = Vertices[0].Pos - Vertices[3].Pos; // Get a vector on the surface of the mirror
mirrorV1.rotateYZBy(getRotation().X, core::vector3df(0, 0, 0));
mirrorV1.rotateXZBy(-getRotation().Y, core::vector3df(0, 0, 0));
mirrorV1.rotateXYBy(getRotation().Z, core::vector3df(0, 0, 0));
mirrorV2 = Vertices[2].Pos - Vertices[1].Pos; // Get another vector on the surface of the mirror
mirrorV2.rotateYZBy(getRotation().X, core::vector3df(0, 0, 0));
mirrorV2.rotateXZBy(-getRotation().Y, core::vector3df(0, 0, 0));
mirrorV2.rotateXYBy(getRotation().Z, core::vector3df(0, 0, 0));
mirrorNormal = mirrorV1.crossProduct(mirrorV2); // Use the above 2 vectors to find the mirror's Normal
mirrorNormal = mirrorNormal.normalize(); // Normalize the Normal (to a length of 1).
myAngle = angle(dwarfVector, mirrorNormal);
dP = 2.0f * mirrorNormal.dotProduct(dwarfVector); // Calculate the "dot product" - used to find the reflection vector below
reflectionVector = core::vector3df(dP, dP, dP) * mirrorNormal - dwarfVector; // Standard formula for a reflection vector!
reflectionVector.setLength(100.0f);
if (frontSide != oldFrontSide) // This flips the image horizontally, so the image is reversed, like a real mirror.
{
tempX = Vertices[0].TCoords.X; // Set the texture coordinates so the image is reversed on front side
tempY = Vertices[0].TCoords.Y;
Vertices[0].TCoords.X = Vertices[2].TCoords.X;
Vertices[0].TCoords.Y = Vertices[2].TCoords.Y;
Vertices[2].TCoords.X = tempX;
Vertices[2].TCoords.Y = tempY;
if (getRotation().X > 90.0f) //This flips the image, so if the user flips the mirror vertically, it still shows the ground on the bottom
setRotation(core::vector3df(getRotation().X - 180.0f, getRotation().Y, getRotation().Z));
if (getRotation().X < -90.0f) //This flips the image, so if the user flips the mirror vertically, it still shows the ground on the bottom
setRotation(core::vector3df(getRotation().X + 180.0f, getRotation().Y, getRotation().Z));
return reflectionVector;
}
};
we are working on a scientific project for mentally ill people(schizophrenia or dementia patients)
In the game(our project) players (patient) will be performing some small and very easy task and then they have to interact with the objects also.
while playing this game patient,s scores and errors will be counted
From these scores and errors their Doctors will get the idea about the severity of the disease
You could make a mirror effect much easier (infact i dont think you can do it perfectly without it) with proper use of a cameras perspective and making a glfrustum. And currently the code to make a matrix4 into a frustum perspective matrix is missing so here it is...... you need to use the LH version