Search code examples
parametersstructparameter-passingcg

Retrieving a struct parameter from a Cg shader


I find this annoying but is there a better way to retrieve a struct parameter from a Cg shader?

In the 11_two_light_with_structs example (OpenGL), there's a struct Material in the shader:

Cg shader:

// From page 128
struct Material {
  float3 Ke;
  float3 Ka;
  float3 Kd;
  float3 Ks;
  float shininess;
};

Then in the code they do this:

C code:

myCgVertexParam_material_Ke = cgGetNamedParameter( myCgVertexProgram, "material.Ke" );
myCgVertexParam_material_Ka = cgGetNamedParameter( myCgVertexProgram, "material.Ka");
myCgVertexParam_material_Kd = cgGetNamedParameter( myCgVertexProgram, "material.Kd");
myCgVertexParam_material_Ks = cgGetNamedParameter( myCgVertexProgram, "material.Ks");

Seems tedious, can't you just do

myCgVertexParam_materialALL = cgGetNamedParameter( myCgVertexProgram, "material" ) ;

Then something like:

cgSetParameterValuefr( myCgVertexParam_materialALL, 13, brassMat ) ;//! no.

Here I'm trying to treat the struct as an array, but that last command doesn't work though, with the error "The parameter is not of a numeric type."


Solution

  • Cg just does it this way, and it is what it is.

    HLSL/D3D11 does improve this with the concept of CBUFFERS. What you end up being able to do is create a C-style struct in your C++ code that mirrors all the parameters in your shader, and flushing that all at once to the gpu, without having to do it by silly variable name:

    C++ code:

    struct GPUCDATA
    {
      // the concatenated modelview-projection matrix
      float modelViewProj[16] ;  // column major
      float diffuseLightPos[4] ;
      float diffuseLightColor[4] ;
      float specularLightPos[4] ;
      float specularLightColor[4] ;
      float eyePos[4] ;
    } ;
    

    hlslShader.vsh

    cbuffer Globals : register( b0 )
    {
      // the concatenated modelview-projection matrix
      float4x4 modelViewProj ;
      float4 diffuseLightPos ;
      float4 diffuseLightColor ;
      float4 specularLightPos ;
      float4 specularLightColor ;
      float4 eyePos ;
    } ;
    

    Then from C++:

    // gpu is the ID3D11DeviceContext
    D3D11_MAPPED_SUBRESOURCE mappedRes ;
    CHECK_HRESULT( gpu->Map( gpuCDataBuffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &mappedRes ), "Map gpucdatabuffer" );
    GPUCDATA* gpuMems = (GPUCDATA*)mappedRes.pData ;
    memcpy( gpuMems, &gpuCData, sizeof( GPUCDATA ) ) ; // write to the gpu mems.
    gpu->Unmap( gpuCDataBuffer, 0 ) ;
    gpu->VSSetConstantBuffers( 0, 1, &gpuCDataBuffer );
    gpu->PSSetConstantBuffers( 0, 1, &gpuCDataBuffer );
    

    And that's it!