LensFlare in SW renderer

Started by brianbaillargeon, August 14, 2010, 05:57:39 AM

Previous topic - Next topic

brianbaillargeon

Hi,

I've been tinkering around with JPCT this summer, I'm working on something like the game Portal from Valve. These have nothing to do with the Portals class in JPCT. The portals I'm making are like holes in the wall, but when you look into one, you see out of another portal. I've got some portals appearing properly, but they lag quite a bit and I can only get them to work in the SW renderer, but that's okay. If anybody asks, I can explain what I did.

My problem is with LensFlares. When I make a LensFlare in the SW renderer, I just see white patches. I've tried the GL renderer and the LensFlare was beautiful, but I need to use the SW renderer for these portals to work. Is there a way to get LensFlares to work properly with the SW renderer?

I can provide screenshots or code excerpts upon request.

zammbi

QuoteI've got some portals appearing properly, but they lag quite a bit and I can only get them to work in the SW renderer, but that's okay. If anybody asks, I can explain what I did.
I wouldn't mind knowing, just in case I need to make a similar effect in my rpg. Who knows someone here could explain how to make it faster.

EgonOlsen

I don't see a reason why it shouldn't work in sw renderer. A screen shot would be nice.

brianbaillargeon

Okay, I'll explain.

I'm combining some 2D java.awt ideas with JPCT, so my display() method looks like this:

private void display() {

   //create an image which is drawn in the Frame later
        //frame is declared as a java.awt.Frame. width and height are the dimensions of the frame.
    Image im=frame.createImage(width,height);
    Graphics g=im.getGraphics();
   
    //draws the world using the software renderer
        buffer.display(g, leftBorderWidth, titleBarHeight);

        /*here I did a selection sort of the portals in the order of their distance from the camera,
        but that's rigorous info I can leave out*/

        /*draws the portals. The 'portals' variable is declared as java.util.LinkedList<Portal> portals,
        and the Portal class is shown below*/
        for (int i=0;i<portals.size();i++)
        {
        Portal current=portals.get(i);
                //We don't want to draw portals if we're miles away, so we get the distance to 'current'
        SimpleVector camToPortal=current.structure.getTransformedCenter();
        camToPortal.sub(camera.getPosition());
        if (camToPortal.length()<PORTAL_DISCARD_DISTANCE)
        {
                        /*just plain ol' java.awt. Any objects in the foreground that could get in front of the portal
                        could probably be put in another World object, which we could render after the portals are drawn*/
        Polygon p=current.getPolygon();
        g.setClip(p);
        g.drawImage(current.getImage(),0,0,frame);
        }
        }
        gFrame.drawImage(im,0,0,frame);
   
  }


And this is my Portal class:

import com.threed.jpct.*;
import java.awt.*;
public class Portal{
       //An Object3D representing the portal, but we never add it to the world.
Object3D structure;
       //The portal that this portal leads to
Portal dest=null;
       //Used to manipulate coordinates of the vertices in the portal's polygons.
GenVertContr gvc=new GenVertContr();
       //The coordinates of the vertices in the portal's polygons
SimpleVector []threeDs=null;
       //the angles that this portal is rotated about the x, y, and z axes.
float dx=0;
float dy=0;
float dz=0;

       //x,y,z are the coordinates. dx, dy, and dz are the angles that the portals is rotated about the x, y, and z axes.
public Portal(float x, float y, float z, float dx, float dy, float dz)
{
           //I would load the structure once, and I'd clone that structure for every new portal.
           //But this will work too.
           structure=Loader.load3DS("Portal.3ds", 10);
   if (objs.length>0)
   {
    structure=objs[0];
    for (int i=1;i<objs.length;i++)
    {
    structure=Object3D.mergeObjects(portalObj, objs[i]);
    }
   }
   structure.enableLazyTransformations();
//if you're taking the cloning approach, you'd have to clone the mesh as well before the next line
structure.getMesh().setVertexController(gvc, true);
               //place the portal
structure.translate(x,y,z);
               //rotate the portal. I forget why, but structure.rotateX() rotateY() and rotateZ() yield different results.
structure.rotateAxis(new SimpleVector(1,0,0), dx);
structure.rotateAxis(new SimpleVector(0,1,0), dy);
structure.rotateAxis(new SimpleVector(0,0,1),dz);

this.dx=dx;
this.dy=dy;
this.dz=dz;

               //get the coordinates of the vertices, and place them to where they would be in the world.
threeDs=gvc.getSourceMesh();
for (int i=0;i<gvc.getMeshSize();i++)
{
threeDs[i].rotate(structure.getRotationMatrix());
threeDs[i].add(structure.getTransformedCenter());
}
}

       //Links two portals together.
public void setDest(Portal dest)
{
this.dest=dest;

//sometimes we might not want this to be the case, but usually we will.
dest.dest=this;
}

       //Here's the tricky part. Getting the image of what the other portal's seeing
public Image getImage()
{
               /*Before we go any further, take note that the class that has display(),
               and it has the World, the Frame, the FrameBuffer etc is called Main*/

Image im=Main.frame.createImage(Main.frame.getWidth(),Main.frame.getHeight());
Graphics g=im.getGraphics();


//Hang on to your head
Camera cam=Main.world.getCamera();

               //Climb out of your head and see the world from the dest portal's eyes
Main.world.newCamera();
Camera newCam=Main.world.getCamera();
               //the core geometry
SimpleVector camToSrc=structure.getTransformedCenter().calcSub(cam.getPosition());
camToSrc.rotateX(dx-dest.dx);
camToSrc.rotateY(dest.dy-dy);
newCam.setPosition(dest.structure.getTransformedCenter().calcSub(camToSrc));
SimpleVector lookAt=cam.getDirection();
lookAt.rotateX(dx-dest.dx);
lookAt.rotateY(dest.dy-dy);
lookAt.add(newCam.getPosition());
newCam.lookAt(lookAt);
newCam.rotateCameraZ(dest.dz-dz);

//draw the world from dest's view into im's graphics instance.
Main.buffer.clear(Main.skyColor);
Main.world.renderScene(Main.buffer);
Main.world.draw(Main.buffer);
Main.buffer.update();
Main.buffer.display(g, Main.leftBorderWidth, Main.titleBarHeight);

               //don't forget to climb back into your own head
Main.world.setCameraTo(cam);

               //we've got what we need
return im;
}

public Polygon getPolygon()
{
Polygon p=new Polygon();
addPoint(p,0);
addPoint(p,2);
addPoint(p,12);
addPoint(p,14);
               /*... there were 98 of these, and they're not in any particular order.
               I found some way to number all the vertices and draw them in another frame, then I could see where each point is,
               and which order they would need to be added in order to create a non-self-intersecting polygon*/

return p;
}

private void addPoint(Polygon p,int index)
{
try
{
SimpleVector twoD=Interact2D.project3D2D(Main.camera, Main.buffer, threeDs[index]);
p.addPoint((int)twoD.x, (int)twoD.y);
}
catch(NullPointerException e)
{

}
catch(ArrayIndexOutOfBoundsException e)
{

}
}
public class GenVertContr extends GenericVertexController
{

@Override
public void apply() {

}

}
}


Any questions? I hope that wasn't too rigorous.

brianbaillargeon

Okay, I uploaded a screenshot on my website.



The burst you see behind the white patches isn't from the LensFlare, that's a Primitives.getPlane with a texture I made.
Everything with the LensFlare is stolen from the Terrain project I came across on this forum.
So we have this stuff:
texMan.addTexture("burst",new Texture("lens1.jpg",true));
texMan.addTexture("halo0",new Texture("lens2.jpg",true));
texMan.addTexture("halo1",new Texture("lens3.jpg",true));
texMan.addTexture("halo2",new Texture("lens4.jpg",true));
sunFlare=new LensFlare(sunSmudge.getTransformedCenter(),"burst","halo0","halo1","halo2");
sunFlare.setTransparency(12);

EgonOlsen

Just decrease the transparency value from 12 to 0, 1 or 2. That should help. Software rendering differs from hardware a little in this aspect.

brianbaillargeon

Ah, brilliant. I tried a bunch of things, but it never occurred to me to change the transparency. LensFlare.setTransparency(0) looks good.

Now, I've been curious - if you want fog to affect terrain, but you also have a distant object like a sun that you don't want to be affected by the fog, what do you do? My idea is to have one world that includes the terrain with fog enabled, and a separate world that includes the sun with fog disabled. I haven't tested if that works. Any thoughts?

EgonOlsen

Yes, that's basically what i did in the terrain demo too, IIRC. When combining the software renderer with fog, have a look at Object3D.setDepthBufferWrites(<boolean>);. Also make sure that you are using all your cpu's core for rendering with the software renderer to get maximum performance: http://www.jpct.net/wiki/index.php/Multithreading

brianbaillargeon