DirectX Light and shadow detailed

Source: Internet
Author: User

Here I use the DirectX9 to achieve a piecemeal illumination and shadow mapping, shadow mapping algorithm and OpenGL the same, you watch carefully.

First, declare four shaders and get their constant handles:

void Initshaders () {storevertexshader=new Shader (".. /shader/store_vs.fx ", Shader_type_vs);modelmatrixstorehand=storevertexshader->consttable-> Getconstantbyname (NULL, "Modelmatrix");viewmatrixstorehand=storevertexshader->consttable-> Getconstantbyname (NULL, "Viewmatrix");p rojmatrixstorehand=storevertexshader->consttable-> Getconstantbyname (NULL, "Projmatrix"); Storepixshader=new Shader (".. /shader/store_ps.fx ", shader_type_ps); Texvertexshader=new shader (". /shader/tex_vs.fx ", Shader_type_vs); Modelmatrixhand=texvertexshader->consttable->getconstantbyname (NULL," Modelmatrix "); Viewmatrixhand=texvertexshader->consttable->getconstantbyname (NULL," ViewMatrix "); Projmatrixhand=texvertexshader->consttable->getconstantbyname (NULL, "Projmatrix"); normalMatrixHand= Texvertexshader->consttable->getconstantbyname (NULL, "Normalmatrix"); shadowmatrixhand=texvertexshader- >consttable->getconstantbyname (NULL, "Shadowmatrix"); Texpixshader=new Shader (".. /shader/tex_ps.fx ", SHADER_TYPE_PS); Ambhand=texpixshader->consttable->getconstantbyname (NULL, "Amb");d iffhand=texpixshader-> Consttable->getconstantbyname (NULL, "diff"); Lightdirhand=texpixshader->consttable->getconstantbyname ( NULL, "Lightdir"), Ambmtlhand=texpixshader->consttable->getconstantbyname (null, "AMBMTL");d iffmtlhand= Texpixshader->consttable->getconstantbyname (NULL, "DIFFMTL");}

The vertex with the beginning of s tore and the fragment shader are used when rendering the shadow map to hold the scene depth at the point of view of the light source, followed by the handle to the MVP transform matrix.

The vertex and fragment shader at the beginning of Tex are used when rendering the scene to perform a depth comparison and illumination operations, and then to obtain the MVP transform matrix, the normal transformation matrix, the light source viewpoint projection transformation matrix, and the various illumination parameter handles.

With these handles we can pass values to the constants in the shader.


Then set the illumination parameters:

Float Lightd[4] = {1.0f, 1.0f, -1.0f, 0.0f};float ambientlight[4] = {0.7f, 0.7f, 0.7f, 1.0f};float diffuselight[4] = {1.0f , 1.0f, 1.0f, 1.0f};float ambientlightmtl[4] = {0.7f, 0.7f, 0.7f, 1.0f};float diffuselightmtl[4] = {1.0f, 1.0f, 1.0f, 1.0f };void initlight () {D3dxvector4 amb (ambientlight);D 3dxvector4 diff (diffuselight);D 3dxvector4 lightdir (LIGHTD);D 3dxvector4 AMBMTL (AMBIENTLIGHTMTL);D 3dxvector4 diffmtl (DIFFUSELIGHTMTL);texpixshader->consttable-> Setvector (D3D,AMBHAND,&AMB); Texpixshader->consttable->setvector (D3d,diffhand,&diff); Texpixshader->consttable->setvector (D3d,lightdirhand,&lightdir);texpixshader->consttable-> Setvector (D3D,AMBMTLHAND,&AMBMTL); Texpixshader->consttable->setvector (D3D,DIFFMTLHAND,&DIFFMTL);}

These several lighting parameters in various fixed pipeline tutorials have appeared n many times, see these names should know the meaning of it.

To render the shadow map, pass the world transformation matrix to shader, just like this:

D3dxmatrix modelmatrix,scalemat,rotxmat,rotymat,tranmat;d3dxmatrixidentity (&modelmatrix);D 3DXMatrixScaling ( &scalemat,model->scale,model->scale,model->scale);D 3DXMatrixRotationX (&rotxmat,atr (model-> YR));D 3DXMatrixRotationY (&rotymat,atr (MODEL->XR));D 3DXMatrixTranslation (&tranmat,model->x,model- >Y,MODEL->Z); modelmatrix=modelmatrix*scalemat*rotxmat*rotymat*tranmat;storevertexshader->consttable- >setmatrix (D3d,modelmatrixstorehand,&modelmatrix); Model->rendersimple ();

It is also necessary to pass a normal transformation matrix when rendering a normal scene, it is important to remember that the normal world transformation matrix is not the world transformation matrix of the object, like this:

D3dxmatrix modelmatrix,scalemat,rotxmat,rotymat,tranmat;d3dxmatrixidentity (&modelmatrix);D 3DXMatrixScaling ( &scalemat,model->scale,model->scale,model->scale);D 3DXMatrixRotationX (&rotxmat,atr (model-> YR));D 3DXMatrixRotationY (&rotymat,atr (MODEL->XR));D 3DXMatrixTranslation (&tranmat,model->x,model- >Y,MODEL->Z); modelmatrix=modelmatrix*scalemat*rotxmat*rotymat*tranmat;texvertexshader->consttable- >setmatrix (D3d,modelmatrixhand,&modelmatrix);D 3DXMATRIX normalmatrix;d3dxmatrixidentity (& Normalmatrix);D 3DXMatrixInverse (&normalmatrix,null,&modelmatrix);D 3DXMatrixTranspose (&normalmatrix , &normalmatrix); Texvertexshader->consttable->setmatrix (D3d,normalmatrixhand,&normalmatrix); Model->render ();

Then get the default render target and depth cache:

D3d->getrendertarget (0,&defaultrendertarget);d 3d->getdepthstencilsurface (&defaultDepthSurface);

Then create a shadow texture, and the shadow texture renders the target with the depth cache used to render the shadow texture:

D3d->createtexture (shadowmapsize,shadowmapsize,1,d3dusage_rendertarget,d3dfmt_r32f,d3dpool_default,& Shadowmaptexture,null);d 3d->createdepthstencilsurface (shadowmapsize,shadowmapsize,d3dfmt_d24x8, D3dmultisample_none,0,true,&shadowdepthsurface,null); Shadowmaptexture->getsurfacelevel (0,& Shadowrendertarget);
Note that the format of the shaded texture here is r32f, which means that the shadow map is only available for the R channel and the GBA channel is unavailable.


And then the light that we want is the directional light, then the light projection matrix is an orthogonal matrix, so to create:

Float size=128;d3dxmatrixidentity (&lightprojectionmatrix);D 3DXMatrixOrthoOffCenterLH (& LIGHTPROJECTIONMATRIX,-SIZE,SIZE,-SIZE*2,SIZE*2,-SIZE*2,SIZE*2);
The size of this side can be defined by itself, the larger the value, the larger the shadow map range, but the fineness decreases.


The Light space View matrix is then established:

D3dxvector3 Viewpos (lightpos.x,lightpos.y,lightpos.z);D 3dxvector3 Tovec (cx,cy,cz);D 3dxvector3 upVec (0.0f,1.0f, 0.0f);D 3DXMatrixIdentity (&lightviewmatrix);D 3DXMatrixLookAtLH (&lightviewmatrix,&viewpos,&tovec , &upvec);


At the end of the rendering section, the shadow map is rendered first:

void Generateshadowmap (Callbackptr callback) {D3d->setrendertarget (0,shadowrendertarget);d 3d-> Setdepthstencilsurface (shadowdepthsurface);d 3d->clear (0,null,d3dclear_target| D3dclear_zbuffer,d3dxcolor (1.0f,1.0f,1.0f,1.0f), 1.0f,0);d 3d->beginscene ();d 3d->setrenderstate (D3DRS_ CULLMODE,D3DCULL_CW);d 3d->setvertexshader (Storevertexshader->vsprog);d 3d->setpixelshader ( Storepixshader->psprog); Storevertexshader->consttable->setmatrix (d3d,projmatrixstorehand,& Lightprojectionmatrix); Storevertexshader->consttable->setmatrix (d3d,viewmatrixstorehand,& Lightviewmatrix) callback ();d 3d->setrenderstate (D3DRS_CULLMODE,D3DCULL_CCW);d 3d->endscene ();
Turn the render target and depth cache into shadow maps, and then clear the color and depth, reset to 1.0 to indicate the maximum depth, the rendering depth can be taken clockwise to remove the front, and then you can render a lot less and the results will not be affected, after rendering and then reset back to counterclockwise.


Then the optical space projection transformation matrix is computed:

void Generateshadowmatrix () {Shadowmatrix=lightviewmatrix*lightprojectionmatrix;}

A normal scene rendering is then carried out, the optical space Projection transformation matrix is passed to the Texvertexshader, and the camera uses the view and projection transformation matrix:

void Drawshadowmap (Callbackptr callback) {d3d->setdepthstencilsurface (defaultdepthsurface);d 3d-> SetRenderTarget (0,defaultrendertarget);d 3d->clear (0,null,d3dclear_target| D3dclear_zbuffer,d3dxcolor (0.5f,0.7f,0.8f,0.5f), 1.0f,0);d 3d->beginscene ();d 3d->setvertexshader ( Texvertexshader->vsprog);d 3d->setpixelshader (Texpixshader->psprog); texvertexshader->consttable- >setmatrix (D3d,viewmatrixhand,&cameraviewmatrix); Texvertexshader->consttable->setmatrix (D3D, Projmatrixhand,&cameraprojectionmatrix); Texvertexshader->consttable->setmatrix (D3d,shadowMatrixHand, &shadowmatrix);d 3d->settexture (0,shadowmaptexture), callback ();d 3d->endscene ();
Note that the render target and depth cache are switched to the default before rendering, which is rendered to the screen instead of to the texture. Then clear the default color and depth cache.


This concludes the CPP code, and then look at shader.

First we use Storevertexshader to transform the scene vertex into the light space and then use Storepixshader to save the scene depth value to the shadow texture.

Storevertexshader:

float4x4 modelmatrix,viewmatrix,projmatrix;struct Input {float4 position:position;float4 normal:normal;float2 texcoord0:texcoord0;}; struct Output {float4 position:position;float4 clipvert:texcoord1;};o Utput main (Input input) {FLOAT4 Modelvert = input.position;float4x4 Mvpmatrix = Mul (Modelmatrix, Mul (Viewmatrix, Projmatr ix)); Float4 Clipvert = Mul (Modelvert, mvpmatrix); output output = (output) 0;output.position = Clipvert;output.clipvert = C Lipvert;return output;}

Note that the final result is the light clipping space, the range-W-+w.


Storepixshader:

struct Input {float4 clipvert:texcoord1;}; struct Output {float4 Pixcolor:color;};o Utput main (Input input) {FLOAT4 Clipvert = input.clipvert;float depth = clipvert.z/clipvert.w;output Output = (output) 0; Output.pixcolor = float4 (depth, depth, depth, depth); return output;}
Homogeneous division of the depth value makes it in the range of 0-1. Note that the output texture is in the range 0-1, which belongs to the light texture space.


Then use Texvertexshader and Texpixshader when rendering the scene normally.

Texvertexshader:

float4x4 modelmatrix,viewmatrix,projmatrix,normalmatrix;float4x4 shadowmatrix;struct Input {float4 position:position;float4 Normal:normal;float2 texcoord0:texcoord0;}; struct Output {float4 position:position;float2 texcoord0:texcoord0;float3 normal:texcoord1;float4 Shadowvert:texco Ord2;};o Utput main (Input input) {float4x4 Modelviewprojmatrix = Mul (Modelmatrix, Mul (Viewmatrix, Projmatrix)); Float4 Modelvert = Input.position;float4 Modelnormal = input.normal;float2 texCoord0 = input.texcoord0;float3 Worldnormal = Mul ( MODELNORMAL.XYZ, (float3x3) normalmatrix); Float4 Clipvert = Mul (Modelvert, Modelviewprojmatrix); Float4 Worldvert = Mul ( Modelvert, Modelmatrix); Float4 Shadowvert = Mul (Worldvert, shadowmatrix); output output = (output) 0;output.position = clipvert;output.texcoord0 = Texcoord0;output.normal = Worldnormal;output.shadowvert = ShadowVert;return output;} 
The result of the Shadowvert is that in the light clipping space, the following transformations are made in the fragment shader:

Light texture space, lighting standard coordinate space, light clipping space

Remember that only vectors within the same space can be operated on.


Then the Texpixshader:

FLOAT4 amb,diff,ambmtl,diffmtl,lightdir;texture textureshadow;texture texture1;texture Texture2;sampler TexShadow = sampler_state {Texture = <Texture0>; Minfilter = LINEAR; Magfilter = LINEAR;}; Sampler Tex1 = sampler_state {Texture = <Texture1>; Minfilter = LINEAR; Magfilter = LINEAR;}; Sampler Tex2 = sampler_state {Texture = <Texture2>; Minfilter = LINEAR; Magfilter = LINEAR;}; struct Input {float2 texcoord0:texcoord0;float3 normal:texcoord1;float4 shadowvert:texcoord2;}; struct Output {float4 pixcolor:color;};  Float Calcshadowfactor (float4 shadowvert) {float4 Shadowndcvert = shadowvert/shadowvert.w;float2 Shadowvertcoord = 0.5 * Shadowndcvert.xy + FLOAT2 (0.5, 0.5); shadowvertcoord.y = 1.0-shadowvertcoord.y;float Depthnow = Shadowndcvert.z;float de  Pthstore = tex2d (Texshadow, Shadowvertcoord). R;float factor = 1.0;float bias = -0.00005;if (ABS (shadowndcvert.x) <= 1.0 &&abs (SHADOWNDCVERT.Y) <=1.0 &&abs (shadowndcvert.z) <=1.0) factor = (Depthnow + Bias > Depthstore)? 0.0:1.0;return factor;} Float4 calclight (float3 normal,float shadowfactor) {FLOAT4 light = FLOAT4 (0.0,0.0,0.0,1.0); float ndotl = max (dot ( Normalize (LIGHTDIR.XYZ), normalize (normal)), 0.0); light = Amb * AMBMTL + diff * diffmtl * ndotl * Shadowfactor;return Ligh t;} Output main (Input input) {FLOAT4 Texcolor = (0.6 * tex2d (TEX1, input.texcoord0)) + (0.4 * tex2d (TEX2, input.texcoord0)); FL Oat Shadowfactor = Calcshadowfactor (Input.shadowvert); Float4 Lightcolor = Calclight (Input.normal, shadowFactor); O Utput output = (output) 0;output.pixcolor = Lightcolor * Texcolor;return output;}
First, a homogeneous division is computed Shadowndcvert illumination standard coordinate space coordinates, and then coordinate scaling and offset to obtain shadowvertcoord illumination texture space coordinates, note OpenGL and DirectX for texture coordinate representation of a little difference, OpenGL Texture coordinates y-axis upward, directx texture coordinate y-axis downward, and finally the shadow map with the depth of the shadow obtained by passing a light calculation function to calculate the light, the shadow parameter multiplied by the diffuse light to get the shadow, the light formula is the same as the previous vertex-based lighting formula.

Here's how the results look:


There's a lot of jagged, okay? We can use some filtering algorithms to eliminate these unsightly jagged edges in the shader that generate shadow textures.

The specific shadow filtering algorithm can refer to:

http://fabiensanglard.net/shadowmappingPCF/index.php

http://fabiensanglard.net/shadowmappingVSM/index.php





DirectX Light and shadow detailed

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.