For those of you that have actually used the scene support in Sgine will be aware, the scenegraph architecture is extremely abstract and is designed to avoid implications towards a specific use and allow multiple uses within the same scenegraph. For example, a NodeContainer could possibly contain physics information, sound/music information, visual rendering information, etc. while each part being completely separate and independent from the other. The level at which I'm able to accomplish this is almost entirely due to the awesomeness that is Scala, but to that end abstractions often make it difficult to architect advanced uses without making system extremely complicated. For example, if I want to have my root NodeContainer define matrix information to translate 'z' to -200.0, meaning that all children will receive that it can be problematic to support if nodes between don't also provide matrix support. However, that is the difficulty I solved today. :)
I've created a simple trait "MatrixNode" that contains a "localMatrix" and a "worldMatrix". The "localMatrix" can be manipulated to represent the local translation, rotation, scale, etc. and upon change will invalidate the "worldMatrix" causing it to get updated to the parent's "worldMatrix" (walking up the scenegraph as necessary) multiplied against the "localMatrix".
See the following example:
package org.sgine.ui import org.sgine.core.Color import org.sgine.core.Resource import org.sgine.easing.Linear import org.sgine.render.Renderer import org.sgine.render.scene.RenderableScene import org.sgine.scene.GeneralNodeContainer import org.sgine.scene.MatrixNode object TestScene { def main(args: Array[String]): Unit = { val r = Renderer.createFrame(1024, 768, "Test RenderScene") val scene = new GeneralNodeContainer() val container1 = new GeneralNodeContainer() with MatrixNode container1.localMatrix().translate(0.0, 0.0, -200.0) scene += container1 val container2 = new GeneralNodeContainer() with MatrixNode container2.localMatrix().translate(0.0, 0.0, -500.0) container1 += container2 val container3 = new GeneralNodeContainer() container2 += container3 val component = new Image() component.source := Resource("puppies.jpg") component.color := Color(1.0, 1.0, 1.0, 0.5) component.location.z := 100.0 container3 += component r.renderable := RenderableScene(scene) } }
This is a pretty simple example. As you can see there are four containers (scene, container1, container2, and container3) and two of them mix-in "MatrixNode" in order to specify a translation (container1 and container2). Finally, there is a Image "component" that defines its own location.z. As a result "component" will render at a "z" translation of -600.0 (-200.0 + -500.0 + 100.0). Notice that although "container3" is between "container2" and "component" it is still applied. This allows extremely powerful control of the contents of the scenegraph while maintaining a very simple abstract feel.
Hopefully in the coming weeks you'll see much more functionality like this making its way into the system. In fact, I believe I'm going to have to write something along these lines for Color in order to properly mix colors hierarchically for OpenGL.
No comments:
Post a Comment
Note: Only a member of this blog may post a comment.