PickPolygon reporting nothing

Started by cyberkilla, February 08, 2007, 10:51:37 PM

Previous topic - Next topic

cyberkilla

I am getting nothing from pickPolygon in some circumstances.

In the render loop, I try it just after the scene is rendered/drawn/displayed to framebuffer. It works!

Still inside render loop, but before rendering, I very rarely get anything from it.

I do use multiple cameras, and multiple framebuffers.
I am certain it is because of this.
I have tried setting the world to the active camera, and even rendering the scene again, before pickPolygon, but no luck:)

Just incase it is obvious to someone..

public synchronized Object3D getObjectAtCursor(int x,int y,RenderPane renderPane)
{
Camera      camera      = renderPane.camera;
FrameBuffer frameBuffer = renderPane.frameBuffer;


world.setCameraTo(camera);
world.renderScene(frameBuffer);
//world.draw(frameBuffer);

SimpleVector td  = Interact2D.reproject2D3D(camera,frameBuffer,x,y);
int[]        res = Interact2D.pickPolygon(
world.getVisibilityList(),td,
Interact2D.EXCLUDE_NOT_SELECTABLE);
if (res == null)
return null;
//Never gets past here,outside of paintComponent().

Object3D obj = world.getObject(Interact2D.getObjectID(res));

return obj;
}
http://futurerp.net - Text Based MMORPG
http://beta.rpwar.com - 3D Isometric MMORPG

EgonOlsen

You need a valid VisLIst for using pickPolygon, i.e. one that represents the currently visible frame. If you do the picking in thread a and the drawing (i.e. the implicit creation of the VisList) in thread b (aka in paintComponent), you'll get random results depending on the current state of the VisList, which can be anything between empty and full. Could that  be the problem here?

cyberkilla

Yes, indeed.

I use the repaint() method to suggest the components to be painted!

How could I avoid this issue?
http://futurerp.net - Text Based MMORPG
http://beta.rpwar.com - 3D Isometric MMORPG

EgonOlsen

Maybe by letting the repaint-thread store the current VisList so that the other thread can access it (in a synchronized way)?

cyberkilla

I tried adding a System.out.println(visList.isValid()) to the above code.

This is the result...


Java version is: 1.5.0_08
-> support for BufferedImage
-> using BufferedImage
Software renderer (OpenGL mode) initialized
Software renderer disposed
Software renderer (OpenGL mode) initialized
Java version is: 1.5.0_08
-> support for BufferedImage
-> using BufferedImage
Software renderer (OpenGL mode) initialized
Software renderer disposed
Software renderer (OpenGL mode) initialized
Java version is: 1.5.0_08
-> support for BufferedImage
-> using BufferedImage
Software renderer (OpenGL mode) initialized
Software renderer disposed
Software renderer (OpenGL mode) initialized
Java version is: 1.5.0_08
-> support for BufferedImage
-> using BufferedImage
Software renderer (OpenGL mode) initialized
Software renderer disposed
Software renderer (OpenGL mode) initialized
Additional visibility list (1) created with size: 4096
Additional visibility list (2) created with size: 4096
Additional visibility list (3) created with size: 4096
Loading file from InputStream
File from InputStream loaded...28766 bytes
Processing new material Material.004!
Processing new material Material.006!
Processing object from 3DS-file: Plane
Object 'Plane_jPCT0' created using 624 polygons and 321 vertices.
Object Merged..
Model Loaded..
New Bone!
Exception in thread "Thread-1" java.lang.StackOverflowError
at com.threed.jpct.VisList.isValid(Unknown Source)
at com.threed.jpct.VisList.isValid(Unknown Source)
at com.threed.jpct.VisList.isValid(Unknown Source)
at com.threed.jpct.VisList.isValid(Unknown Source)
at com.threed.jpct.VisList.isValid(Unknown Source)
at com.threed.jpct.VisList.isValid(Unknown Source)
at com.threed.jpct.VisList.isValid(Unknown Source)
at com.threed.jpct.VisList.isValid(Unknown Source)
at com.threed.jpct.VisList.isValid(Unknown Source)
at com.threed.jpct.VisList.isValid(Unknown Source)
at com.threed.jpct.VisList.isValid(Unknown Source)
at com.threed.jpct.VisList.isValid(Unknown Source)
at com.threed.jpct.VisList.isValid(Unknown Source)
at com.threed.jpct.VisList.isValid(Unknown Source)
at com.threed.jpct.VisList.isValid(Unknown Source)
at com.threed.jpct.VisList.isValid(Unknown Source)
at com.threed.jpct.VisList.isValid(Unknown Source)
at com.threed.jpct.VisList.isValid(Unknown Source)
at com.threed.jpct.VisList.isValid(Unknown Source)
at com.threed.jpct.VisList.isValid(Unknown Source)
at com.threed.jpct.VisList.isValid(Unknown Source)
at com.threed.jpct.VisList.isValid(Unknown Source)
at com.threed.jpct.VisList.isValid(Unknown Source)
at com.threed.jpct.VisList.isValid(Unknown Source)
at com.threed.jpct.VisList.isValid(Unknown Source)
at com.threed.jpct.VisList.isValid(Unknown Source)
at com.threed.jpct.VisList.isValid(Unknown Source)
at com.threed.jpct.VisList.isValid(Unknown Source)
at com.threed.jpct.VisList.isValid(Unknown Source)
at com.threed.jpct.VisList.isValid(Unknown Source)
at com.threed.jpct.VisList.isValid(Unknown Source)

http://futurerp.net - Text Based MMORPG
http://beta.rpwar.com - 3D Isometric MMORPG

cyberkilla

Quote from: "EgonOlsen"Maybe by letting the repaint-thread store the current VisList so that the other thread can access it (in a synchronized way)?

I've tried simply neglecting to paint anything(if(true)return;), but still no difference.

I only have one thread running, which is a render loop.


public class RenderLoop extends Thread
{
protected RenderPane[] renderPanes;

public RenderLoop(RenderPane[] renderPanes)
{
this.renderPanes = renderPanes;

start();
}

public void run()
{
boolean refreshUnselected = false;
long timestamp = 0;
EditorPane editorPane = EditorPane.getInstance();
for(; ;)
{
//Update the editor pane - allow it to handle input.
editorPane.update();

long currentTime = System.currentTimeMillis();
if(timestamp <= currentTime - 500)
{
refreshUnselected = true;
timestamp = currentTime;
}else
refreshUnselected = false;

//Render the panes.
for(RenderPane r : renderPanes)
{
if(r == editorPane.getSelectedRenderPane() || refreshUnselected)
r.repaint();
}
Thread.yield();
}
}


Even after disabling this, the problem persists.
Could this problem be caused in some other way?
http://futurerp.net - Text Based MMORPG
http://beta.rpwar.com - 3D Isometric MMORPG

EgonOlsen

Forget about VisList.isValid()...i mean, have a look at the implementation of this method: :oops:


public boolean isValid() {
  return isValid();
}


VisList-management got so complicated, that giving this method back its real purpose is pointless. I'll remove it from the next version.
You are right...my idea won't work, because storing the VisList doesn't prevent it from being updated by another thread. The only solution i can think of is to do the picking right after the renderScene in the same thread, i.e. in the paintComponent(). Or are you already doing this? It's still not clear to me, which thread does what in your application and which one calls the getObjectAtCursor()-method!?

cyberkilla

Hehe, that would explain the overflow;).

Well, I have ONE thread. The render loop above.

There are FOUR "renderPanes"(JComponents) which are repainted.

In the loop above, it calls an update method - does the pickPolygon.

Then, it loops through the components, suggesting a repaint with, well, repaint();).

The other stuff is just to make the selected component draw fast, and the others to only update every 200ms, for performance reasons;)

So, they are all in the same thread. Now, I know, im only suggesting a repaint, so it means the actual repaint is on the event dispatcher thread.
I have disabled painting anything at all.

The problem persists.
http://futurerp.net - Text Based MMORPG
http://beta.rpwar.com - 3D Isometric MMORPG

EgonOlsen

Ok, got that. So the problem is now, that it works when doing it after the world.renderScene(frameBuffer); and that it doesn't work when doing it before?

cyberkilla

It doesnt work if I include renderScene in the method, as pasted.

However, the code inside the painting loop is essentially the same.
There is some camera movements, but nothing else really.

Its not highly optimised, but thats not important...

public synchronized void paintComponent(Graphics g)
{
Object3D model = editorPane.model;

float radianRotX = editorPane.cameraRotationX;
float radianRotY = editorPane.cameraRotationY;

RenderFactory renderFactory = RenderFactory.defaultInstance;

renderFactory.drawBackground(this);


if(model != null)
{
if(viewMode == VIEW_NORMAL)
{
renderFactory.moveCameraAroundModel(
model,radianRotX, radianRotY,
       editorPane.cameraZoom,
       editorPane.cameraPanX,
       editorPane.cameraPanY,this);
}
else if(viewMode == VIEW_SIDE)
{
renderFactory.moveCameraToSide(editorPane.cameraZoom,editorPane.cameraPanX,
       editorPane.cameraPanY,this);
}
else if(viewMode == VIEW_TOP)
{
renderFactory.moveCameraToTop(editorPane.cameraZoom,editorPane.cameraPanX,
       editorPane.cameraPanY,this);
}
else if(viewMode == VIEW_REAR)
{
renderFactory.moveCameraToRear(editorPane.cameraZoom,editorPane.cameraPanX,
       editorPane.cameraPanY,this);
}
}
renderFactory.world.setCameraTo(camera);
renderFrame();
displayFrame(g);

if(model != null)
renderFactory.drawNearestVertex(g,this);

renderFactory.drawSkeleton(g,this);
renderFactory.draw3DCursor(g,this);
//renderFactory.getObjectAtCursor(mouseMapper.getMouseX(),
// mouseMapper.getMouseY(),this);

}

/**
* Renders the model onto the framebuffer.
*/
public void renderFrame()
{
World world = RenderFactory.defaultInstance.getWorld();
//frameBuffer.clear(Color.black);

frameBuffer.clearZBufferOnly();

world.renderScene(frameBuffer);

//world.draw(frameBuffer);
world.drawWireframe(frameBuffer, Color.GRAY);

frameBuffer.update();
   }
/**
* Draws the framebuffer to the graphics context.
*
* @param g graphics context.
*/
public void displayFrame(Graphics g)
{
frameBuffer.display(g);
}


Its worth mentioning that the method...

  if(model != null)
        renderFactory.drawNearestVertex(g,this);

...above, has the same pickPolygon function in, and it works fine - after render, of course:).
Taking it out makes no difference.
http://futurerp.net - Text Based MMORPG
http://beta.rpwar.com - 3D Isometric MMORPG

cyberkilla


/**
* Moves the camera around a 3d object.
* This method accepts x,y orbiting rotation, a zoom level,
* and a panning coordinate.
*
* @param model model to point camera at
* @param x x rotation
* @param y y rotation
* @param zoom zoom level
* @param mx x panning offset
* @param my y panning offset
*/
public void moveCameraAroundModel(Object3D model,float x, float y,float zoom,float mx,float my,RenderPane renderPane)
{
Camera camera = renderPane.camera;

   SimpleVector center = model.getTransformedCenter();
   
   SimpleVector oldCamPos    = camera.getPosition();
   SimpleVector oldestCamPos = new SimpleVector(oldCamPos);
   oldCamPos.scalarMul(4f);

   SimpleVector camPos  = new SimpleVector(center);
   
   
   Matrix cameraRotation = model.getRotationMatrix().cloneMatrix();
   cameraRotation.rotateX(x);
   cameraRotation.rotateY(y);
   
   
   SimpleVector zOffset = cameraRotation.getZAxis();
   zOffset.scalarMul(zoom);
   
   camPos.add(zOffset);
   

   camPos.add(oldCamPos);
   camPos.scalarMul(0.2f);

   SimpleVector delta = camPos.calcSub(oldestCamPos);
   float len = delta.length();

   if (len != 0)
    camera.moveCamera(delta.normalize(), len);
   center.add(new SimpleVector(mx,my,0));
   camera.lookAt(center);
   
  // camera.moveCamera(new SimpleVector(mx,my,0), 1f);
}
public void moveCameraToSide(float zoom,float mx,float my,RenderPane renderPane)
{
Camera camera = renderPane.camera;
SimpleVector center = EditorPane.defaultInstance.model.getTransformedCenter();
camera.setPosition(center);
camera.moveCamera(new SimpleVector(zoom,0,0),1f);
camera.lookAt(center);
//camera.moveCamera(new SimpleVector(0,mx,my),1f);
}
public void moveCameraToTop(float zoom,float mx,float my,RenderPane renderPane)
{
Camera camera = renderPane.camera;
SimpleVector center = EditorPane.defaultInstance.model.getTransformedCenter();
camera.setPosition(center);
camera.moveCamera(new SimpleVector(0,zoom,0),1f);
camera.lookAt(center);
//camera.moveCamera(new SimpleVector(mx,0,my),1f);
}
public void moveCameraToRear(float zoom,float mx,float my,RenderPane renderPane)
{
Camera camera = renderPane.camera;
SimpleVector center = EditorPane.defaultInstance.model.getTransformedCenter();
camera.setPosition(center);
camera.moveCamera(new SimpleVector(0,0,zoom),1f);
camera.lookAt(center);
//camera.moveCamera(new SimpleVector(mx,my,0),1f);
}
/**
* Draws a small rectangle other the vertex closest to the
* mouse cursor.
*
* @param g
* @param renderPane
*/
public void drawNearestVertex(Graphics g,RenderPane renderPane)
{
MouseMapper mouseMapper = renderPane.mouseMapper;
SimpleVector vect = getClosestVertex(
mouseMapper.getMouseX(),
mouseMapper.getMouseY(),
renderPane);
if(vect == null)
return;

SimpleVector vect2D = Interact2D.project3D2D(
world.getCamera(),renderPane.frameBuffer,vect);

if(vect2D == null)
return;

g.setColor(Color.green);
g.fillRect((int)vect2D.x-2, (int)vect2D.y-2, 4,4);
}



/**
* Draws the 3d cursor into place on a graphics context.
*
* @param g
* @param frameBuffer
*/
public void draw3DCursor(Graphics g,RenderPane renderPane)
{
SimpleVector vect = EditorPane.defaultInstance.cursor3D;
SimpleVector vect2 = EditorPane.defaultInstance.cursor3D2;
if(vect == null || vect2 == null)
return;

Camera      camera      = renderPane.camera;
FrameBuffer frameBuffer = renderPane.frameBuffer;



SimpleVector vect2D = Interact2D.project3D2D(camera,frameBuffer,vect);
SimpleVector vect2D2 = Interact2D.project3D2D(camera,frameBuffer,vect2);

if(vect2D == null || vect2D2 == null)
return;

g.setColor(Color.white);
g.drawRect((int)vect2D.x-2, (int)vect2D.y-2, 4,4);
g.drawRect((int)vect2D.x-4, (int)vect2D.y-4, 8,8);

MouseMapper mouseMapper = renderPane.mouseMapper;
int mouseX = mouseMapper.getMouseX();
int mouseY = mouseMapper.getMouseY();

g.drawLine(mouseX,mouseY, (int)vect2D2.x, (int)vect2D2.y);
g.drawRect((int)vect2D2.x-4, (int)vect2D2.y-4, 8,8);




}



/**
* Draws the bone structure of the skeleton onto
* a graphics context.
*
* @param g
*/
public void drawSkeleton(Graphics g,RenderPane renderPane)
{
SimpleSkeleton skeleton = EditorPane.defaultInstance.skeleton;

if(skeleton == null)
return;

List<SimpleBone> bones  = skeleton.getBones();

drawBones(g,bones,renderPane);
}
private void drawBones(Graphics g,List<SimpleBone> bones,RenderPane renderPane)
{
for(SimpleBone bone : bones)
{
drawBone(g,bone,renderPane);
drawBones(g,bone.getChildren(),renderPane);
}
}
/**
* Draws a single bone, using the pivot, and
* end point vectors.
*
* @param g
* @param bone
*/
Color color = new Color(0x4d,0xef,0x92);
private void drawBone(Graphics g,SimpleBone bone,RenderPane renderPane)
{
Graphics2D g2 = (Graphics2D)g;

Stroke strokeOld = g2.getStroke();

g2.setStroke(new BasicStroke(5.0f,                     // Line width
               BasicStroke.CAP_ROUND,    // End-cap style
               BasicStroke.JOIN_ROUND)); // Vertex join style

g2.setColor(color);

Camera      camera      = renderPane.camera;
FrameBuffer frameBuffer = renderPane.frameBuffer;


SimpleVector pivot2D    = Interact2D.project3D2D(camera,frameBuffer,bone.getPivot());
SimpleVector endPoint2D = Interact2D.project3D2D(camera,frameBuffer,bone.getEndPoint());

if(pivot2D == null || endPoint2D == null)
return;

g.drawLine((int)pivot2D.x,(int)pivot2D.y,(int)endPoint2D.x,(int)endPoint2D.y);

if(((Bone)bone).endPointSelected())
g2.setColor(Color.orange);
else
g2.setColor(Color.gray);

g2.drawOval((int)endPoint2D.x-6,(int)endPoint2D.y-6, 11, 11);

if(bone.isRoot()){
if(((Bone)bone).pivotSelected() )
g2.setColor(Color.orange);
else
g2.setColor(Color.gray);

g2.drawOval((int)pivot2D.x-6,(int)pivot2D.y-6, 11, 11);
}
g2.setStroke(strokeOld);
}
/**
* Draws a background onto the framebuffer of a renderpane.
*
* @param renderFactory
*/
public void drawBackground(RenderPane renderPane)
{
FrameBuffer frameBuffer = renderPane.frameBuffer;
int width  = frameBuffer.getOutputWidth();
int height = frameBuffer.getOutputHeight();

Graphics g = frameBuffer.getGraphics();

//Draw base colour.
if(EditorPane.defaultInstance.selectedRenderPane == renderPane)
g.setColor(new Color(0x00,0x25,0x0a));
else
g.setColor(new Color(0x00,0x14,0x09));

g.fillRect(0,0,width,height);

g.setColor(new Color(0x00,0x35,0x0e));
//Draw the vertical lines.
int i = 0,num = (width / 32) + 1;
while(i<num)
{
g.drawLine(i * 32,0, i * 32,height);

i++;
}
//Draw the horizontal lines.
i = 0; num = (height / 32) + 1;
while(i<num)
{
g.drawLine(0,i * 32, width,i * 32);

i++;
}

//Draw origin crosshair
g.setColor(Color.GRAY);
g.drawLine(width/2, height/2-5, width/2, height/2+5);
g.drawLine(width/2-5, height/2, width/2+5, height/2);


}


Thats everything:)
http://futurerp.net - Text Based MMORPG
http://beta.rpwar.com - 3D Isometric MMORPG

EgonOlsen

Have you done a setSelectable(Object3D.MOUSE_SELECTABLE); on these objects?

cyberkilla

Yes, and it all works, but only in paintComponent
http://futurerp.net - Text Based MMORPG
http://beta.rpwar.com - 3D Isometric MMORPG

EgonOlsen

Good...at least i'm coming close to understand the actual problem now... :wink: Another question: paintComponent() and getObjectAtCursor() are part of the same class?

cyberkilla

No...

getObjectAtCursor() is in RenderFactory.
and
paintComponent() is in RenderPane.
http://futurerp.net - Text Based MMORPG
http://beta.rpwar.com - 3D Isometric MMORPG