Jump to content

  • Log In with Google      Sign In   
  • Create Account






ZECloud::RenderList

Posted by freeworld, 10 February 2012 · 524 views

I was listening to this song earlier and it just had this great verse in it.

Cause you
You're so calm
I don't know where you are from
You
You're so young
I don't care what you've done wrong


Too me it screams the essence of childhood, being an adult and whatching children grow up. To not take the world so seriously that you never do anything. Everyone makes mistakes and it's not the end of the world. I constantly find my self reminding my own kids to not worry so much. Seeing how easily people get fustrated these days, it's not what I remmeber as a kid. "Tokyo Police Club - Shoulders and Arms" is the song for anyone interested.

Well I started doing a little more remodeling then I thought I was going to. The following snippet is the current and probably old renderList. These lists are the back bone of my renderer and do all the heavy lifting for me. The list stores a struct called drawcall, which is the basic information about what is trying to be drawn and how; position, size, texture, shader, rotation/origin, and diffuse coloring. Which actually isnt the original layout either. The old drawcall, stored the actual vertecies along with the texture, shader and so forth.

A year or two ago, I switched to the concept that all I needed was rectangles/quads. Why store all the extra data when I could just translate them later? Since then I've had countless times where a trangle or line would've been so much more helpfull, then trying to aligned a quad textured with the shape just right. If you poked around my last post, you probably remember the DrawQuad function, there did used to be DrawTriangle, DrawLine.... hence why I didn't call it something more associative like DrawSprite.

Once all drawcalls have been made for this frame, everything move onto the renderer which mainipulates the render lists and presents them to the screen. Starting at the preFill. Any sorting of the list happens here. I sort all my calls so that transparent textures are at the back, orderer back to front, and opaque textures orderer front to back. Using the z depth of the textures, This allows alot of flexibility in game design. THeres no need to design you code around the fact that certain images have to be drawn at certain times to appear right. Aslong as they're positions are set right, they'' appear correctly.

After sorting any render target swapping happens here. This is one aspect that is being remodeled. Currently the renderList only supports one render target per renderlist. This meant I had to hardwire a seperate pipeline for doing lighting, else suffer the fact that Id have to have a seperate renderList withe the exact same data for each buffer required by the lighting system, and relock the vertexbuffer for each list and everything else that has to be done for each list, added up pretty fast. The new list is going to store chains of effects. each link in the chain is simply a renderTarget and shader to be used. This can even be the backbuffer just rendering with different shaders each time. Also each link can have a set of secondary textures that should be included into the stream. Such as passing the gBuffer along with what is being rendered to do lighting. It will be a bit experimental, as honostely some of the functionality I've never used before but always wanted to.

Once things are sorted, the rendertarget is set. Fill, lcoks the vertex buffer for the current texture and shader combo. Using the drawcall iterator, fill walks through the drawcall vector, any call that matchs the current state gets translated and placed into the vertexbuffer. If a new state is found, fill stops immediately. This is all to take advantage of the iterator and try to not process any drawcall more than once... ie the pipeline should walk through the list only once.

All the translation though is being moved to the point when the drawcall is made, except that or view -> screen translation which happens in the shader using an orthogonal projection. The pipeline uses it's own camera to tranlate the call from world to view space. Cull, then rotate if nessecary. Culling is really generic, I use an oversized view (bigger than the screen), and just do a quick bounds check with the center of the quad and the screen. Aslong as you're not trying to draw a 512x512 or bigger texture it shouldn't have any popping as it leaves the screen.

PostFill is pretty much the opposite of prefill. it resets the rendertarget to the back buffer if it was changed, then resets the drawcall iterator so new drawcalls will start by overwriting the old ones before pushing new ones on the stack.

namespace ZEGraphics
{

    class RenderList
    {
    public:

	    LPDIRECT3DSURFACE9	  backBufferCopy;        // used to save the backbuffer while a secondary buffer is being used.
	    LPDIRECT3DSURFACE9	  tempRenderTarget;
        IDirect3DVertexBuffer9* vertexBuffer;        // dynamic vertexBuffer used by this renderList only.

	    std::vector<ZEGraphics::Sprite*> renderTargets;    // list of secondary targets that will get rendered to in order withe the assigned shaders.

        std::vector<ZEGraphics::Drawcall>		   drawcalls;
        std::vector<ZEGraphics::Drawcall>::iterator drawcallIterator;    // the iterator is used by the fill process only, to save the readers position inbetween state changes.

    public:
 
        RenderList();
	    RenderList(ZEGraphics::Device* device);        // Basic constrctor, sets iterator and reserves space for 5K drawcalls.

        ~RenderList();                                // releases all data including vertexBuffer, drawcall vector... etc.
	    void Reset();                                // resets the drawcallIterator, and other temp settings.
        
        /**********************************************************************************************
        *    PreFill - sets up the list for converting to vertexbuffer. Sorts by state change,
        *              resets the iterator and prepares the render target to be used.
        **********************************************************************************************/
        void PreFill(ZEGraphics::Device* device);

        /**********************************************************************************************
        *    Fill - Enters the vertex data for the drawcalls of the same state.
        **********************************************************************************************/
        void Fill(ZEGraphics::Camera* camera, IDirect3DTexture9*& _texture, DWORD& _shader, UINT& _primitiveCount, bool& _isTransparent, bool& _isEmpty);

        /**********************************************************************************************
        *    PostFill - Resets the renderTarget and clears the list for re entering new draw calls.
        **********************************************************************************************/
        void PostFill(ZEGraphics::Device* device);

        /**********************************************************************************************
        *    AddDrawcall - pushs a single drawcall onto the stack.
        **********************************************************************************************/
        void AddDrawcall(ZEGraphics::Drawcall _drawcall);

        bool Full();        // Return true if the drawcalls have exceeded the vertexBuffer capacity. 100K calls (200K triangles).

    private:

        /**********************************************************************************************
        *    helper functions to split the big functions up and make them easier to read and edit, blah blah blah.
        **********************************************************************************************/

        bool NextDrawcall(); // move iterator to next available drawcall. return false if no drawcalls available.
        void GenerateQuad(ZE::VEC3 pos, ZE::VEC2 size, ZE::VEC3& vert1, ZE::VEC3& vert2, ZE::VEC3& vert3, ZE::VEC3& vert4);
        void SetVertex(DWORD index, ZEGraphics::Vertex*& vertexData, ZE::VEC3 pos, ZE::VEC3 normals, ZE::VEC2 uv, ZEGraphics::COLOR diffuse);

    };

};

#endif

The new renderList will be moving one from the all in one bucket for every drawcall. I'm also going back to the old way of string vertecies in the drawcall to facilitae the difference between triangles, quads and lines. The later being the only one that is actually a special case. Circles I use a precision variable to determine how many triangles I use to build them.

Drawcall buckets, that's what I'll be calling it now. The idea is to store drawcalls in seperate buckets for each state combo. So shader and texture will be stored in the bucket instead of individual drawcalls. No need to check if a drawcall is valid anymore, if it's in the bucket then use it with this state. Shaders migh even be removed to only the renderlist and the render chains. So if a shader is going to be used by a rednerList it's going to apply it to all of them. Off the top of my head I can't think of any time I used a seperate shader within the same renderList. So buckets will probably be sorted just by texture.

Render chains will be another big change, already mentioned, a chain is a render target and shader to be applied. it will also have a way of assigning secondary textures to be applied to the stream. Say you build you color buffer, normals and other gBuffer goodies. Then need to render your scene to the screen using all that light data, but you can only use one texture at a time. Makes it kinda impposible right?

Well the skeleton is in place and some of the dta types are finished, I still got alot of coding before it's what I want. I am trying to keep the old pipeline untouched though, so all my old projects still work just fine. They just cant use any new features. :) But now I'm all typed out... good luck and happy coding dev world... YORDLES!




Latest Visitors

PARTNERS