Sign in to follow this  
littlekid

Question on shader base engine design

Recommended Posts

I am currently stuck in my implementation of a shader base system. Currently, I am working towards the goal where all meshes,objects are all rendered using shaders. Currently I have a own mesh format where inside it is a section that specifies the HLSL semantic and the data to bind it to. e.g
Mesh Format:
Material
{
  MaterialData
  {
    ID = 10002
    Effect = "Resource\Sample.fx"

    MaterialVariable
    {
      Semantic = "DIFFUSETEXTURE"
      DataType = STRING
      Data = "Resource\Wood.dds"
    }

    MaterialVariable
    {
      Semantic = "NORMALMAP"
      DataType = STRING
      Data = "Resource\WoodNormal.dds"
    }
  }
}



Currently I came up with 2 design: Design One: - Mesh is loaded and its specific variables like textures are bound to the shader using the CStaticLinker class. - Non mesh specific data like, Light Position etc are link to the shader using a CDynamicLinker class where the data is pulled off from the LightManager - Each Mesh has its own array of static/dynamic linker class. - For each rendering of the mesh, the array of Static/Dynamic Linker classes are updated, and then the mesh is drawn. - The downside that I think might happen is that such a design won't allow the mesh to use global shaders easily(ShadowMap.fx) since for every effect the mesh might use, a new array of static/dynamic linker needs to be created. Design Two: - Sitting in between the mesh and shader is a table of material slots. e.g:
MaterialSlot1
{
  HLSLSemantic = WORLDMATRIX
  DataType = MATRIX
}

MaterialSlot2
{
  HLSLSemantic = DIFFUSETEXTURE
  DataType = TEXTURE2D
}
- On each shader creation at the start, the shader iterates its variables semantic and check if a corresponding semantic is found in the MaterialSlot Table - If a matching MaterialSlot semantic is found, a CLinker class is created. - Insider each shader class will be a array of CLinker class. - Mesh, LightSystem, etc will update their data to the relevant MaterialSlots. E.g Mesh updates it worldmatrix to WORLDMATRIX MaterialSlot, LightSystem updates light position to LIGHTSPOS MaterialSlot. - When rendering a object: 1. Mesh, LightSystem, etc updates its data to the Materialslots 2. the shader just iterates it CLinker array and updates its variable by getting the data from the materialslots table. - The benifit is the shader does not need to know where the data comes from. To the shader, all data comes from the materialslot table. - This allow easy switching of effect to be used. e.g I can force all objects to render using FooShader.fx. - The downside that I think would be that it might be slower, considering that data needs to be updated to the materialslot first before arrving to the shader. Which design is better? Or are there more efficient ways to handle a shaderbase material system? I am sorry if this seems to be a noobish question. This is currently my first time trying to take a full shader base approach for my material system. [Edited by - littlekid on July 3, 2008 8:28:05 AM]

Share this post


Link to post
Share on other sites
I was thinking of making the shader system more flexiblie. E.g

Cube Mesh has standard lighting shader "Cube.fx"
Building Mesh has standard lighting shader "Building.fx"
Lampost Mesh has standard lighting shader "Lampost.fx"

Simple Rendering is easily done:
-Set Cube.fx
-Set shader constants
-Draw Cube
-Set Building.fx
-Set shader constants
-Draw Building
-Set Lampost.fx
-Set shader constants
-Draw Lampost

Lets say for now I decided to add shadows to the scene using shadowmaps. Since ShadowMap creation is pretty similar throughout, I only created a common shader called "CreateShadowMap.fx"

And now drawing process becomes:

ShadowMap creation stage
-Set CreateShadowMap.fx
-Set shader constants by getting data from the MaterialTable
-Draw Cube
-Set shader constants by getting data from the MaterialTable
-Draw Building
-Set shader constants by getting data from the MaterialTable
-Draw Lampost
-Update the newly created shadow map to the corresponding slot in the MaterialTable

Lighing stage
-Set Cube.fx
-Set shader constants by getting data from the MaterialTable
-Draw Cube
-Set Building.fx
-Set shader constants by getting data from the MaterialTable
-Draw Building
-Set Lampost.fx
-Set shader constants by getting data from the MaterialTable
-Draw Lampost

By just D3D/D3DX functions, how would the shader know where to get its data from?
ShadowMap creation stage
-Set CreateShadowMap.fx
-How does the effect file knows it needs data from the Cube mesh?
-Draw Cube
-How does the effect file knows it needs data from the Building mesh?
-Draw Building
-How does the effect file knows it needs data from the Lampost mesh?
-Draw Lampost

furthermore shader constant data does not necessary needs to come from a single source. Some may come from the mesh, some may come from the camera system etc.

I am not sure if I am thinking in the right direction. Are there better and simpler way to make a shader-base system?

Share this post


Link to post
Share on other sites
Quote:
Original post by littlekid
Cube Mesh has standard lighting shader "Cube.fx"
Building Mesh has standard lighting shader "Building.fx"
Lampost Mesh has standard lighting shader "Lampost.fx"
Note those are "strong" assumptions. You're assuming everything as a "standard" shader: no tcGen, no vertex deformation, no procedural noise, nothing.
Quote:
Original post by littlekid
Lets say for now I decided to add shadows to the scene using shadowmaps. Since ShadowMap creation is pretty similar throughout, I only created a common shader called "CreateShadowMap.fx"
This works only because you're pretending your shaders to be simple and similar. This doesn't work with arbitrary shaders, a way more involved approach is needed.
Quote:
Original post by littlekid
furthermore shader constant data does not necessary needs to come from a single source. Some may come from the mesh, some may come from the camera system etc.
I feel you need another layer of abstraction. It doesn't matter the origin, the destination matters. No matter how you put it, you'll need to support uniform fetching in some way. The FX framework makes it pretty easy but besides your API of choice understanding what you're going to load is a bit ankward.
Quote:
Original post by littlekid
By just D3D/D3DX functions, how would the shader know where to get its data from?
ShadowMap creation stage
-Set CreateShadowMap.fx
-How does the effect file knows it needs data from the Cube mesh?
-Draw Cube
-How does the effect file knows it needs data from the Building mesh?
-Draw Building
-How does the effect file knows it needs data from the Lampost mesh?
-Draw Lampost
By its semantics and annotations? The FX framework is a bit of a magic box to me, it doesn't fit my needs so I use "HLSL".

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this