(C++) Mirror node for use with Irrlicht

Post those lines of code you feel like sharing or find what you require for your project here; or simply use them as tutorials.
vesa
Posts: 3
Joined: Sat Jul 15, 2006 11:26 am

Re: Close-up reflections not accurate

Post by vesa »

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 found a great article by Hun Yen Kwoon about virtual camera positioning that may be very useful.
http://www.gamedev.net/reference/progra ... tures/vcp/
There's also a mirror-examle for D3D8.
thephoenix
Posts: 19
Joined: Wed Jan 25, 2006 7:44 pm

Post by thephoenix »

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...

EDIT: Oh... didn't read vesas post...
Gaurav Gangwar
Posts: 23
Joined: Thu Jul 31, 2008 7:35 am

code not worki9ng on 1.4.1 realese

Post by Gaurav Gangwar »

Hi all,

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.

Thanks
hybrid
Admin
Posts: 14143
Joined: Wed Apr 19, 2006 9:20 pm
Location: Oldenburg(Oldb), Germany
Contact:

Post by hybrid »

You have to correct the methods' signatures. Otherwise the materials are not properly set.
Gaurav Gangwar
Posts: 23
Joined: Thu Jul 31, 2008 7:35 am

Post by Gaurav Gangwar »

Hi hybrid ,

Thanks for the reply

I am not getting compilation error so how come it is due to method signature
Pls explain more

Thanks
hybrid
Admin
Posts: 14143
Joined: Wed Apr 19, 2006 9:20 pm
Location: Oldenburg(Oldb), Germany
Contact:

Post by hybrid »

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.
Gaurav Gangwar
Posts: 23
Joined: Thu Jul 31, 2008 7:35 am

Post by Gaurav Gangwar »

Hi all,

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")

scene::ISceneNode* cube = 0;
scene::ISceneNode* box = 0;
scene::IAnimatedMeshSceneNode* dwarf = 0;


scene::ICameraSceneNode* camera = 0;
IrrlichtDevice* device = 0;
bool quit;
core::vector3df myReflectionVector, cameraPosition;

scene::ICameraSceneNode* fixedCam = 0;

class CMirror : public scene::ISceneNode
{
core::aabbox3d<f32> Box;
video::SMaterial Material;

public:
video::S3DVertex Vertices[4];

CMirror(scene::ISceneNode* parent, scene::ISceneManager* mgr, s32 id, IrrlichtDevice* myDevice)
: scene::ISceneNode(parent, mgr, id)
{
Material.Wireframe = false;
Material.Lighting = false;

if (myDevice->getVideoDriver()->getDriverType() == video::EDT_OPENGL)
{
//EDT_OPENGL requires we flip the image vertically
Vertices[0] = video::S3DVertex(-70,70,0, 1,1,0, video::SColor(255,255,255,255), 0, 1);
Vertices[1] = video::S3DVertex(-70,-70,0, 1,0,0, video::SColor(255,255,255,255), 0, 0);
Vertices[2] = video::S3DVertex(70,70,0, 0,1,1, video::SColor(255,255,255,255), 1, 1);
Vertices[3] = video::S3DVertex(70,-70,0, 0,0,1, video::SColor(255,255,255,255), 1, 0);
}
else
{
//For other drivers don't need to flip it
Vertices[0] = video::S3DVertex(-70,-70,0, 1,1,0, video::SColor(255,255,255,255), 1, 1);
Vertices[1] = video::S3DVertex(-70,70,0, 1,0,0, video::SColor(255,255,255,255), 1, 0);
Vertices[2] = video::S3DVertex(70,-70,0, 0,1,1, video::SColor(255,255,255,255), 0, 1);
Vertices[3] = video::S3DVertex(70,70,0, 0,0,1, video::SColor(255,255,255,255), 0, 0);
}

Box.reset(Vertices[0].Pos);
for (s32 i=1; i<4; ++i)
Box.addInternalPoint(Vertices.Pos);
}

// void OnPreRender()
// {
// if (IsVisible)
// SceneManager->registerNodeForRendering(this );
//
//// ISceneNode::OnPreRender();
// }

virtual void render()
{
u16 indices[] = { 0,2,3, 2,1,3, 1,0,3, 2,0,1 };
video::IVideoDriver* driver = SceneManager->getVideoDriver();

driver->setMaterial(Material);
driver->setTransform(video::ETS_WORLD, AbsoluteTransformation);
driver->drawIndexedTriangleList(&Vertices[0], 4, &indices[0], 4);
}

virtual const core::aabbox3d<f32>& getBoundingBox() const
{
return Box;
}

virtual s32 getMaterialCount()
{
return 1;
}

virtual video::SMaterial& getMaterial(s32 i)
{
return Material;
}

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 len(core::vector3df v) //vector length
{
return (irr::f32)sqrt((v.X * v.X) + (v.Y * v.Y) + (v.Z * v.Z));
}

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);
}

virtual core::vector3df getMirrorReflection(scene::ISceneNode* nodeLookingAtMirror, scene::ICameraSceneNode* renderCamera)
{
f32 myAngle, dP, tempX, tempY;
core::vector3df reflectionVector, mirrorV1, mirrorV2, mirrorNormal, dwarfVector, delVector;
bool oldFrontSide;
static bool frontSide = true;

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);

oldFrontSide = frontSide;
if (myAngle < 90)
frontSide = false;
else
frontSide = true;

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;

tempX = Vertices[1].TCoords.X;
tempY = Vertices[1].TCoords.Y;
Vertices[1].TCoords.X = Vertices[3].TCoords.X;
Vertices[1].TCoords.Y = Vertices[3].TCoords.Y;
Vertices[3].TCoords.X = tempX;
Vertices[3].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);

video::IVideoDriver* driver = device->getVideoDriver();
scene::ISceneManager* smgr = device->getSceneManager();
gui::IGUIEnvironment* guiEnv = device->getGUIEnvironment();

driver->setTextureCreationFlag(video::ETCF_ALWAYS_32_BIT, true);

// 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

myReflectionVector = mirror->getMirrorReflection(dwarf, fixedCam);

driver->beginScene(false, true, video::SColor(255,113,113,133));

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;
}
}

device->drop(); // Delete Irrlicht Device
return 0;
}
Gaurav Gangwar
Posts: 23
Joined: Thu Jul 31, 2008 7:35 am

Post by Gaurav Gangwar »

Hi guys,

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


waiting for quick replies.
JP
Posts: 4526
Joined: Tue Sep 13, 2005 2:56 pm
Location: UK
Contact:

Post by JP »

getMaterialCount returns a u32 now, not an s32. There's also other functions which have made the same change.
Image Image Image
Gaurav Gangwar
Posts: 23
Joined: Thu Jul 31, 2008 7:35 am

Post by Gaurav Gangwar »

yes and OnPreRender() has changed to virtual void OnRegisterSceneNode()

and i have overloaded it like as following :-

virtual void OnRegisterSceneNode()
{
if (IsVisible)
SceneManager->registerNodeForRendering(this );

//ISceneNode::OnRegisterSceneNode();
}

and now the mirror is there but it is just ehite in colour and but no reflection :(

help pls
JP
Posts: 4526
Joined: Tue Sep 13, 2005 2:56 pm
Location: UK
Contact:

Post by JP »

Have you made the necessary changes to all the material based functions like we suggested?
Image Image Image
Gaurav Gangwar
Posts: 23
Joined: Thu Jul 31, 2008 7:35 am

Post by Gaurav Gangwar »

yes i have made the changes here is the mirror class:


class CMirror : public scene::ISceneNode
{
core::aabbox3d<f32> Box;
video::SMaterial Material;

public:
video::S3DVertex Vertices[4];

CMirror(scene::ISceneNode* parent, scene::ISceneManager* mgr, s32 id, IrrlichtDevice* myDevice)
: scene::ISceneNode(parent, mgr, id)
{
Material.Wireframe = false;
Material.Lighting = false;

if (myDevice->getVideoDriver()->getDriverType() == video::EDT_OPENGL)
{
//EDT_OPENGL requires we flip the image vertically
Vertices[0] = video::S3DVertex(-70,70,0, 1,1,0, video::SColor(255,255,255,255), 0, 1);
Vertices[1] = video::S3DVertex(-70,-70,0, 1,0,0, video::SColor(255,255,255,255), 0, 0);
Vertices[2] = video::S3DVertex(70,70,0, 0,1,1, video::SColor(255,255,255,255), 1, 1);
Vertices[3] = video::S3DVertex(70,-70,0, 0,0,1, video::SColor(255,255,255,255), 1, 0);
}
else
{
//For other drivers don't need to flip it
Vertices[0] = video::S3DVertex(-70,-70,0, 1,1,0, video::SColor(255,255,255,255), 1, 1);
Vertices[1] = video::S3DVertex(-70,70,0, 1,0,0, video::SColor(255,255,255,255), 1, 0);
Vertices[2] = video::S3DVertex(70,-70,0, 0,1,1, video::SColor(255,255,255,255), 0, 1);
Vertices[3] = video::S3DVertex(70,70,0, 0,0,1, video::SColor(255,255,255,255), 0, 0);
}

Box.reset(Vertices[0].Pos);
for (s32 i=1; i<4; ++i)
Box.addInternalPoint(Vertices.Pos);
}

virtual void OnRegisterSceneNode()
{
if (IsVisible)
SceneManager->registerNodeForRendering(this );

//ISceneNode::OnRegisterSceneNode();
}

virtual void render()
{
u16 indices[] = { 0,2,3, 2,1,3, 1,0,3, 2,0,1 };
video::IVideoDriver* driver = SceneManager->getVideoDriver();

driver->setMaterial(Material);
driver->setTransform(video::ETS_WORLD, AbsoluteTransformation);
driver->drawIndexedTriangleList(&Vertices[0], 4, &indices[0], 4);
}

virtual const core::aabbox3d<f32>& getBoundingBox() const
{
return Box;
}

virtual u32 getMaterialCount()
{
return 1;
}

virtual video::SMaterial& getMaterial(u32 i)
{
return Material;
}

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 len(core::vector3df v) //vector length
{
return (irr::f32)sqrt((v.X * v.X) + (v.Y * v.Y) + (v.Z * v.Z));
}

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);
}

virtual core::vector3df getMirrorReflection(scene::ISceneNode* nodeLookingAtMirror, scene::ICameraSceneNode* renderCamera)
{
f32 myAngle, dP, tempX, tempY;
core::vector3df reflectionVector, mirrorV1, mirrorV2, mirrorNormal, dwarfVector, delVector;
bool oldFrontSide;
static bool frontSide = true;

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);

oldFrontSide = frontSide;
if (myAngle < 90)
frontSide = false;
else
frontSide = true;

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;

tempX = Vertices[1].TCoords.X;
tempY = Vertices[1].TCoords.Y;
Vertices[1].TCoords.X = Vertices[3].TCoords.X;
Vertices[1].TCoords.Y = Vertices[3].TCoords.Y;
Vertices[3].TCoords.X = tempX;
Vertices[3].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;
}
};
hybrid
Admin
Posts: 14143
Joined: Wed Apr 19, 2006 9:20 pm
Location: Oldenburg(Oldb), Germany
Contact:

Post by hybrid »

You also have to adapt the const qualifiers of the methods.
Gaurav Gangwar
Posts: 23
Joined: Thu Jul 31, 2008 7:35 am

Post by Gaurav Gangwar »

Thanks a lot hybrid and JP

now the code is now working as expected.

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

Sorry for the late reply
FreakNigh
Posts: 122
Joined: Thu Oct 19, 2006 7:31 am
Location: Orlando FL, USA
Contact:

Post by FreakNigh »

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

Code: Select all

float* create_glfrustumLH(float left, float right, float bottom, float top, float nearZ, float farZ, float *m)
{
	float x = (2.0F*nearZ) / (right-left);
	float y = (2.0F*nearZ) / (top-bottom);
	float a = (right+left) / (right-left);
	float b = (top+bottom) / (top-bottom);
	float c = -(farZ+nearZ) / ( farZ-nearZ);
	float d = -(2.0F*farZ*nearZ) / (farZ-nearZ);

#define M(row,col)  m[col*4+row]
	M(0,0) = x;     M(0,1) = 0.0F;  M(0,2) = a;      M(0,3) = 0.0F;
	M(1,0) = 0.0F;  M(1,1) = y;     M(1,2) = b;      M(1,3) = 0.0F;
	M(2,0) = 0.0F;  M(2,1) = 0.0F;  M(2,2) = -c;      M(2,3) = d;
	M(3,0) = 0.0F;  M(3,1) = 0.0F;  M(3,2) = 1.0F;  M(3,3) = 0.0F;
#undef M
	
	return m;
}

float* create_glfrustumRH(float left, float right, float bottom, float top, float nearZ, float farZ, float *m)
{
	float x = (2.0F*nearZ) / (right-left);
	float y = (2.0F*nearZ) / (top-bottom);
	float a = (right+left) / (right-left);
	float b = (top+bottom) / (top-bottom);
	float c = -(farZ+nearZ) / ( farZ-nearZ);
	float d = -(2.0F*farZ*nearZ) / (farZ-nearZ);

#define M(row,col)  m[col*4+row]
	M(0,0) = x;     M(0,1) = 0.0F;  M(0,2) = a;      M(0,3) = 0.0F;
	M(1,0) = 0.0F;  M(1,1) = y;     M(1,2) = b;      M(1,3) = 0.0F;
	M(2,0) = 0.0F;  M(2,1) = 0.0F;  M(2,2) = c;      M(2,3) = d;
	M(3,0) = 0.0F;  M(3,1) = 0.0F;  M(3,2) = -1.0F;  M(3,3) = 0.0F;
#undef M
	
	return m;
}
Post Reply