Cleaning up Renderer Interface

Renderer has grown a little wild and I was looking through some things to help trem it down.



I plan on: Removing all get*State() They were deprecated for 0.7 and can be gone for 0.8.



Looking through all the draw modes I’d love to be able to get it down to a single draw(Trimesh) (although this is not possible), but I’d like to remove as many excess draw methods as possible.



draw(CloneNode) and draw(Clone) - Is clone and clone node useful to anyone? Most people who have used it report it doesn’t do what they had hoped it would and perhaps it’s not all that useful a solution.



draw(Text) - we now have 3 ways of rendering text, this way with LWJGLFont, the Font Widget and the UI Font. Guurk’s UI is turning out very nicely, and I believe if he can get trees, slider bars, etc, it might become the default GUI system for jME. As such, rendering text using his tool may be the best solution, removing the need to use LWJGLFont, hence removing this draw method.



draw(Curve) - any use at all?



draw(point) draw(line) - is point and lines useful to anyone?



draw(Tint) - is there anyway that this can be rendered without it’s own draw method? It’s just a transparent quad.

I agree on removing all of the mentioned items. Clone would be useful eventually if written to provide more use then the current implementation, but should be done in a may that does not require its own entry in the renderer. Line and Point are likely useful to some people (everything is useful to somebody) but do they have a place in a 3d engine? Debatable I guess.



Curve same as Line… Tint can be redone to use the renderqueue so no need for its own entry in renderer.

When i made Tint, i was sorta…umm…amaturish :?



Go ahead and remove it. I dont think anyone is actually using Tint anyway. So you could remove the whole thing if you want.



DP

I’ve only been looking at jME today, so I could well be missing things. My previous experience of scenegraphs is OGRE (http://www.ogre3d.org/) so I am (very) biased. IMHO, Ogre is a fantastic design let down by the language it was written in.



My initial impressions are that the renderer shouldnt be drawing the actual trimeshes. It should provide an API to define and draw vertex/index buffers. The triMesh could then call this API, giving the trimesh the ability to draw itself, while being API (LWJGL/JOGL) independant.



I’m also a bit confused as to why BezierMesh extends TriMesh? Shouldnt they should both extend some sort of Renderable superclass? (I’ve always thought of extends relationships as being “is-a”. I would assume that BezierMesh is-not-a TriMesh?)



Like I said, I’ve only started looking at the engine today, so I could be missing some stuff, but these are my first impressions.



EDIT:



Maybe a bit more detail to the API idea might be in order. There would basically be a method on the Renderer like





void setShader(Shader s)
void render(int VertexType, Buffer data)




VertexType would be TRIANGLES, QUADS, TRI_LIST etc, and data would contain all the data needed to render that "piece" of geometry. Each piece of geometry would have a material or shader (depending on how you overload these words) associated with it. This would be set before calling render.

I think that jme should suport points and lines. I use points in my game. I also think Curve is a nice efect.

My initial impressions are that the renderer shouldnt be drawing the actual trimeshes. It should provide an API to define and draw vertex/index buffers. The triMesh could then call this API, giving the trimesh the ability to draw itself, while being API (LWJGL/JOGL) independant.


Simply different design decisions. jME is also API independant. The trimesh is passed to the concrete implementation. This will not change.

I'm also a bit confused as to why BezierMesh extends TriMesh? Shouldnt they should both extend some sort of Renderable superclass? (I've always thought of extends relationships as being "is-a". I would assume that BezierMesh is-not-a TriMesh?)



BezierMesh is a TriMesh is a Geometry is a Spatial.

BezierMesh is a TriMesh it is a TriMesh with a curved smooth surface.

I think that jme should suport points and lines. I use points in my game. I also think Curve is a nice efect.


What do you use them for? If there is a way to do the same thing using trimeshes, then we should do that. If not, then I am going to put this up for a vote.

Renanse reminded me that we use Lines in our own Scenegraph demo test. And I can’t think of a great replacement for them, so I think Lines may be worth saving. However, still haven’t heard a good reason for Points. I’m definately more open now though. :stuck_out_tongue:

The trimesh is passed to the concrete implementation. This will not change.


Why have you decided to go this route? I've always assumed the object should know how to render itself, so I'm interested to know the reasons for this type of design.

Because the scene object is a data object.



A Renderer worries about rendering data.

Each renderer will know how to render a given object for a different api, ie. LWJGLRenderer renders for LWJGL, a JOGLRenderer would be for JOGL, etc. Otherwise, each object would need to contain api code for each type of render target and that would just be silly.

I like the design that an object does not draw itself. The object preps itself for drawing but the draw is done by the renderer.



Not “rendering” designs but…





The function



BoundingVolume.initCheckPlanes();



seems like a C++ carryover. It doesn’t really serve a purpose (or does it) because it’s never called as a BoundingVolume. This should be a private function of the bounding volumes themselves.



Also, we’re staring to have classes



IntersectionOBB

IntersectionBox

IntersectionSphere





with intersection testing going along the lines of multiple “instanceof” statements. This is also true with

     public BoundingVolume merge(BoundingVolume volume)

. Would it be better design to have somethign like:



(inside BoundingVolume)


BoundingVolume void mergeSphere(BoundingSphere x);
BoundingVolume void merge(BoundingVolume v);




(inside BoundingSphere)

public BoundingVolume merge(BoundingVolume v){
return v.mergeSphere(this);
}



This design would remove any need for instanceof and is suppose to optimize nicely. Plus it seems more OO.

The current design could be messy because I plan to impliment OBBTree as a BoundingVolume, which is yet another "instanceof" in 4-5 places right now.

I agree with removing Clone. I have an idea for a “TriMeshClone” class that would extend TriMesh. Users could specify parameters like “sharetextures=true” or “shareKeyframeControllers=true” which when the function createCopy(TriMesh toClone) is called, a trimesh is returned that would refrence the original’s texture[] and TextureBuffer. This way, only what the user wants shared is shared. The only change from how clone works now is that even after the textures are shared, they could later on (if the programmer wants too) unshare their texture by reasigning texture buffers or texture[]'s. This way, TriMeshClone could be rendered as a simple TriMesh.

Ok, my tasks:


  1. Remove the Clone stuff.
  2. Switch to UIText (some profiling will need to be done to make sure there is not any performance issues here).
  3. Remove Tint (this can be handled with the RenderQueue now)
  4. Remove the get*State()
  5. Remove the old Model loading code so it only uses cep’s.


....

with intersection testing going along the lines of multiple "instanceof" statements. This is also true withCode:
public BoundingVolume merge(BoundingVolume volume)
. Would it be better design to have somethign like:

(inside BoundingVolume)

Code:
BoundingVolume void mergeSphere(BoundingSphere x);
BoundingVolume void merge(BoundingVolume v);



(inside BoundingSphere)

Code:
public BoundingVolume merge(BoundingVolume v){
return v.mergeSphere(this);
}


This design would remove any need for instanceof and is suppose to optimize nicely. Plus it seems more OO.



The trouble is, the merging code and intersection code is called (most of the time) internally by the nodes. The nodes do not know what kind of bounding volume they are using, so they can't call the correct method.

They don’t need too. They would call merge(). The code would be like this:



Spatial a,b;

BoundingVolume a1=a.getWorldBound();

BoundingVolume b1=b.getWorldBound();



if (a1.intersect(b1)) System.out.println(“Hello World”);





Lets say a is a … BoundingSphere and b is a … BoundingBox. The call would go something like



The function intersect inside BoundingSphere would look like this:



public boolean intersect(BoundingVolume bv){
  return bv.intersectSphere(this);
}



The code inside Bounding box would look like this:


public boolean intersectSphere(BoundingSphere bs){
// If they intersect return true;
}



The original function doens't need to know what they are. It gets delegated by the calling function.

ok, so you are recommending moving intersections into the volumes themselves. I don’t have a problem with that.



I’ll add that to my list.



6. Move intersections into BoundingVolume and subclasses.



Those 6 items will be my tasks for the next bit of time. They are small chunks that I can take care of in my limited time.

"Cep21" wrote:
The function

BoundingVolume.initCheckPlanes();

seems like a C++ carryover. It doesn't really serve a purpose (or does it) because it's never called as a BoundingVolume. This should be a private function of the bounding volumes themselves.

We can remove it as part of the Interface and make it private. It's only a method to avoid repetition in the constructors.

I might be wrong on this but from looking at the renderer code this morning there seems to be a slight fault with how the render queue works.



My understanding is that SimplGame.render calls renderer.draw(Spatial) which will call Spatial.onDraw(renderer)



The onDraw method checks if the object is within the Camera frustum and if it is adds itself to the renderQueue.



When displayBackBuffer is called the RenderQueue is displayed. However this calls onDraw again, which means that another frustum check is done. The object must be visible though, else it wouldnt be in the renderQueue. Surely you should just do somethin like




renderer.draw(opaqueBucket.list[i])



Or am I missing something?

Mostly right. It should be:


    opaqueBucket.list[i].draw(renderer);



since the draw code applies states before the renderer is called in to render the actual item. Dunno how I had onDraw in there, probably a cut and paste type error. :P

Fixed.
"mojomonk" wrote:
What do you use them for? If there is a way to do the same thing using trimeshes, then we should do that. If not, then I am going to put this up for a vote.

I use them to render stars and dust. It is much simpler then using a skybox and has a better result. For the dust I could use billboards and particles but I was under the Impression that my way is faster.

Wile you are working on cleaning up JME I would suggest that you get ride of one of the data folders. They greatly slow down the speed of the cvs download. His could discourage people that want to look into JME.