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:
// From page 128
struct Material {
float3 Ke;
float3 Ka;
float3 Kd;
float3 Ks;
float shininess;
};
Then in the code they do this:
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."
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:
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] ;
} ;
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!