\\ Home : Articoli : Stampa
Effect
Di RobyDx (del 27/03/2007 @ 21:10:20, in English, linkato 2335 volte)

 

Previous DirectX version worked with fixed pipeline. On the contrary, DirectX 10 it’s based on shaders. A shader it’s a code that describes trasformation rules that from vertex generates the scene. The 2 main shaders are vertex and pixel shader. The first moves vertex from its position in object space and from its position in projection space. The second, starting from output information given by vertex shader, creates all pixels and executes for each one the shader giving them the middle weight, using the output position given by pixel shader. Here is a shader example

struct VS_INPUT
{
    float4 Pos : POSITION;
    float4 color:COLOR;
};

struct PS_INPUT
{
    float4 Pos : SV_POSITION;
    float4 color:COLOR;
};

PS_INPUT VS( VS_INPUT input )
{
    PS_INPUT output = (PS_INPUT)0;
    output.Pos = input.Pos;
    output.color=input.color;
    return output;
}

float4 PS( PS_INPUT input) : SV_Target
{
    return input.color;
}

technique10 Render
{
    pass P0
    {
        SetVertexShader( CompileShader( vs_4_0, VS() ) );
        SetGeometryShader(NULL);
        SetPixelShader( CompileShader( ps_4_0, PS() ) );
    }
}

 This file it’s called Effect. An effect file it’s an ASCII file that has to be loaded during app execution. It can have any extension (but the standard suggests FX.) An effect can contain more shader for each tyme but there must be almost a vertex and a pixel shader. To be applyed we need to select a vertex, a pixel, and, optionally, a geometry shader. These 3 elements are reunite in a pass.

 A pass it’s the effect description. Passes are organized in techniques that can contain more passes, and an effect can contain more techniques.

technique10 Render
{
    pass P0
    {
        SetVertexShader( CompileShader( vs_4_0, VS() ) );
        SetGeometryShader(NULL);
        SetPixelShader( CompileShader( ps_4_0, PS() ) );
    }
}

In this examples we have got a technique called Render and a pass called P0. We can see that in pass are set 3 shaders, (but geometry shader it’s NULL). Vertex and Pixel Shader are the result of compilation of VS and PS functions above defined.

CompileShader( vs_4_0, VS() )

This command orders shader to compile the funciont VS() as a Vertex Shader with 4.0 version (in D3D10 it’s good to use ever 4.0 version. The previous versions could be set to use old shader version (used in DirectX9). In the same mode works pixel shader (using ps_4_0 instead of vs_4_0, obiously), and in the same mode we can compile Geometry Shader using gs_4_0, but it’s not the scope of our tutorial

Now let’s analize vertex shader.

struct VS_INPUT
{
    float4 Pos : POSITION;
    float4 color:COLOR;
};

struct PS_INPUT
{
    float4 Pos : SV_POSITION;
    float4 color:COLOR;
};

PS_INPUT VS( VS_INPUT input )
{
    PS_INPUT output = (PS_INPUT)0;
    output.Pos = input.Pos;
    output.color=input.color;
    return output;
}

VS function it’s a vertex shader. This funcion it’s called for each scene vertex. In input it receives a structure that it’s called VS_INPUT, that describes vertex format. The structure it’s defined by ourself: this let us to create vertex with any kind of informations. In output we will give another structure (again defined by ourself). In the function we can write anything we want, but the trade structures are a need for the shader. Shaders can’t trade informations between themself, and then we must use structures (as a bridge) to communicate with shaders.

struct VS_INPUT
{
    float4 Pos : POSITION;
    float4 color:COLOR;
};

In this example we have decided that as a input we will use a float4 variable (that contains 4 floats called x,y,z,w) that we will call Pos, and another float called color. We can do anything with these values, also variable names are in our hands. But look well the shader: after variable name, there are 2 dots and 2 semantics (POSITION and COLOR). There are names that are, as anything, in our hands (we can also write SHIT or FUCK) but these names will let to DirectX10 to pass data correctly. In our case we will create poligons with vertices composed by 8 values (4 for position, 4 for color), and with POSITION and COLOR we will understand, from DirectX, what is color and what is position

float4 PS( PS_INPUT input) : SV_Target
{
    return input.color;
}

The pixel shader it’s very similar to vertex shader, with a little difference: it will return only a float4, that is final color of pixel. In input it will take the PS_INPUT structure that we have generated from vertex shader.

This simple shader, for each vertex, takeas a float4 as position, one as color and send it to pixel shader that will sent to pixel shader that will return final color oin the screen. The PS_INPUT structure that we use it’s not important. We could also use different structures, the important thing it’s the semantic. The COLOR value from vertex shader will go on the COLOR value of pixel shader. For this, we must use right semantics.

Other 2 things:

SV_POSITION: means that that will be the final vertex position. Then vertex shader has to return a float4 with this semantics, otherwise, D3D10 will not know how to generate triangles.

SV_Target: means that pixel values will be sent to View Target. Pixel Shader must return this value.

In next tutorial we will go deep in this arguments.

ID3D10Effect* effect;

ID3D10Blob* error;
HRESULT hr=D3DX10CreateEffectFromFileA(filename,NULL,NULL,"fx_4_0",D3D10_SHADER_ENABLE_STRICTNESS,
0,device,NULL,NULL,&effect,&error,NULL);

The D3DX10CreateEffectFromFile loads a shader, compile it and prepares it for rendering. If hr will be = to S_OK then shader loading it’s ok, otherwise, there are som errors, as a file not found or code errors. The ID3D10Blog contains a memory buffer that it’s filled with compilation error. This can be read and used to understand error.

LPCSTR errorString=(LPCSTR) error->GetBufferPointer();

if error will be not equal to NULL, we must remember to release the pointer!

To apply an effect we must set technique and effect.

effect->GetTechniqueByIndex(0)->GetPassByIndex(0)->Apply(0);

GetTechnique returs as tructure to memorie technique, GetPass returns the pass and apply will set all to device (0 it’s a private value and we must leave it). We can also save the pass and use it directly without call it anytime. It’s possibile to find technique and passes also using a LPCSTR that describes it’s name. After Appply() fucntion, any thing will use that shader until we will not specify another shader (or will set nothing as shader). On the contrary of D3D9, there is not the End istruction that means to stop with that shader.

GetDesc, in shader class, are functions that give us description and information about technique and pass, to read about loaded shader.
In next tutorial we will use this shader to see a triangle!

Other information are, as ever, in D3D help.

A special thanks goes to Vincent who translate this lesson.