About Store Forum Documentation Contact



Post Reply 
Render to texture mirrors
Author Message
b1s Offline
Member

Post: #1
Render to texture mirrors
Here is a quick way to do mirrors from the render to texture tutorial
There is still room to improve, but for me this was enough.

If anyone finds a way to do this better then please share.
In our project I also used several systems to optimize this like:
-Not rendering the mirror every frame
-Only rendering the realtime image on first lod
-Changing the resolution and other settings from the image according to games detail settings

and maybe there was some other stuff too but I left them out from this small tutorial.

Here is the mirror.obj with mesh and textures
Mirror.rar

Drop this folder to obj folder and in game press "M"
button to spawn mirrors.
Let me know if there are any questions.


PHP Code:
/******************************************************************************/
#include "stdafx.h"
#include "../../../../../data/enum/_enums.h"
/******************************************************************************/
//One Way to do a render to texture mirror. It's not 100% correct but pretty close
//Feel free to edit the code and try to fix any issues you might be able to solve.
/******************************************************************************/
Viewport    viewport[2];
Camera        camera  [2];
Flt            mirrorCamDist;
Vec2        fov;
Mesh        box ,
            
ball;
Image        rtt // Render Target Tetxture (of IMAGE_RT mode)
MaterialPtr mirrorMat;
bool        mirrorInRange true;
Camera        desired_camera// create a helper desired camera

/******************************************************************************/
// Player
/******************************************************************************/
STRUCT(Player Game::Chr)
//{
   
virtual Bool update();
};
/******************************************************************************/
// MIRROR
/******************************************************************************/
struct MirrorObject Game::Static // Extend
{

   
virtual void create     (Game::ObjParams &obj); // extend creation to include accessing item type
   
virtual Bool update     (                    ); // extend updating to include bomb explosion, and 'mesh_overlay' update
   
virtual UInt drawPrepare(                    ); // extend drawing  to include request for the RM_OVERLAY mode

   // io
   
virtual void save(File &f); // extend saving  to include members saving
   
virtual Bool load(File &f); // extend loading to include members loading

   
MirrorObject();
};
/******************************************************************************/
Game::ObjMemx<MirrorObjectMirrors;
Game::ObjMemx<      PlayerPlayers;
/******************************************************************************/
/******************************************************************************/
Bool Player::update()
{
   if(
action)
   {
      if(
Kb.b(KB_W) || Kb.b(KB_S) || Kb.b(KB_A) || Kb.b(KB_D) || Kb.b(KB_Q) || Kb.b(KB_E))actionBreak();
   }

   if(!
action)
   {
      
// turn & move
      
input.turn.x=Kb.b(KB_Q)-Kb.b(KB_E);
      
input.turn.y=Kb.b(KB_T)-Kb.b(KB_G);
      
input.move.x=Kb.b(KB_D)-Kb.b(KB_A);
      
input.move.z=Kb.b(KB_W)-Kb.b(KB_S);
      
input.move.y=Kb.b(KB_SPACE)-Kb.b(KB_LSHIFT);

      
// dodge, crouch, walk, jump
      
input.dodge Kb.bd(KB_D)-Kb.bd(KB_A);
      
input.crouchKb.(KB_LSHIFT);
      
input.walk  Kb.(KB_LCTRL );
      
input.jump  =(Kb.bp(KB_SPACE ) ? 3.5f 0);
   }
   return 
super::update();
}


/******************************************************************************/
// MIRROR
/******************************************************************************/
MirrorObject::MirrorObject()
{
 
}
/******************************************************************************/
void MirrorObject::create(Game::ObjParams &obj)
{
    
super::create(obj);
    
    
//Change the diffuse for mirrrors material to the rtt image
    
this->mesh->parts[0].material()->base_0 = &rtt// draw texture
    
this->mesh->parts[0].material()->validate();
}
/******************************************************************************/
Bool MirrorObject::update()
{
    return 
__super::update();
}
/******************************************************************************/
UInt MirrorObject::drawPrepare()
{
    
Matrix matrix=matrixScaled();
    if(
Frustum(mesh->boxmatrix))
    {
        
mirrorInRange true;                                    //Render the mirror image
        
        
Matrix mirrorMatrix desired_camera.matrix;            //Create a mirrorMatrix    and use desired_camera.matrix for its base
        
Vec cameraTarget desired_camera.matrix.pos;            //target pos
        
cameraTarget Mirror(mirrorMatrix.pos,pos(),matrix.x); //mirror camera target on x axis
        
cameraTarget Mirror(cameraTarget,pos(),Vec(0,1,0));    //mirror camera target on world up axis
        
Vec cameraPos desired_camera.matrix.pos;                //camera pos
        
cameraPos Mirror(mirrorMatrix.pos,pos(),this->matrix().z); //mirror camera pos on z axis
        
camera[1].setFromAt(cameraPos-matrix.z,pos());            //set mirror cameras position and target
        
        
Flt CamDist Dist(camera[1].at,camera[1].matrix.pos);    //Check distance between camera pos and target
        //Calculate the fov angles accoring to width and height of the actor box and camera distance
        
Flt a = (actor.box().w()/2)/CamDist;fov.Tan(a)*2
        
Flt b = (actor.box().h()/2)/CamDist;fov.Tan(b)*2;
        
mirrorCamDist CamDist;                                //set the distance for clipping
        
        //Draw mesh normally
        
MaterialLock=material(); mesh->draw(matrix);
        
MaterialLock=NULL;
        return 
true;
    }else return 
false;
}
/******************************************************************************/
void MirrorObject::save(File &f)
{
   
super::save(f);
}
Bool MirrorObject::load(File &f)
{
   if(
super::load(f))
   {
        
this->mesh->parts[0].material()->base_0 = &rtt// draw texture
        
this->mesh->parts[0].material()->validate();
   }
   return 
false;
}

//Just creating a mirror object and mesh
void createMirror()
{
    
Game::ObjParams &obj=*Game::Objs("obj/mirror/0.obj");                                  // get barrel object parameters
    
Game::Obj *tmpObj Game::World.objCreateNear(obj,Matrix(obj.scale(),Players[0].pos()-Vec(0,0,1))); // create new object at (16,8,16) position and give objects default scaling
}
/******************************************************************************/
// MAIN
/******************************************************************************/
void InitPre()
{
   
App.name("Camera Collisions");
   
App.flag=APP_MS_EXCLUSIVE|APP_FULL_TOGGLE;
   
DataPath("../data");
   
Paks.add("engine.pak");

   
D.full(true).sync(true).ambPower(0.3f).hpRt(true);
}
/******************************************************************************/
Bool Init()
{
    
// initialize cameras
    
camera[0].setSpherical(Vec(0,0,0), 0003);
    
camera[1].setSpherical(Vec(0,0,0), 0003);

    
Physics.create(CSS_NONE,true,"../Installation/PhysX");
    
Sky    .atmospheric();
    
Sun.image=Images("gfx/sky/sun.gfx"); Sun.light_color=1-D.ambColor();

    
// create the world
    
Game::World.init()
          .
setObjType(Mirrors,OBJ_STATIC//Use mirrors instead of static objects
          
.setObjType(Players,OBJ_PLAYER)
          .New(
"world/sample.world");


    return 
true;
}
/******************************************************************************/
void Shut()
{
}

void UpdateCamera()
{
    
//I used third person camera from the camera collision tutorial
    
if(Players.elms())
    {
      
// first setup the desired camera as in the previous tutorials
      
desired_camera.yaw  -=Ms.d().x;         // update camera yaw   angle according to mouse delta x
      
desired_camera.pitch+=Ms.d().y;         // update camera pitch angle according to mouse delta y
      
Clamp(desired_camera.pitch,-PI_2,PI_4); // clamp to possible camera pitch angle
      
desired_camera.dist=Max(1.0f,desired_camera.dist*ScaleFactor(Ms.wheel()*-0.2f)); // update camera distance according to mouse wheel
      
desired_camera.at  =Players[0].pos();
      
desired_camera.setSpherical(); // set as spherical from current values, this will set the camera's matrix (desired_camera.matrix)

      // now what we'll do is cast a small sized Ball from starting position to target camera destination
      // we'll stop the ball at first contact point, and set camera at that place

      // create a helper ball which will be used for collision detection
      
Ball ball(0.1fdesired_camera.at); // we place it at starting point (where the camera is looking at)

      // now we'll move the ball in the direction where the camera should be
      
Physics.move(balldesired_camera.matrix.pos-ball.pos); // use physics movement to move the ball as far as it can go without any collisions

      // now the ball.pos is located at either maximum movement distance or at nearest collision point
      // having ball's position we can now set the final camera position
      
camera[0].setPosDir(ball.posdesired_camera.matrix.zdesired_camera.matrix.y); // we'll use 'desired_camera.matrix' directions which were set in 'setSpherical' camera method

      
camera[0].updateVelocities().set(); // update camera velocities and activate it
    
}
}

/******************************************************************************/
Bool Update()
{
    
Game::World.update(Cam.at);
    
UpdateCamera();


    if(
Kb.bp(KB_M)) // on space
        
createMirror(); //Create the mirror to the sample world

    
if(Kb.bp(KB_ESC))return false;
    return 
true;
}
/******************************************************************************/
void Render()
{
    
Game::World.draw(); //draw world
}
void RenderToTexture()
{
   
Int tex_size=256;  //Texture size
   
camera[1].set(); //Enable secondary camera used for mirrors
   
Flt tmpFov D.viewFov(); // remember old fov before rendering
   
D.viewFrom(mirrorCamDist+0.1); //change viewport clipping accoring to distance. add a little extra just incase.
   
D.viewFov(fov.x,FOV_X); //get fov from object calculations
   
D.viewFov(fov.y,FOV_Y); //get fov from object calculations
   // create the Render Target Texture if it hasn't been created yet
   
if(!rtt.is())rtt.create(tex_size,tex_size,1,IMAGE_B8G8R8A8,IMAGE_RT,1);
   
// render to texture
   
Bool super_sample=false;                                              // optionally use super sampling to enable anti-aliasing at the cost of greater viewport size
   
Int  render_size =Min(D.x(), D.y(), tex_size*(super_sample 1)); // calculate rendering viewport size
   
D.viewRect(&RectI(0,0,render_size,render_size));                      // set new viewport
   
Renderer.dest_rt=&rtt;                                                 // specify custom render target
   
Renderer(Render);                                                     // perform rendering
   
Renderer.dest_rt=NULL;                                                // disable custom render target
   
D.viewRect(NULL);                                                     // Restore full viewport
   
D.viewFrom(0.01f);                                                     // Restore clipping
   
D.viewFov(tmpFov);                                                     // Restore fov
   
camera[0].set();                                                         //Restore main camera
}
/******************************************************************************/
void Draw()
{
    
//*********************Mirrors in game*****************************///
    
    
RenderToTexture();    //Render to texture
    
mirrorInRange false;  //restore range check
    //*********************Mirrors in game*****************************///

    // render normally
    
Renderer(Render);

}
/******************************************************************************/ 
(This post was last modified: 07-22-2011 11:27 AM by b1s.)
07-22-2011 11:27 AM
Find all posts by this user Quote this message in a reply
Driklyn Offline
Member

Post: #2
RE: Render to texture mirrors
Cool! Thanks for sharing... smile

Any chance of an in-game screenshot so we can have an idea of how the effect will look?
07-22-2011 06:52 PM
Find all posts by this user Quote this message in a reply
Harry Offline
Member

Post: #3
RE: Render to texture mirrors
I've checked it and its great grin Almost like Realtime Reflections added in DX11 update in Crysis 2 grin First thing which come to my mind is to change teleports in Ineisis with mirrors from another teleport. It could be possible, am I right?
07-22-2011 09:45 PM
Visit this user's website Find all posts by this user Quote this message in a reply
b1s Offline
Member

Post: #4
RE: Render to texture mirrors
Yeah.. I accidently made that already while making this one. It was a pretty cool effect.
Kinda like walking into a painting.
07-25-2011 11:07 AM
Find all posts by this user Quote this message in a reply
Grabonito Offline
Member

Post: #5
RE: Render to texture mirrors
Great effect ! Thanks.
(This post was last modified: 10-10-2011 10:26 AM by Grabonito.)
10-10-2011 10:25 AM
Find all posts by this user Quote this message in a reply
llynx Offline
Member

Post: #6
RE: Render to texture mirrors
Couldn't you effectively render a 180 degree fov viewport to the reflection map of an object and have pseudo realistic reflections?
10-10-2011 11:03 PM
Find all posts by this user Quote this message in a reply
Post Reply