Community

Upcoming Events

Unite 2010

11/10 - 11/12 @ Montréal, Canada

GDC China

12/5 - 12/7 @ Shanghai, China

Asia Game Show 2010

12/24 - 12/27

GDC 2011

2/28 - 3/4 @ San Francisco, CA

More events...

11/10 - 11/12 @ Montréal, Canada

GDC China

12/5 - 12/7 @ Shanghai, China

Asia Game Show 2010

12/24 - 12/27

GDC 2011

2/28 - 3/4 @ San Francisco, CA

More events...

Quick Stats

64 people currently visiting GDNet.

2406 articles in the reference section.

Help us fight cancer!

Join SETI Team GDNet!

2406 articles in the reference section.

Help us fight cancer!

Join SETI Team GDNet!

## RacorX4RacorX4 has gotten a few additional features compared to RacorX3. First of all this example will not use a plain quad anymore, it uses instead a Bézier patch class, that shows a round surface with a texture attached to it. To simulate light reflections, a combined diffuse and specular reflection model is used.
RacorX4 uses the trackball class provided with the Common files framework, to rotate and move the object. You can choose different specular colors with the <C> key and zoom in and out with the mouse wheel. ## Vertex Shader DeclarationCompared to RacorX3, additionally the texture coordinates will be mapped to input register v7. // shader decl DWORD dwDecl[] = { D3DVSD_STREAM(0), D3DVSD_REG(0, D3DVSDT_FLOAT3 ), // input register v0 D3DVSD_REG(3, D3DVSDT_FLOAT3 ), // normal in input register v3 D3DVSD_REG(7, D3DVSDT_FLOAT2), // tex coordinates D3DVSD_END() }; The corresponding layout of the vertex buffer in BPatch.h looks like: struct VERTICES { D3DXVECTOR3 vPosition; D3DXVECTOR3 vNormal; D3DXVECTOR2 uv; }; // Declare custom FVF macro. #define D3DFVF_VERTEX (D3DFVF_XYZ|D3DFVF_NORMAL|D3DFVF_TEX1) The third flag used in the custom FVF macro indicates the usage of one texture coordinate pair. This macro is provided to ## Setting the Vertex Shader ConstantsThe vertex shader constants are set in #define CLIP_MATRIX 0 #define CLIP_MATRIX_1 1 #define CLIP_MATRIX_2 2 #define CLIP_MATRIX_3 3 #define INVERSE_WORLD_MATRIX 8 #define INVERSE_WORLD_MATRIX_1 9 #define INVERSE_WORLD_MATRIX_2 10 #define LIGHT_VECTOR 11 #define EYE_VECTOR 12 #define SPEC_POWER 13 #define SPEC_COLOR 14 In // set the clip matrix m_pd3dDevice->SetVertexShaderConstant(CLIP_MATRIX, &(m_matWorld * m_matView * m_matProj),4); // set the world inverse matrix D3DXMATRIX matWorldInverse; D3DXMatrixInverse(&matWorldInverse, NULL, &m_matWorld); m_pd3dDevice->SetVertexShaderConstant(INVERSE_WORLD_MATRIX, matWorldInverse,3); // stuff for specular lighting // set eye vector E m_pd3dDevice->SetVertexShaderConstant(EYE_VECTOR, vEyePt,1); // specular color if(m_bKey['C']) { m_bKey['C']=0; ++m_dwCurrentColor; if(m_dwCurrentColor >= 3) m_dwCurrentColor=0; } m_pd3dDevice->SetVertexShaderConstant(SPEC_COLOR, m_vLightColor[m_dwCurrentColor], 1); Like in the previous example the concatenated world-, view- and projection matrix are set into The eye vector ( The user can pick one of the following specular colors with the <C> key: m_vLightColor[0]=D3DXVECTOR4(0.3f,0.1f,0.1f,1.0f); m_vLightColor[1]=D3DXVECTOR4(0.1f,0.5f,0.1f,1.0f); m_vLightColor[2]=D3DXVECTOR4(0.0f,0.1f,0.4f,1.0f); In // specular power m_pd3dDevice->SetVertexShaderConstant(SPEC_POWER, D3DXVECTOR4(0,10,25,50),1); // light direction D3DXVECTOR3 vLight(0,0,1); m_pd3dDevice->SetVertexShaderConstant(LIGHT_VECTOR, vLight,1); D3DXCOLOR matDiffuse(0.9f, 0.9f, 0.9f, 1.0f); m_pd3dDevice->SetVertexShaderConstant(DIFFUSE_COLOR, &matDiffuse, 1); As in the previous examples, the light is positioned at (0.0, 0.0, 1.0). There are four specular power values, from which one will be used in the vertex shader.
## The Vertex ShaderThe vertex shader handles a combined diffuse and specular reflection model: ; diffuse and specular vertex lighting #include "const.h" vs.1.1 ; transpose and transform to clip space mul r0, v0.x, c[CLIP_MATRIX] mad r0, v0.y, c[CLIP_MATRIX_1], r0 mad r0, v0.z, c[CLIP_MATRIX_2], r0 add oPos, c[CLIP_MATRIX_3], r0 ; output texture coords mov oT0, v7 ; transform normal dp3 r1.x, v3, c[INVERSE_WORLD_MATRIX] dp3 r1.y, v3, c[INVERSE_WORLD_MATRIX_1] dp3 r1.z, v3, c[INVERSE_WORLD_MATRIX_2] ; renormalize it dp3 r1.w, r1, r1 rsq r1.w, r1.w mul r1, r1, r1.w ; light vector L ; we need L towards the light, thus negate sign mov r5, -c[LIGHT_VECTOR] ; N dot L dp3 r0.x, r1, r5 ; compute normalized half vector H = L + V add r2, c[EYE_VECTOR], r5 ; L + V ; renormalize H dp3 r2.w, r2, r2 rsq r2.w, r2.w mul r2, r2, r2.w ; N dot H dp3 r0.y, r1, r2 ; compute specular and clamp values (lit) ; r0.x - N dot L ; r0.y - N dot H ; r0.w - specular power n mov r0.w, c[SPEC_POWER].y ; n must be between -128.0 and 128.0 lit r4, r0 ; diffuse color * diffuse intensity(r4.y) mul oD0, c[DIFFUSE_COLOR], r4.y ; specular color * specular intensity(r4.z) mul oD1, c[SPEC_COLOR], r4.z Compared to the vertex shader in the previous example program, this shader maps the texture coordinates to texture stage 0 with the following instruction: ; output texture coords mov oT0, v7 The corresponding texture stage states set for the shading of the pixels in the multitexturing unit will be shown below in the section named "Non-Shader specific code". The instructions that transform the normal and calculate the diffuse reflection were already discussed along with the previous example. The real new functionality in this shader is the calculation of the specular reflection, which happens in the code lines starting with the ## Specular ReflectionCompared to the diffuse reflection model, the appearance of the reflection depends in the specular reflection model on the position of the viewer. When the direction of the viewing coincides, or nearly coincides, with the direction of specular reflection, a bright highlight is observed. This simulates the reflection of a light source by a smooth, shiny and polished surface. To describe reflection from shiny surfaces an approximation is commonly used, which is called the Phong illumination model (not to be confused with Pong Shading), named after its creator Phong Bui Tong [Foley]. According to this model, a specular highlight is seen when the viewer is close to the direction of reflection. The intensity of light falls off sharply when the viewer moves away from the direction of the specular reflection.
A model describing this effect has to be aware of at least the location of the light source L, the location of the viewer V, and the orientation of the surface N. Additionally a vector R that describes the direction of the reflection might be useful. The half way vector H, that halfs the angle between L and V will be introduced below. The original Phong formula approximates the falloff of the intensity. It looks like this: kspecular cos where kspecular is a scalar coefficient showing the percentage of the incident light reflected. ß describes the angle between R and V. The exponent Together with the diffuse reflection model shown above, the Phong illumination model can be expressed in the following way: Ireflected = Idirected((N dot L) + kspecular cos cos Ireflected = Idirected((N dot L) + kspecular (R dot V) This is the generally accepted phong reflection equation. As the angle between V and R decreases, the specularity will rise. Because it is expensive to calculate the reflection vector R (mirror of light incidence around the surface normal), James F. Blinn [Blinn] introduced a way to do this using an imaginary vector H, which is defined as halfway between L and V. H is therefore: H = (L + V) / 2 When H coincides with N, the direction of the reflection coincides with the viewing direction V and a specular hightlight is observed. So the original formula (R dot V) is expanded to (N dot ((L + V) / 2)) or (N dot H) The complete Blinn-Phong model formula looks like: Ireflected = Idirected((N dot L) + kspecular (N dot H) Now back to the relevant code piece that calculates the specular reflection: ; compute normalized half vector H = L + V add r2, c[EYE_VECTOR], r5 ; L + V ; renormalize H dp3 r2.w, r2, r2 rsq r2.w, r2.w mul r2, r2, r2.w ; N dot H dp3 r0.y, r1, r2 ; compute specular and clamp values (lit) ; r0.x - N dot L ; r0.y - N dot H ; r0.w - specular power n mov r0.w, c[SPEC_POWER].y ; n must be between -128.0 and 128.0 lit r4, r0 The (N dot (L+V)) Although L + V is not equivalent to the half vector H, the term half vector H will be used throughout the upcoming examples. In the vertex shader source H is normalized in the following The reduction of the original Blinn-Phong formula reduces the number of vertex shader instructions and there leads to a higher performance. This is a typical way of optimizing vertex shader code on a functional level [Taylor]. Although L + V is not equivalent to H, the term vector H is used throughout the example source. One of the main instructions in this piece of code is the dest.x = 1; dest.y = 0; dest.z = 0; dest.w = 1; float power = src.w; const float MAXPOWER = 127.9961f; if (power < -MAXPOWER) power = -MAXPOWER; // Fits into 8.8 fixed point format else if (power > MAXPOWER) power = -MAXPOWER; // Fits into 8.8 fixed point format if (src.x > 0) { dest.y = src.x; if (src.y > 0) { // Allowed approximation is EXP(power * LOG(src.y)) dest.z = (float)(pow(src.y, power)); } }
The last two instructions multiply the intensity with the diffuse and specular color components and move them into their respective output registers: ; diffuse color * diffuse intensity(r4.y) mul oD0, c[DIFFUSE_COLOR], r4.y ; specular color * specular intensity(r4.z) mul oD1, c[SPEC_COLOR], r4.z ## Non-Shader specific CodeThis example uses the multitexturing unit to shade pixels. The proper texture stage states are set in // texture settings m_pd3dDevice->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_MODULATE); m_pd3dDevice->SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_TEXTURE); m_pd3dDevice->SetTextureStageState(0, D3DTSS_COLORARG2, D3DTA_DIFFUSE); m_pd3dDevice->SetTextureStageState( 1, D3DTSS_COLOROP, D3DTOP_DISABLE); m_pd3dDevice->SetTextureStageState( 1, D3DTSS_ALPHAOP, D3DTOP_DISABLE); m_pd3dDevice->SetTextureStageState( 0, D3DTSS_MINFILTER, D3DTEXF_LINEAR); m_pd3dDevice->SetTextureStageState( 0, D3DTSS_MAGFILTER, D3DTEXF_LINEAR); m_pd3dDevice->SetTextureStageState( 0, D3DTSS_MIPFILTER, D3DTEXF_LINEAR); m_pd3dDevice->SetTextureStageState( 0, D3DTSS_ADDRESSU, D3DTADDRESS_CLAMP); m_pd3dDevice->SetTextureStageState( 0, D3DTSS_ADDRESSV, D3DTADDRESS_CLAMP); This texture stage stages modulate the diffuse color with the texture color, disable texture stage 1 and switch on a bilinear filtering with the D3DTEXF_LINEAR flags for the D3DTSS_MINFILTER/D3DTSS_MAGFILTER texture stage states. The D3DTSS_MIPFILTER texture stage state indicates the texture filter to use between mipmap levels. By providing D3DTEXF_LINEAR, trilinear texture filtering, or mip map filtering is switched on. The clamp texture-addressing mode applies the texture only once on the polygon and then smears the color of the edge pixels of the texture. Furthermore it cut off all negative values to 0 by remaining the positive values unchanged. We use a Bézier patch here to build up the surface used on source provided by ShaderX author Bart Sekura. A Bézier patch is the surface extension of the Bézier curve. Whereas a curve is a function of one variable and takes a sequence of control points, the patch is a function of two variables with an array of control points. A Bézier patch can be viewed as a continuous zet of Bézier curves. The Bézier patch is the most commonly used surface representation in the computer graphic (see [Skinner]). ## SummarizeRacorX4 shows a specular reflection model, that is very similar to the Blinn-Phong reflection model. Additionally it shows the functionality behind the |