Google
 

Sunday, April 08, 2007

Engine Design - Interfaces and RCScene

The interfaces are pretty much as the tutorial has them, I have removed the set methods from the IRCHasMaterial interface as I didn't think they where of much use as I prefer setting fields in my objects with properties rather than using methods. I don't think there is any performance issue with it, it is just a personal preference.

Interfaces
interface IRCObjectComponent
interface IRCHasMaterial : IRCObjectComponent
interface IRCChildRenderer : IRCObjectComponent
interface IRCLoadable : IRCObjectComponent
interface IRCRenderable : IRCObjectComponent

IRCObjectComponent has no methods associated with it, yet.

IRCHasMaterial has a single method:


void SetMaterialProperties();



The method is used to invoke the setting up of shader parameters with the objects material fields. Things like material ambient color and material diffuse color should be set using this method.

IRCChildRenderer has a single method:


void RenderChildren(GraphicsDevice myDevice);



The method should be used to call an objects child render methods. for example one of my particle emitters has an array of RCBilboard objects, this class inherits from IRCChildRenderer as it needs to render each billboard in the array.

IRCLoadable has a single method:


void LoadGraphicsContent(GraphicsDevice myDevice,     ContentManager myLoader);



This method is used to load any graphical content ready to be drawn. For example an object that has a shader that uses an environment cube map would use this to load the cube map asset into memory ready to use.

IRCRenderable has a single method:


void Render(GraphicsDevice myDevice);



Objects that need to be rendered should use this method, so that is probably 99% of all objects in the engine!

The Scene Objects
I have added a new class called RCSceneLoader which can load/save scenes to XML. I implemented this class ages ago and it is now totally out of date, so I will leave this for another post once I have brought it up to date with the engine as it stands now.

The only real change to the RCSceneGraph class is the addition of one method, GetObject. This method is passed the objects name that you want to retrieve from the scene graph and returns the RCObjectNode containing this object which you can then cast to it's expected type and use.


public RCObjectNode GetObject(string Name)
{
    for(int on=0;on < myRoot.Nodes.Count;on++)
    {
        if (((RCObjectNode)myRoot.Nodes[on]).Name == Name)
        return (RCObjectNode)myRoot.Nodes[on];
    }
    return null;
}



Here is an example of it being used:

RCTerrain terrain = (RCTerrain)game.Scene.GetObject("terrain").Object;



RCScenePicker
This class uses ray picking to select an object from the scene with the mouse.


public class RCScenePicker
{
    private static Ray myRay;
    private static ArrayList RayHitList;

    public static Ray RayPicker
    {
        get { return myRay; }
        set { myRay = value; }
    }

    private RCScenePicker() { }

    public static RCObject GetClickedModel(Point mousecoords,
                RCSceneGraph Scene)
    {
        RCCamera camera = RCCameraManager.ActiveCamera;

        Vector3 nearSource = camera.Viewport.Unproject(
            new Vector3(mousecoords.X, mousecoords.Y,
            camera.Viewport.MinDepth), camera.Projection, camera.View,
            Matrix.Identity);

        Vector3 farSource = camera.Viewport.Unproject(
            new Vector3(mousecoords.X, mousecoords.Y,
            camera.Viewport.MaxDepth), camera.Projection, camera.View,
            Matrix.Identity);

        Vector3 direction = farSource - nearSource;

        direction.Normalize();

        myRay = new Ray(nearSource, direction);
        return RayIntersects(Scene);
    }

    private static RCObject RayIntersects(RCSceneGraph Scene)
    {
        RCObject retVal = null;
        RayHitList = new ArrayList();

        for (int n = 0; n < Scene.SceneRoot.Nodes.Count; n++)
        {
            RCObject obj =
                (RCObject)(((RCObjectNode)
                    Scene.SceneRoot.Nodes[n]).Object);
            BoundingBox bb = obj.ObjectsBoundingBox;
            Nullable<float> distance;
            myRay.Intersects(ref bb,out distance);
            if (distance != null)
            {
                object[] thisObj = new object[2];
                thisObj[0] = (int)distance;
                thisObj[1] = obj;

                RayHitList.Add(thisObj);
            }
        }

        // Now get the object nearest the camera.
        object[] lastDist = new object[] {(int)
            RCCameraManager.ActiveCamera.Viewport.MaxDepth,
            new RCObject("tmp")};

        for (int o = 0; o < RayHitList.Count; o++)
        {
            if((int)((object[])RayHitList[o])[0] < (int)lastDist[0])
                lastDist = ((object[])RayHitList[o]);
        }

        if(RayHitList.Count > 0)
            retVal = (RCObject)lastDist[1];

        return retVal;
    }
}



In my next post I will be documenting the changes I have made to the objects in Tutorial 3, the Shader and ShaderManager class, the TexturedQuad, the Camera and CameraManager class.

No comments:

Post a Comment

Note: Only a member of this blog may post a comment.