Monday, September 23, 2013

Rendering OD

I spent most of the weekend working on getting the shader graph out of Blender and into the pipeline.

I had expected generating the shader from the graph to be the difficult part, but that was actually surprisingly simple.

A simple emissive shader looks like this:

EngineGlow
{
 Nodes
 {
  Material_Output
  {
   Type = OUTPUT_MATERIAL
   Inputs
   {
    Surface
    {
     Type = SHADER
    }
    Volume
    {
     Type = SHADER
    }
    Displacement
    {
     Type = VALUE
     Default = 0.000000
    }
   }
   Outputs
   {
   }
  }
  Emission
  {
   Type = EMISSION
   Inputs
   {
    Color
    {
     Type = RGBA
     Default = 0.000000, 0.405629, 0.800000, 1.000000
    }
    Strength
    {
     Type = VALUE
     Default = 400.000000
    }
   }
   Outputs
   {
    Emission
    {
     Type = SHADER
    }
   }
  }
 }
 Links
 {
  0
  {
   FromNode = Emission
   FromSocket = Emission
   ToNode = Material_Output
   ToSocket = Surface
  }
 }
}

Because this is just my attribute file format, after loading it, it's trivial to take the Links section and insert them directly into the Inputs section.  Then you just find the MATERIAL_OUTPUT node and recursively work your way back up the nodes, using default values if there is no link.

Each node type typically ends up generating only one or two lines of code, and a handful of variables.  Generating braces at the beginning and end of each node keeps all variables declarations local, and you just pass the name of the variable you want to set to the recursive call.  For BSDF nodes, just emit a function call to a pre-defined lighting function (which all just reduce to Phong at the moment, but that can be dealt with later).

So, the hard part was not generating the actual fragment shader. 

Mapping UV channels initially seemed like it was going to be difficult, because they are mapped by name and Assimp doesn't preserve this information.  Then I realized I could do the name lookup when I export the shader graph, and as long as Assimp preserves the channel order I can just embed the UV index in the attribute file.

The only part that really caused trouble was trying to get the textures to map to materials properly.  The Blender COLLADA exporter only looks at the "legacy" shaders, and only exports a single texture (and maybe a normal map if you have things set correctly).  Ultimately this came down to ignoring textures from the COLLADA file and gathering, converting and binding textures directly from the shader graph.  The only other thing was telling Assimp not to merge materials, because it doesn't have an accurate picture of things.

In any case, this all seems to be working.  It's a lot more flexible that what I had before, and I can actually set proper emissive ranges for HDR.

So, since you bothered to read this far, I give you an in-game screenshot:



No comments:

Post a Comment