(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.
shadowking97
Posts: 8
Joined: Mon Mar 09, 2009 5:55 am
Location: TX

Post by shadowking97 »

Nobody here knows me... yet... I am working on making a commercial grade video game, which my laziness drew me to Irrlicht. As its a good engine, it didn't have all of the features I wanted... but it had enough. The mirror is one of the features I required, so I revised the original one into a new perspective cam one. Since I might be making money off this... I guess I might just help other people using it. The mirror class doesnt like angles at extreme proximity, but its fine looking either head on or moderate distance. It is also one sided. I know it says that it allows for an extra texture as an overlay, but that doesnt work yet. Here is my version of the mirror (works with Irrlicht 1.5):

Code: Select all

class cMirror: public scene::ISceneNode
{
   /*
   This cMirro class is a reconstruction of Panther's version of cMirror.
   It allows for near-perfect reflections, with the exception of extreme angles.
   As the reflection is caculated for the center of the mirror, when the camera
   is close to the mirror, it distorts the rest of the image at odd or extreme
   angles. It also comes with an option for an overlay material for cracks,
   dirt, or to make it a semi-reflective surface such as marble. This class
   is completely self sufficient, to use, just create your mirror object,
   apply transformations or animators, and just before your main render in
   the main loop, use [mirror name]->reflect(); cMirror uses the default
   camera instead of an object, since reflection must be made to players
   point of view.
   */
private:
   core::aabbox3d<f32> Box;
   scene::ISceneNode * cube;
   video::SMaterial reflectMaterial;
   video::ITexture * reflectTexture;
   scene::ICameraSceneNode * reflectCamera;
   scene::ICameraSceneNode * defaultCamera;
   f32 facos[360]; //Fast acos lookup table.
   f32 fsin[360]; //Fast sin lookup table.
   f32 w, h; //hieght and width of the mirror.
   bool hasExtraTexture;
   vector3df vUp, mirrorNormal;

public:
   video::S3DVertex Vertices[4];
   
   ~cMirror(){
      free(reflectTexture);
   }
   
   cMirror(scene::ISceneNode* parent, scene::ISceneManager* mgr, s32 id, IrrlichtDevice* myDevice, scene::ICameraSceneNode* Camera, video::ITexture * mirrorOverlay= 0) : scene::ISceneNode(parent, mgr, id)
   {
      defaultCamera = Camera;
      w=25;
      h=25;
      video::IVideoDriver* driver = myDevice->getVideoDriver();
      if (driver->queryFeature(video::EVDF_RENDER_TO_TARGET)) //If the driver can handle Render-To-Target, then...
      {
         
         reflectTexture = driver->addRenderTargetTexture(core::dimension2d<s32>(1024,1024));
         this->setMaterialTexture(0, reflectTexture); // set material of mirror to render target and settings
         this->setMaterialFlag(video::EMF_NORMALIZE_NORMALS, true);
         this->setMaterialFlag(video::EMF_LIGHTING, false);
         this->setMaterialFlag(video::EMF_WIREFRAME,false);
         if(mirrorOverlay!=0) // If the mirror has an extra texture, apply it.
         {
            hasExtraTexture=true;
			cube = SceneManager->addCubeSceneNode(50);
			 cube->setMaterialTexture(0,mirrorOverlay);
            cube->setMaterialType(video::EMT_TRANSPARENT_ALPHA_CHANNEL);
			cube->setRotation(getRotation());
			cube->setScale(vector3df(getScale().X,getScale().Y,0.01f));
			cube->setMaterialFlag(video::EMF_NORMALIZE_NORMALS, true);
            cube->setMaterialFlag(video::EMF_LIGHTING, false);
         }
		 else
			 hasExtraTexture=false;
         this->setMaterialType(video::EMT_SOLID);
         reflectCamera = SceneManager->addCameraSceneNode(0, this->getPosition(),  // add dynamic camera..
         defaultCamera->getPosition()); //Looking at the camera. This alows you to align the near-
                                        //view plane directly with the mirror plane.
      }
      else
      {
         //TODO: add error message
      }
      if (driver->getDriverType() == video::EDT_OPENGL)
      {
         //EDT_OPENGL requires we flip the image vertically
         Vertices[0] = video::S3DVertex(-h,w,0, 1,1,0, video::SColor(255,255,255,255), 0, 1);
         Vertices[1] = video::S3DVertex(-h,-w,0, 1,0,0, video::SColor(255,255,255,255), 0, 0);
         Vertices[2] = video::S3DVertex(h,w,0, 0,1,1, video::SColor(255,255,255,255), 1, 1);
         Vertices[3] = video::S3DVertex(h,-w,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(-h,-w,0, 1,1,0, video::SColor(255,255,255,255), 1, 1);
         Vertices[1] = video::S3DVertex(-h,w,0, 1,0,0, video::SColor(255,255,255,255), 1, 0);
         Vertices[2] = video::S3DVertex(h,-w,0, 0,1,1, video::SColor(255,255,255,255), 0, 1);
         Vertices[3] = video::S3DVertex(h,w,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[i].Pos);

     //C++ computation of cos/sin/tan can be slow, so precompute values and
     //create a lookup table.
     for(int i = 0; i<360; i++){
        fsin[i]=(f32)sin((float)i);
        facos[i]=(f32)acos((float)i);
     }
		vUp = vector3df(0,1,0);
		mirrorNormal = vector3df(0,0,-1);
		vUp.rotateYZBy(getRotation().X, core::vector3df(0, 0, 0));
        vUp.rotateXZBy(-getRotation().Y, core::vector3df(0, 0, 0));
        vUp.rotateXYBy(getRotation().Z, core::vector3df(0, 0, 0));
		mirrorNormal.rotateYZBy(-getRotation().X, core::vector3df(0, 0, 0));
        mirrorNormal.rotateXZBy(getRotation().Y, core::vector3df(0, 0, 0));
        mirrorNormal.rotateXYBy(getRotation().Z, core::vector3df(0, 0, 0));
   }

   f32 acos_f(f32 deg)
   {
      // Fast computation of acos
      deg = (f32)fmodf(deg,360);
      if(deg<0)
         deg+=360;

      s32 deg_int = (s32)deg;
      f32 deg_frac = deg - deg_int;

      return(facos[deg_int] + deg_frac*(facos[deg_int+1] - facos[deg_int]));
   }

   f32 sin_f(f32 deg)
   {
      // Fast computation of sin
      deg = (f32)fmodf(deg,360);
      if(deg<0)
         deg+=360;

      s32 deg_int = (s32)deg;
      f32 deg_frac = deg - deg_int;

      return(fsin[deg_int] + deg_frac*(fsin[deg_int+1] - fsin[deg_int]));
   }

   virtual void render()
   {
     
      u16 indices[] = {       0,2,3, 2,1,3, 1,0,3, 2,0,1      };
       video::IVideoDriver* driver = SceneManager->getVideoDriver();
            
       driver->setMaterial(reflectMaterial);
       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() const
   {
      return 1;
   }

   virtual void OnRegisterSceneNode()
   {
      if (IsVisible)
         SceneManager->registerNodeForRendering(this);
   
      ISceneNode::OnRegisterSceneNode();
   }
   
   virtual video::SMaterial& getMaterial(u32 i)
   { 
      return reflectMaterial;
   }

   //Basic math functions, inlined because the call to the functions
   //take as much time as the functions themselves!
   inline irr::f32 len(core::vector3df v)  //vector length
   {
      return (irr::f32)sqrt((v.X * v.X) + (v.Y * v.Y) + (v.Z * v.Z));
   }

   inline irr::f32 len2(core::vector3df v,core::vector3df v2)  //Distance between
   {                                             //two vectors
      f32 dx = v.X - v2.X;
     f32 dy= v.Y -v2.Y;
     f32 dz= v.Z-v2.Z;
      return (irr::f32)sqrt((dx * dx) + (dy * dy) + (dz * dz));
   }
   
   
   inline irr::f32 acosd(irr::f32 input) //arc-cosine in degrees, uses f32 type (instead of "double")
   {                                     //Modified to use Fast acos instead of acos. Minute error rating
                                        //with a hit of speed.
      f32 value = acos_f(input) * 180.0f / 3.14159265358979f; //Converts from radians back to degrees
      return value;
   }

   inline 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 acosd(v1.dotProduct(v2) / (len(v1) * len(v2)));
      }
   }
   inline virtual void setRotation(const core::vector3df &newpos)
   {
		if(hasExtraTexture)
			cube->setRotation(newpos);
	   ISceneNode::setRotation(newpos);
	   vector3df rotate = getRotation();
		vUp = vector3df(0,1,0);
		 core::matrix4 m;
   m.setRotationDegrees(rotate);
		m.rotateVect(vUp);  
		// Get a vector on the surface of the mirror
         vector3df mirrorV1 = Vertices[0].Pos - Vertices[3].Pos;
         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));

         // Get another vector on the surface of the mirror
         vector3df mirrorV2 = Vertices[2].Pos - Vertices[1].Pos;
         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));

         // Use the above 2 vectors to find the mirror's Normal
         mirrorNormal = mirrorV1.crossProduct(mirrorV2);

         // Normalize the Normal (to a length of 1).
         mirrorNormal = mirrorNormal.normalize();

   }
   virtual void setPosition(const core::vector3df &v)
   {
	   if(hasExtraTexture)
		   cube->setPosition(v);
	   ISceneNode::setPosition(v);
   }
   virtual void setScale(const core::vector3df &v){
	   if(hasExtraTexture)
		   cube->setScale(vector3df(v.X,v.Y,0.01f));
	   ISceneNode::setScale(v);
   }
void rotateVectorAroundAxis(vector3df & vector, const vector3df & axis, f32 radians)
{
   quaternion MrQuaternion;
   matrix4 MrMatrix;
   (void)MrQuaternion.fromAngleAxis(radians, axis);
   MrQuaternion.getMatrix(MrMatrix);
   MrMatrix.rotateVect(vector);
} 
   void reflect() //Does everything required to reflect the image.
      {           //All put into one function to reduce funtion calls.
         f32 myAngle, dP;
         core::vector3df reflectionVector,
            sightVector;
         bool oldFrontSide;
         static bool frontSide = true;
         
         // Store the node's vector to the mirror
         sightVector = defaultCamera->getPosition()-getPosition();
         
         //check to see if this is the front of the mirror. This mirror is
         //one sided, do to the fact that in most games, mirrors will not be
         //floating in the middle of the air, but attached to another suface.
         //Also, mirror calculations can be stopped to increase FPS when you
         //dont need it.
         myAngle = angle(sightVector, mirrorNormal);
         oldFrontSide = frontSide;
         if (myAngle < 90)
            frontSide = false;
         else
            frontSide = true;
         video::IVideoDriver* driver = SceneManager->getVideoDriver();
         if (!frontSide)
         {
            driver->setRenderTarget(reflectTexture, true, true, video::SColor(0,0,0,0));
            driver->setRenderTarget(0);
            return;
         }
		
		//plane3df mirrorplane = plane3df(vector3df(0,0,0),mirrorNormal);

         // Calculate the "dot product" - used to find the reflection
         //vector below
         dP = 2.0f * mirrorNormal.dotProduct(sightVector);
         // Standard formula for a reflection vector!
         reflectionVector = core::vector3df(dP, dP, dP) * mirrorNormal - sightVector;
         //Set the lenght of the reflection vector to the length of
         //the matching sight vector. Used in camera placement.
         reflectionVector.setLength(len(sightVector));

         //This flips the image, so if the user flips the mirror vertically,
         //it still shows the ground on the bottom
         if (getRotation().X > 90.0f)
            setRotation(core::vector3df(getRotation().X - 180.0f, getRotation().Y, getRotation().Z));
         if (getRotation().X < -90.0f)
            setRotation(core::vector3df(getRotation().X + 180.0f, getRotation().Y, getRotation().Z));
            
         //Uses the mirror position and the reflection vector
         //to place the camera.

         //get half the length between the 2 cameras to find
         //the near clipping plane.
         f32 length2 = len2(defaultCamera->getPosition(),
            reflectCamera->getPosition())/2;

         //create_glfrustumLH creates the view frustum from the camera to the
         //mirror (remeber reflection camera is actually pointing to the
         //original camera) But create_glfrustumLH requires fixing.
		 vector3df f = vector3df(0,1,0);
		 // Fix for rot on Z axis
		 //xfactor*=cos(getRotation().Z); //Zrot=0, then factor*1, to |Zrot|=90, factor*-1 
		 //yfactor*=asin(getRotation().Z); 
         reflectCamera->setPosition(getPosition()-reflectionVector);
         reflectCamera->setUpVector(vUp);

         //Target the default camera.
         reflectCamera->setTarget(defaultCamera->getPosition());

         //Rotate the reflection vector to offset the rotation to the
         //reflection camera. (Note: The X axis is negitive here)
		 //f.rotateXYBy(-getRotation().Z, core::vector3df(0, 0, 0));
		 //vector3df rotate = getRotation();
		 vector3df forward = vector3df(0,0,1);
		 vector3df up = vector3df(0,1,0);
		 vector3df right = vector3df(1,0,0);
		 rotateVectorAroundAxis(reflectionVector, right, DEGTORAD*-getRotation().X);
		 rotateVectorAroundAxis(up, right, DEGTORAD*-getRotation().X);
		 rotateVectorAroundAxis(forward, right, DEGTORAD*-getRotation().X);

		 rotateVectorAroundAxis(reflectionVector, up, DEGTORAD*-getRotation().Y);
		 rotateVectorAroundAxis(forward, up, DEGTORAD*-getRotation().Y);

		 rotateVectorAroundAxis(reflectionVector, forward, DEGTORAD*-getRotation().Z);


         //reflectionVector.rotateYZBy(-rotate.X-(rotate.Y/.5f)*(rotate.X/45), core::vector3df(0, 0, 0));
         //reflectionVector.rotateXZBy(rotate.Y-(rotate.X/.5f)*(rotate.Y/45), core::vector3df(0, 0, 0));
         //reflectionVector.rotateXYBy(-rotate.Z, core::vector3df(0, 0, 0));
         
		 f32 yfactor = -.5f;//*(f.Y);
		 f32 xfactor = .5f;//-.5;//*(f.Y);

         //Create the view frustum. w= half the width of the mirror. For scalability,
         // times this by getScale().X. for H, multiply it by getScale().Y.
         // reflecionVector is the center of the mirror from the camera.
         reflectCamera->setProjectionMatrix(create_glfrustumLH((reflectionVector.X*xfactor-
            (w/2*getScale().X)),(reflectionVector.X*xfactor+(w/2*getScale().X))
            ,reflectionVector.Y*yfactor-(h/2*getScale().Y),
            reflectionVector.Y*yfactor+(h/2*getScale().Y),length2/2,
            defaultCamera->getFarValue()));
         
         //Set the up vector for the camera.
		 if(hasExtraTexture)
			 cube->setVisible(false);
      
         //render the image onto the mirror.
         driver->setRenderTarget(reflectTexture, true, true, video::SColor(0,0,0,255)); // set render target texture (the mirror's texture)
         this->setVisible(false); // make mirror invisible (so it doesn't get painted over)
         SceneManager->setActiveCamera(reflectCamera); // set fixed camera as active camera
         SceneManager->drawAll(); // draw whole scene into render buffer

		 if(hasExtraTexture)
			 cube->setVisible(true);
         //Reset everything
         driver->setRenderTarget(0); // set back old render target
         this->setVisible(true); // make the mirror visible again
         SceneManager->setActiveCamera(defaultCamera);
   }

   // function used to create the view matrix. Provided by FreakNigh.
   matrix4 create_glfrustumLH(f32 left, f32 right, f32 bottom, f32 top, f32 nearZ, f32 farZ)
   {
      f32 x = (2.0F*nearZ) / (right-left);
      f32 y = (2.0F*nearZ) / (top-bottom);
      f32 a = (right+left) / (right-left);
      f32 b = (top+bottom) / (top-bottom);
      f32 c = -(farZ+nearZ) / ( farZ-nearZ);
      f32 d = -(2.0F*farZ*nearZ) / (farZ-nearZ);

      matrix4 m;
      m.makeIdentity();
   #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;
   }

}; 
To use the mirror class:

Code: Select all

	cMirror * mirror = new cMirror(smgr->getRootSceneNode(), smgr, 999, device, cam, driver->getTexture("../media/mirrordirt.png"));
	
	mirror->setPosition(vector3df(0,0,15.001f));
	mirror->setRotation(vector3df(0,0,0));
	mirror->setScale(vector3df(1,2,0));//scaling z does nothing.

Code: Select all

//main loop
	while (device->run())
	{
		driver->beginScene(true, true, 0);
		mirror->reflect();
		smgr->drawAll();
		env->drawAll();
		driver->endScene();
	}
Oh, and please dont ask me about helping me with my game. I mainly prefer to work alone, as Ive been ____ over too many times.


*EDIT*
I updated the code above, it now does indeed allow for a second overlay texture. (Didn't use a custom material render, should work for all drivers that allow Alpha textures.) Also, the mirror now returns PERFECT reflections... so long as you dont modify more than one axis on the rotations.... Ive been trying to figure out the calculations to offset the different axis rotations that mess each other up... if someone can figure it out before I do, please let us know.
Last edited by shadowking97 on Tue Mar 10, 2009 11:11 pm, edited 2 times in total.
shadowking97
Posts: 8
Joined: Mon Mar 09, 2009 5:55 am
Location: TX

Post by shadowking97 »

I edited the above code again... To create the projection matrix, you had to off set the mirror rotation, which I had been trying to do, but I found a way to store a local axis to rotate the projection vector. The local axis is updated as the vector is being rotated, which was the problem all along. It now shows perfect reflections from all angles/rotations. Objects behind the mirror are clipped, so no worries there either. Constuctor was also updated to require the default camera, as it freaks out with more than one mirror with out that setting. Next thing on my list is getting 2 mirrors to reflect each other correctly...
Image created with the updated mirror code above:
Image
shadowking97
Posts: 8
Joined: Mon Mar 09, 2009 5:55 am
Location: TX

Post by shadowking97 »

I cleaned up the code a little bit, and split the class into a .cpp/.h combo.
Download Source
From what I can tell so far:
Reflections good (perfect?) from any angle/rotation
Overlay should work on any device that supports transparent textures.
Texture should have alpha channel.
Everything behind the mirror plane is clipped
The up vector and mirror normal is now calculated only on mirror rotation, to improve FPS when its not moving.
Used only irrlicht types, code should be portable.

If anyone has any problems, please let me know!


All you need:

Code: Select all

#include "cMirror.h"

Code: Select all

cMirror * mirror = new cMirror(smgr->getRootSceneNode(), smgr, 999, device, cam, driver->getTexture( "../media/mirrordirt.png"));
//cMirror * mirror = new cMirror(smgr->getRootSceneNode(), smgr, 999, device, cam);
mirror->setPosition(vector3df(0,-30,30.f));
mirror->setRotation(vector3df(0,0,0));
mirror->setScale(vector3df(1,2,0));

Code: Select all

mirror->reflect();
Happy reflecting!

*Edit*
Seems to be relatively fast, fullscreen without the mirror my FPS is around 220, but when i add 1 mirror (and im in front of it) it drops down only to around 200. (My scene is just a skybox, a cube and the mirror with an overlay texture).
shadowking97
Posts: 8
Joined: Mon Mar 09, 2009 5:55 am
Location: TX

Post by shadowking97 »

OpenGL Fix:

Change:

Code: Select all

      if (driver->getDriverType() == video::EDT_OPENGL)
      {
         //EDT_OPENGL requires we flip the image vertically
         Vertices[0] = video::S3DVertex(-h,w,0, 1,1,0, video::SColor(255,255,255,255), 0, 1);
         Vertices[1] = video::S3DVertex(-h,-w,0, 1,0,0, video::SColor(255,255,255,255), 0, 0);
         Vertices[2] = video::S3DVertex(h,w,0, 0,1,1, video::SColor(255,255,255,255), 1, 1);
         Vertices[3] = video::S3DVertex(h,-w,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(-h,-w,0, 1,1,0, video::SColor(255,255,255,255), 1, 1);
         Vertices[1] = video::S3DVertex(-h,w,0, 1,0,0, video::SColor(255,255,255,255), 1, 0);
         Vertices[2] = video::S3DVertex(h,-w,0, 0,1,1, video::SColor(255,255,255,255), 0, 1);
         Vertices[3] = video::S3DVertex(h,w,0, 0,0,1, video::SColor(255,255,255,255), 0, 0);
      }
to:

Code: Select all

         Vertices[0] = video::S3DVertex(-h,-w,0, 1,1,0, video::SColor(255,255,255,255), 1, 1);
         Vertices[1] = video::S3DVertex(-h,w,0, 1,0,0, video::SColor(255,255,255,255), 1, 0);
         Vertices[2] = video::S3DVertex(h,-w,0, 0,1,1, video::SColor(255,255,255,255), 0, 1);
         Vertices[3] = video::S3DVertex(h,w,0, 0,0,1, video::SColor(255,255,255,255), 0, 0);

DirectX bug (Render to target):
Z clipping is incorrect: put 2 objects partially inside each other, in the mirror, one object overlapped the other. Switched to OpenGL and it was fine.
Steel Style
Posts: 168
Joined: Sun Feb 04, 2007 3:30 pm
Location: France

Post by Steel Style »

That's seem to be a good work shadowking97 congratulations, I think that it's might be better if you also add un executable on you rar file.
shadowking97
Posts: 8
Joined: Mon Mar 09, 2009 5:55 am
Location: TX

Post by shadowking97 »

Ok, I modified the zip file. It uses the Quake map tutorial. (dont mind that the exe is called hello world, for some reason those got mixed up in my irrlicht 1.5) The exe is in the release folder, but if you dont have VC 9, im not sure if itll work on your computer... its given me trouble in the past... But the source for the project is there, so just add those files and link in the .lib and irrlicht.h and you should be fine...

Also,I modified the source to what i remember is the correct format... (irrlicht types only, first letter upper case for globals, lower case for locals)

It works fine in direct x 9 and open gl, but the others seem to mess up. It technically works in burnings video, but incredibly slow... FPS~4. Im not sure if thats because of the quake map, or the mirror...

Moving behind the mirror disables it. I also added an overlay to the mirror, just a fractal generated in gimp, but it does its job. The mirror is right in front of the camera spawn point, so you can move around to see it.


DO NOT PUT TWO MIRRORS IN FRONT OF EACH OTHER. I stress this because the mirrors would reflect the reflection for the camera (or just black if the camera is behind the other mirror) and it creates some very odd reflections.

Quake cMirror
Steel Style
Posts: 168
Joined: Sun Feb 04, 2007 3:30 pm
Location: France

Post by Steel Style »

Realy good work and a little performance loss.
Vandrick
Posts: 13
Joined: Sat Feb 21, 2009 5:37 am

Post by Vandrick »

Thanks for the mirrors they are very nice.
Image
shadowking97
Posts: 8
Joined: Mon Mar 09, 2009 5:55 am
Location: TX

Post by shadowking97 »

Well... I managed to make an upgrade again.... I'm not posting the upgrade until I have a chance to clean it/see what more I can do to optimize it... But here is basically the upgrade: Progressive reflection to infinity. The mirrors can now reflect each other! Thanks to code I found made by blindside in a bug report 4 years ago... The mirrors can check to see if they are out of the view frustum of the camera and abort the entire process.

You have to link mirrors up together before they will reflect each other correctly, and there is a hard limit of 6 mirrors you can link together (first mirror and 5 that can reflect it), and that is overkill.
mirror1->linkWith(mirror2); //no need to call mirror2->linkWith(mirror1) as the link is both ways.

Reflections of reflections do take up processing power: By adding 2 mirrors and linking them together so they can reflect dropped my FPS from around 300 to 120. (~90 if both mirrors are visible.)

mirror->reflect(); has been changed to mirror->cast(); The reflect function is still there, but cast checks if the mirror is clipped, calls the reflection of the opposing mirrors (if any), then the reflection of this mirror. So, even if that mirror cant reflect any other mirrors, it still checks the view frustum.

Anyway, here is a screen shot:
Image
bitplane
Admin
Posts: 3204
Joined: Mon Mar 28, 2005 3:45 am
Location: England
Contact:

Post by bitplane »

Wow really cool. One question - how come you have to render the reflection of a reflection? Wouldn't it make more sense to to just show the previous frame and accept a lag of one frame in a reflection?
Submit bugs/patches to the tracker!
Need help right now? Visit the chat room
shadowking97
Posts: 8
Joined: Mon Mar 09, 2009 5:55 am
Location: TX

Post by shadowking97 »

One reflection is for the other mirror, that needs to be updated per frame as well(it sees the reflection of the other mirror from the previous frame), then you need to render the reflection that shows the other reflection.


I am getting an odd bug...
If both mirrors are in view, need to set it so it goes reflect() other->reflect2() reflect(). Otherwise the mirrors go black... no matter if i take off the first reflect or the second. and I cant figure out why because reflect() modifies one render to texture, and reflect2() modifies another... If i could get rid of one of those reflects it would jump up the frame rate for the two mirrors to around 150 with both of them in the shot...
*edit*NVM, fixed it. I needed the set location of the reflection camera from the first reflect, so i took that part out of the reflect function and put it in the cast function. Now its (updateCamPosition) other->reflect() reflect()


There was another method I tried once, where it just stored the pixel data of each frame for its own reflection to the camera, it worked, but it slowed the frame per second down to 4...
detvog
Posts: 19
Joined: Sun Mar 02, 2008 8:49 am

Hi

Post by detvog »

can anyone make a new download link for the source ?
shadowslair
Posts: 758
Joined: Mon Mar 31, 2008 3:32 pm
Location: Bulgaria

Post by shadowslair »

The source is in the post on the top of this page?! I can make an archive and upload it somewhere if you insist on downloading it. :roll:
"Although we walk on the ground and step in the mud... our dreams and endeavors reach the immense skies..."
slavik262
Posts: 753
Joined: Sun Nov 22, 2009 9:25 pm
Location: Wisconsin, USA

Post by slavik262 »

Except now it's been changed multiple times. An updated link would be nice.
detvog
Posts: 19
Joined: Sun Mar 02, 2008 8:49 am

Post by detvog »

shadowslair wrote:The source is in the post on the top of this page?! I can make an archive and upload it somewhere if you insist on downloading it. :roll:

Can you make this? The links are broken..rapidshare......
Post Reply