Package my effect in DX

Started by
8 comments, last by Nik02 14 years, 1 month ago
I would like to create a effect class in DX, but I don't know how to set parameters quickly acrodding their names.And I must use D3DXHANDLE. In XNA: expEffect.Parameters["Projection"].SetValue(camera.ProjectionMatrix); That's what I want above... What I mean is that how to associate D3DXHANDLE and patameters and just transfer data into shader from theri names when rendering.
Advertisement
You can pass a string instead of a D3DXHANDLE if you want.
effect->SetVector("LightColor", &lightColor);

You can also retrieve handles and cache them.
// During initializationlightColorHandle = effect->GetParameterByName(NULL, "LightColor");// During runtimeeffect->SetVector(lightColorHandle, &lightColor);
After packaging my shader class,I pass them looks like below:

Shader g_shader;
D3DXMATRIX world;
g_shader->setParemeters("gWorld",&world);


But I must search for the handleWorld by chars "gWorld",that's ineffective.
How do I avoid the search?
MJP showed you how to do it above - you basically ask for the handle with the character based name, which returns a handle object. Then you can use the handle from that point onward to set the objects.
As MJP said:
effect->SetVector("LightColor", &lightColor);
that's ineffective also,and that's why I use D3DXHANDLE.

struct Handle
{
char* name;
D3DXHANDLE handle;
}handle[MAX_NUM];

void MyShader::addParemeters(char* _p)
{
handle.name = _p;
handle.handle= effect->GetParameterByName(NULL, _p);
totalOfPar++;
}

void MyShader::setParemeters(char* _p, D3DXMATRIX* _m)
{
for(i=0;i<totalOfPar;i++)
{
if(strcmp(handle.name,_p))
effect->SetVector(handle.handle, &_m);
}
}


How can I avoid the "for" Circulation or the search?


EDIT: sorry, I misread what you have written. So you want to set all parameters with a single call, is that the idea? If so, I think you would need to use DX10 or DX11 to use constant buffers. It sounds like you are using DX9, so I'm not sure there is a solution for that...
Actually, you can set multiple adjacent constants with a single call in D3D9 as well. Set*ShaderConstants* methods have a parameter specifying how many registers you want to set.

You'd have to figure out the offsets of the variables and put your parameters in a structure that is perfectly equivalent to the register layout that you define in HLSL. The ID3DXConstantTable object can be used to calculate the registers corresponding to given variables. Note that the Effect framework already does this for you. And since the constant tables are static after the effect creation, it is very fast to access variables by handle anyway.

You can also force your HLSL variables to use particular registers, so you don't have to do the lookup from the host program. The syntax for a constant is as follows:

float4 example : register(c0); //variable "example" uses constant register 0.float2 anotherExample: register (c1); //you get the idea......


Then you could set both of these with a single call to Set*ShaderConstantsF, since they are adjacent in the register layout.

In D3D9, you have to use separate registers for vertex and pixel shaders since the API doesn't have the notion of unified pipeline architecture. Also, integer, float and bool registers have their own logical banks. And finally, there is only one bank of constant registers per the three datatypes per shader stage. This is in contrast to D3D10 and up, where there is several general-purpose constant buffers that can store any datatype.

Niko Suni

Quote:Original post by Jason Z
EDIT: sorry, I misread what you have written. So you want to set all parameters with a single call, is that the idea? If so, I think you would need to use DX10 or DX11 to use constant buffers. It sounds like you are using DX9, so I'm not sure there is a solution for that...


Thanks for JZ's reminder,I haven't learnt DX10 11 ,I must study hard..
Quote:Original post by Nik02
Actually, you can set multiple adjacent constants with a single call in D3D9 as well. Set*ShaderConstants* methods have a parameter specifying how many registers you want to set.

You'd have to figure out the offsets of the variables and put your parameters in a structure that is perfectly equivalent to the register layout that you define in HLSL. The ID3DXConstantTable object can be used to calculate the registers corresponding to given variables. Note that the Effect framework already does this for you. And since the constant tables are static after the effect creation, it is very fast to access variables by handle anyway.

You can also force your HLSL variables to use particular registers, so you don't have to do the lookup from the host program. The syntax for a constant is as follows:

float4 example : register(c0); //variable "example" uses constant register 0.float2 anotherExample: register (c1); //you get the idea......



Then you could set both of these with a single call to Set*ShaderConstantsF, since they are adjacent in the register layout.

In D3D9, you have to use separate registers for vertex and pixel shaders since the API doesn't have the notion of unified pipeline architecture. Also, integer, float and bool registers have their own logical banks. And finally, there is only one bank of constant registers per the three datatypes per shader stage. This is in contrast to D3D10 and up, where there is several general-purpose constant buffers that can store any datatype.


Very helpful ! thank you very much! 谢谢 呵呵
I forgot to mention: Since you're using the Effect system, you might want to use ID3DXEffect::SetRawValue. It effectively wraps Set*ShaderConstantsF, and you can give it the handle (or name) of the first variable to establish the first destination register.

Niko Suni

This topic is closed to new replies.

Advertisement