Erik's Digital Portfolio

Erik's Digital Portfolio

  • May1st

    Marching Cubes

    Inspired by NVIDIA’s GPU Gems 3, Chapter 1, David and I decided to create procedural terrain inside his software renderer. Space is divided into cubes (called Voxels) and all 8 corners of a Voxel are assigned a density. Negative densities represent empty air and positive densities are solid land. I created the noise and density generation functions while David created polygons based on the Voxels generated. You can learn more about the software renderer at David’s website.

    Flat Terrain: Good Start, Super Boring

    One Layer of Noise

    Two Layers of Harmonic Noise

    FIVE Layers of Harmonic Noise

    With a Floor

    In Depth Buffer Vision

    Sphere

    Almost anything is possible with the right density function. For example, using the equation for a sphere and adding layers of harmonic noise creates a cool looking asteroid.

  • May1st

    NVIDIA FX Composer is a free utility for writing, editing, and viewing Shaders. Ogre3D is an Open Source graphics engine used in a number of game engines. The whole purpose behind FX Composer is to give shader programmers a place to code and test outside of a game engine or renderer. Unfortunately, the code that works perfectly in FX Composer needs to be modified before it can run in Ogre3D.

    1. Strip away any .fx specific syntax that Ogre can’t understand.
    2. Convert FX Composer auto semantics to Ogre auto semantics. FX Composer will simply declare matrices at the top of the file: float4x4 WorldViewProj : WorldViewProjection; In Ogre, you have to pass those into functions as parameters like so: param_named_auto WorldViewProj worldviewproj_matrix
    3. Make adjustments to Matrix Order. FX Composer expects the DirectX convention of Row-Major matrices and Ogre will hand you Column-Major. Usually, all this means is that when you see mul(Vector, Matrix4x4) you have to rewrite it as mul(Matrix4x4, Vector). If the code pulls out individual vectors or elements from a matrix, more tweaking will be required.
    4. Break up the .fx file. The shader functions need to go into an HLSL file named newshader.hlsl, which must be copied into ogre/materials/programs/ . The effects code needs to go into a Materials file named newshader.material, which must be copied into ogre/materials/scripts/
    5. Assign the new material to an entity in Ogre3D: ent->setMaterialName(“NewShader”);

    For two working samples, see:

    Glow Balloon Shader in Ogre3D

    Bumpy Glossy Shader in Ogre3D

  • May1st

    Ogre3D HLSL Bumpy Glossy Shader Code

    The original HLSL shader code can be downloaded from NVIDIA at http://developer.download.nvidia.com/shaderlibrary/webpages/shader_library.html#BumpyGlossyMetal

    Bumpy Glossy HLSL Shader in Ogre3D

    To get the shader to work in Ogre3D, several changes have been made:

    • Autos (the projection matrices) have been passed in as parameters.
    • Texture Samplers have been passed in as parameters.
    • Matrix multiplication order has been reversed.
    • Structs have been replaced by long lists of parameters, including out parameters.

    bumpyglossy.hlsl

    void bumpyGlossy_VS(
      float3 Position  : POSITION,
      float4 UV    : TEXCOORD0,
      float4 Normal  : NORMAL,
      float4 Tangent  : TANGENT0,
      float4 Binormal  : BINORMAL0,
    
      out float4 vsOutHPosition    : POSITION,
      out float4 vsOutTexCoord    : TEXCOORD0,
      out float3 vsOutWorldNormal    : TEXCOORD1,
      out float3 vsOutWorldPos    : TEXCOORD2,
      out float3 vsOutWorldEyeVec    : TEXCOORD3,
      out float3 vsOutWorldTangent  : TEXCOORD4,
      out float3 vsOutWorldBinorm    : TEXCOORD5,
      out float3 vsOutLightVec1    : TEXCOORD6,
    
      uniform float4x4 WorldITXf,
      uniform float4x4 WorldXf,
      uniform float4x4 ViewIXf,
      uniform float4x4 WvpXf,
      uniform float4    lightPos
      )
    {
      vsOutWorldNormal = mul(WorldITXf, Normal).xyz;
      vsOutWorldTangent = mul(WorldITXf, Tangent).xyz;
      vsOutWorldBinorm = mul(WorldITXf, Binormal).xyz;
      float4 Po = float4(Position.xyz,1.0);
      float3 Pw = mul(WorldXf, Po).xyz;
      vsOutWorldPos = Pw;
      vsOutLightVec1 = lightPos.xyz - Pw;
      vsOutTexCoord = UV;
      vsOutWorldEyeVec = ViewIXf[3].xyz - Pw;
      vsOutHPosition = mul(WvpXf, Po);
    }
    
    void bumpyGlossy_FS(
      float4 vsOutHPosition    : POSITION,
      float4 vsOutTexCoord    : TEXCOORD0,
      float3 vsOutWorldNormal    : TEXCOORD1,
      float3 vsOutWorldPos    : TEXCOORD2,
      float3 vsOutWorldEyeVec    : TEXCOORD3,
      float3 vsOutWorldTangent  : TEXCOORD4,
      float3 vsOutWorldBinorm    : TEXCOORD5,
      float3 vsOutLightVec1    : TEXCOORD6,
    
      out float4 fsOutColor  : COLOR,
    
      uniform float4   AmbiColor,
      uniform float4    SpecularColor,
      uniform float    LightIntensity,
      uniform float4    DiffuseColor,
      uniform float   SpecExpon,
      uniform float   Kd,
      uniform float   Ks,
      uniform float   Kr,
      uniform float   Bumpy,
    
      uniform sampler2D   colorSampler   : register(s0),
      uniform sampler2D   normalSampler   : register(s1),
      uniform sampler2D   glossSampler   : register(s2),
      uniform samplerCUBE envSampler     : register(s3)
      )
    {
      float3 map = tex2D(colorSampler,vsOutTexCoord.xy).rgb;
      float3 bumps = Bumpy * (tex2D(normalSampler,vsOutTexCoord.xy).xyz-(0.5).xxx);
      float gloss = Ks * tex2D(glossSampler,vsOutTexCoord.xy).x;
      float3 Nn = normalize(vsOutWorldNormal);
      float3 Tn = normalize(vsOutWorldTangent);
      float3 Bn = normalize(vsOutWorldBinorm);
      float3 Nb = Nn + (bumps.x * Tn + bumps.y * Bn);
      Nb = normalize(Nb);
      float3 Vn = normalize(vsOutWorldEyeVec);
    
      float falloff = LightIntensity/dot(vsOutLightVec1,vsOutLightVec1);
      float3 Ln = normalize(vsOutLightVec1);
      float3 Hn = normalize(Vn + Ln);
      float hdn = dot(Hn,Nb);
      float ldn = dot(Ln,Nb);
      float4 litV = lit(ldn,hdn,SpecExpon);
      float3 incident = falloff * litV.y * SpecularColor.rgb;
      float3 diffContrib = incident;
      float3 specContrib = litV.z * gloss * incident;
    
      float3 reflVect = reflect(Vn,Nb);
      float3 reflColor = Kr * texCUBE(envSampler,float4(reflVect, 1)).rgb;
    
      float3 result = (DiffuseColor.rgb*map) * (Kd*diffContrib + AmbiColor.rgb + specContrib + reflColor);
      fsOutColor = float4(result.rgb,1.0);
    }

    bumpyglossy.material

    vertex_program BumpGlossVS_HLSL hlsl
    {
      source bumpyglossy.hlsl
      entry_point bumpyGlossy_VS
      target vs_2_0
    
      default_params
      {
        param_named_auto   WvpXf    worldviewproj_matrix
        param_named_auto   WorldXf    worldview_matrix
        param_named_auto   WorldITXf    inverse_transpose_world_matrix 
        param_named_auto   ViewIXf    inverse_view_matrix
        param_named_auto   lightPos  light_position 0
      }
    }
    
    fragment_program BumpGlossFS_HLSL hlsl
    {
      source bumpyglossy.hlsl
      entry_point bumpyGlossy_FS
      target ps_2_0
    
      default_params
      {
        param_named_auto   AmbiColor    ambient_light_colour 0 
        param_named_auto   DiffuseColor  light_diffuse_colour 0
        param_named_auto   SpecularColor  light_specular_colour 0
        param_named      SpecExpon     float 12.0
        param_named      Kd         float 0.1
        param_named      Ks         float 0.8
        param_named      Kr         float 1.0
        param_named      Bumpy       float 2.0
        param_named      LightIntensity   float 20.0
      }
    }
    
    material bumpGloss
    {
      technique
      {
        pass first
        {
          vertex_program_ref BumpGlossVS_HLSL
          {
          }
          fragment_program_ref BumpGlossFS_HLSL
          {
          }
          texture_unit
          {
            texture Default_color.dds 2d
          }
          texture_unit
          {
            texture Default_bump_normal.dds 2d
          }
          texture_unit
          {
            texture Default_gloss.dds 2d
          }
          texture_unit
          {
            cubic_texture Default_reflection.dds combinedUVW
          }
        }
      }
    }

  • May1st

    Ogre3D HLSL Glow Balloon Shader Code

    The original HLSL shader code can be downloaded from NVIDIA at http://developer.download.nvidia.com/shaderlibrary/webpages/shader_library.html#post_glowBalloon

    Glow Baloon HLSL Shader Ogre3D

    To get the shader to work in Ogre3D, several changes have been made:

    • Autos (the projection matrices) have been passed in as parameters.
    • Matrix multiplication order has been reversed.
    • Structs have been replaced by long lists of parameters, including out parameters.

    glowballoon.hlsl

    void gloBalloon_VS(
      float4 position  : POSITION,
      float4 normal  : NORMAL,
    
      out float4 vsOutPos      : POSITION,
      out float3 vsOutWorldNorm  : TEXCOORD0,
      out float3 vsOutWorldView  : TEXCOORD1,
    
      uniform float    Inflate,
      uniform float4x4   WorldITXf,
      uniform float4x4   WorldXf,
      uniform float4x4   ViewIXf,
      uniform float4x4   WvpXf
    ) {
      vsOutWorldNorm = mul(WorldITXf,normal).xyz;
      float4 Po = float4(position.xyz,1); 
      Po += (Inflate*normalize(float4(normal.xyz,0))); // the balloon effect
      float4 Pw = mul(WorldXf,Po);
      vsOutWorldView = normalize(ViewIXf[3].xyz - Pw.xyz);
      vsOutPos = mul(WvpXf,Po);
    }
    
    void gloBalloon_PS(
      float3 vsOutWorldNorm  : TEXCOORD0,
      float3 vsOutWorldView  : TEXCOORD1,
    
      out float4 fsOutColor  : COLOR,
    
      uniform float3  GlowColor,
      uniform float  GlowExpon
    ) {
      float3 Nn = normalize(vsOutWorldNorm);
      float3 Vn = normalize(vsOutWorldView);
      float edge = 1.0 - dot(Nn,Vn);
      edge = pow(edge,GlowExpon);
      float3 result = edge * GlowColor.rgb;
      fsOutColor =  float4(result,edge);
    }

    glowballoon.material

    vertex_program BaloonVS_HLSL hlsl
    {
      source glowballoon.hlsl
      entry_point gloBalloon_VS
      target vs_2_0
    
      default_params
      {
        param_named_auto   WvpXf     worldviewproj_matrix
        param_named_auto   WorldXf   worldview_matrix
        param_named_auto   WorldITXf   inverse_transpose_world_matrix 
        param_named_auto   ViewIXf   inverse_view_matrix
        param_named      Inflate   float 1.5
      }
    }
    
    fragment_program BaloonFS_HLSL hlsl
    {
      source glowballoon.hlsl
      entry_point gloBalloon_PS
      target ps_2_0
    
      default_params
      {
        param_named      GlowColor   float3 1 0.9 1
        param_named      GlowExpon   float 1.2
      }
    }
    
    vertex_program VertexShaderVS_HLSL hlsl
    {
      source vertexlighting.hlsl
      entry_point mainVS
      target vs_2_0
    
      default_params
      {
        param_named_auto   worldViewProj   worldviewproj_matrix
        param_named_auto   world       worldview_matrix
        param_named_auto   cameraPos     camera_position
        param_named_auto   lightPos     light_position 0
        param_named_auto   ambientColor   ambient_light_colour 0 
        param_named_auto   diffColor     light_diffuse_colour 0
        param_named_auto   specColor     light_specular_colour 0
        param_named     shiny        float 25.0
      }
    }
    
    fragment_program VertexShaderFS_HLSL hlsl
    {
        source vertexlighting.hlsl
        entry_point mainFS
        target ps_2_0
    
        default_params
        {
        }
    }
    
    material GlowBalloon
    {
      technique
      {
        pass one
        {
          iteration once_per_light
          vertex_program_ref VertexShaderVS_HLSL
          {
          }
          fragment_program_ref VertexShaderFS_HLSL
          {
          }
          texture_unit
          {
            texture MRAMOR6X6.jpg
          }
        }
    
        pass two
        {
          scene_blend src_alpha one_minus_src_alpha
          depth_check on
          depth_func less_equal
          vertex_program_ref BaloonVS_HLSL
          {
          }
          fragment_program_ref BaloonFS_HLSL
          {
          }
        }
      }
    }

    And because my Ogre glow balloon is two pass shader, I’ll include the vertex lighting that illuminates the model underneath the balloon.

    vertexlighting.hlsl

    void mainVS(
      float4 position      : POSITION,
      float3 normal      : NORMAL,
      float2 UV          : TEXCOORD0,
      
      out float4 vsOutPos    : POSITION,
      out float4 vsOutColor  : COLOR,
      out float2 vsOutUV    : TEXCOORD0,
    
      uniform float4x4 worldViewProj,
      uniform float4x4 world,
      uniform float4    cameraPos,
      uniform float4    lightPos,
      uniform float4   ambientColor,
      uniform float4    diffColor,
      uniform float4    specColor,
      uniform float   shiny
      )
    {
      vsOutPos = mul(worldViewProj, position);
      vsOutUV = UV;
      
      float3 worldpos = mul(position, world);
     
      float3   lightDir= normalize( lightPos - worldpos );
      float3   viewDir  = normalize( cameraPos - worldpos );
     
      float   dotNL   = dot(normal,lightDir);
      float   diff   = saturate(dotNL);
     
      float3   ref   =  (normal * 2 * dotNL) - lightDir;
      float  dotRV  = dot(ref, viewDir);
      float   spec   = pow(saturate(dotRV), shiny); 
     
      vsOutColor = diff * diffColor + spec * specColor + ambientColor;
    }
    
    void mainFS(
      float4 vsOutColor    : COLOR,
      float2 vsOutUV      : TEXCOORD0,
      out float4 fsOutColor  : COLOR,
      uniform sampler2D image : register(s0)
      )
    {
      fsOutColor = vsOutColor + 0.25 * tex2D(image, vsOutUV);
    }