3d環境貼圖,3DShader之陰影貼圖(Shadow Mapping)

 2023-11-12 阅读 17 评论 0

摘要:好久沒寫shader了,一直被實驗室要求作java開發,中間準備了一個月雅思,最近又被老師拉到東莞做Hadoop開發。馬上面臨畢業的問題了,突然人生苦短,趁有生之年多做點自己喜歡的事情吧,所以最近又開始拾起自己喜歡的Shader了。繼續自己偉大的航

好久沒寫shader了,一直被實驗室要求作java開發,中間準備了一個月雅思,最近又被老師拉到東莞做Hadoop開發。馬上面臨畢業的問題了,突然人生苦短,趁有生之年多做點自己喜歡的事情吧,所以最近又開始拾起自己喜歡的Shader了。繼續自己偉大的航程。以后我覺得一個星期應該寫一個Shader,不管有什么大事發生。

今天的Shader講解下Shadow Mapping.國際慣例,上圖先:


3d環境貼圖?



好了,講下原理

3ds畫質補丁、

先從燈光的視角出發,將場景渲染到紋理shadow map,這里儲存的各像素到光源的距離。


然后從攝相機的視角出發,渲染每個像素,將每個像素的坐標從攝相機的view空間轉成燈光的標準設置坐標,其x,y分量除以w就可以對shadow map進行采樣了。如果此點到燈光的距離大于采樣出來的值說明處于陰影當中。否則應該照亮。

3ds游戲高清紋理包,

另外,有幾個小問題需要講解下:


先插入另外一仁兄的博文:http://blog.csdn.net/zjull/article/details/11740505

3d陰影怎么調,

==================引入開始===================

0、簡介

Shadow Mapping是一種基于圖像空間的陰影實現方法,其優點是實現簡單,適應于大型動態場景;缺點是由于shadow map的分辨率有限,使得陰影邊緣容易出現鋸齒(Aliasing);關于SM的研究很活躍,主要圍繞著陰影抗鋸齒,出現了很多SM變種,如PSM,LPSM,VSM等等,在這里http://en.wikipedia.org/wiki/Shadow_mapping可以找到很多SM變種的鏈接;;SM的實現分為兩個pass,第一個pass以投射陰影的燈光為視點渲染得到一幅深度圖紋理,該紋理就叫Shadow Map;第二個pass從攝像機渲染場景,但必須在ps中計算像素在燈光坐標系中的深度值,并與Shadow Map中的相應深度值進行比較以確定該像素是否處于陰影區;經過這兩個pass最終就可以為場景打上陰影。這篇文章主要總結一下自己在實現基本SM的過程中遇到的一些問題以及解決方法,下面進入正題。

1、生成Shadow Map

為了從燈光角度渲染生成Shadow Map,有兩個問題需要解決:一是要渲染哪些物體,二是攝像機的參數怎么設置。對于問題一,顯然我們沒必要渲染場景中的所有物體,但是只渲染當前攝像機視景體中的物體又不夠,因為視景體之外的有些物體也可能投射陰影到視景體之內的物體,所以渲染Shadow Map時,這些物體必須考慮進來,否則可能會出現陰影隨著攝像機的移動時有時無的現象,綜上,我們只需要渲染位于當前攝像機視景體內的所有物體以及視景體之外但是會投射陰影到視景體之內的物體上的物體,把它們的集合稱為陰影投射集,為了確定陰影投射集,可以根據燈光位置以及當前的視景體計算出一個凸殼,位于該凸殼中的物體才需要渲染,如圖1所示。對于問題二,燈光處攝像機的視景體應該包含陰影投射集中的所有物體,另外應該讓物體盡量占據設置的視口,以提高Shadow Map的精度;對于方向光和聚光燈,攝像機的look向量可以設置為光的發射發向,攝像機的位置設置為燈光所在的位置,為了包含陰影集中的所有物體,可以計算陰影投射集在燈光視圖空間中的軸向包圍盒,然后根據面向光源的那個面設置正交投影參數,就可以保證投射集中的所有物體都位于燈光視景體中,并且剛好占據整個視口,如圖2所示。更詳細的信息可以參考《Mathematics for 3D Game Programming and Computer Graphics, Third Edition》一書的10.2節。


圖1:燈光位置與視景體構成一個凸殼,與該凸殼相交的物體稱為陰影投射集

3dshell?

圖2:根據陰影投射集在燈光視圖空間中的包圍盒來計算正交投影參數

2、生成陰影場景

生成了ShadowMap之后,就可以根據相應燈光的視圖矩陣和投影矩陣從攝像機角度渲染帶有陰影的場景了。下面把相關的shader代碼貼上:

vertex shader:

// for projective texturing
uniform mat4 worldMatrix;
uniform mat4 lightViewMatrix;
uniform mat4 lightProjMatrix;varying vec4 projTexCoord;void main()
{// for projective texture mappingprojTexCoord = lightProjMatrix*lightViewMatrix*worldMatrix*pos;// map project tex coord to [0,1]projTexCoord.x = (projTexCoord.x + projTexCoord.w)*0.5;projTexCoord.y = (projTexCoord.y + projTexCoord.w)*0.5;projTexCoord.z = (projTexCoord.z + projTexCoord.w)*0.5;gl_Position = gl_ModelViewProjectionMatrix * pos;

pixel shader(版本一):

// The shadow map
uniform sampler2DShadow shadowDepthMap;varying vec4 projTexCoord;void main()
{// light computingvec4 lightColor = Lighting(...);vec4 texcoord = projTexCoord;texcoord.x /= texcoord.w;texcoord.y /= texcoord.w;texcoord.z /= texcoord.w;// depth comparisonvec4 color = vec4(1.0,1.0,1.0,1.0);float depth = texture(shadowDepthMap,vec3(texcoord.xy,0.0));if(texcoord.z > depth){// this pixel is in shadow areacolor = vec4(0.6,0.6,0.6,1.0);}gl_FragColor = lightColor*color;
}

這樣就實現了最基本的Shadow Mapping,對于每個像素只采樣一個深度texel,看看效果吧。

3ds貼紙。

?圖3:最基本的Shadow Mapping

可以看到效果不盡如人意,主要有三個問題(分別對應上圖標記):1、物體的背光面當作陰影處理了;2、正對著光的一些像素也劃到陰影區去了(Self-shadowing);3、陰影邊緣有比較強的鋸齒效果。對于問題一,可以判斷當前像素是否背著燈光,方法是求得像素在燈光視圖空間中的位置以及法線,然后求一個點積就可以了,對于這種像素,不用進行陰影計算即可;問題二產生的原因是深度誤差導致的,當物體表面在燈光視圖空間中的傾斜度越大時,誤差也越大;解決辦法有多種,第一種是在進行深度比較時,將深度值減去一個閾值再進行比較,第二種是在生成shadow map時,只繪制背面,即將背面設置反轉,第三種方法是使用OpenGL提供的depth offset,在生成shadow map時,給深度值都加上一個跟像素斜率相關的值;第一種方法閾值比較難確定,無法完全解決Self-shadowing問題,第二種方法在場景中都是二維流形物體時可以工作的很好,第三種方法在絕大多數情況都可以工作得很好,這里使用這種方法,如下面代碼所示:

        // handle depth precision problemglEnable(GL_POLYGON_OFFSET_FILL);glPolygonOffset(1.0f,1.0f);// 繪制陰影投射集中的物體glDisable(GL_POLYGON_OFFSET_FILL);

解決第一和第二個問題后的效果如下面所示圖4所示:

3D?


圖4:解決背光面陰影和Self-shadowing問題之后的效果

還有最后一個問題未解決,從上面的圖也可看得出來,陰影邊緣鋸齒比較嚴重,解決這個問題也有兩種較常用方法,第一種方法是用PCF(Percentage Closer Filtering),基本思想是對每個像素從shadow map中采樣相鄰的多個值,然后對每個值都進行深度比較,如果該像素處于陰影區就把比較結果記為0,否則記為1,最后把比較結果全部加起來除以采樣點的個數就可以得到一個百分比p,表示其處在陰影區的可能性,若p為0代表該像素完全處于陰影區,若p為1表示完全不處于陰影區,最后根據p值設定混合系數即可。第二種方法是在陰影渲染pass中不計算光照,只計算陰影,可以得到一幅黑白二值圖像,黑色的表示陰影,白色表示非陰影,然后對這幅圖像進行高斯模糊,以對陰影邊緣進行平滑,以減小據齒效果,最后在光照pass中將像素的光照值與相應二值圖像中的值相乘就可以得到打上柔和陰影的場景了;在理論上來說,兩種方法都能達到柔和陰影的效果,本文采用的PCF方法,第二種方法后面會嘗試,并在效果和速度上與PCF做一下比較,等測試完了會貼到這里來。下面貼上加了PCF的像素shader的代碼:

// The shadow map
uniform sampler2DShadow shadowDepthMap;varying vec4 projTexCoord;void main()
{// light computingvec4 lightColor = Lighting(...);float shadeFactor = 0.0;shadeFactor += textureProjOffset(shadowDepthMap, projTexCoord, ivec2(-1, -1));shadeFactor += textureProjOffset(shadowDepthMap, projTexCoord, ivec2(-1, 1));shadeFactor += textureProjOffset(shadowDepthMap, projTexCoord, ivec2( 1, -1));shadeFactor += textureProjOffset(shadowDepthMap, projTexCoord, ivec2( 1, 1));shadeFactor *= 0.25;// map from [0.0,1.0] to [0.6,1.0]shadeFactor = shadeFactor * 0.4 + 0.6; gl_FragColor = lightColor*shadeFactor;
}

另外注意要對shadow map紋理設置以下紋理參數:

glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_COMPARE_MODE,GL_COMPARE_REF_TO_TEXTURE);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_COMPARE_FUNC,GL_LEQUAL);

PCF效果如下圖 所示,可以看到陰影邊緣變柔和了:

3d渲染陰影部分太暗怎么辦?


圖5:柔和的陰影邊緣(PCF:采樣pattern:左上,左下,右下,右上)

3、結語

關于Shadow Map的變種有很多,不同的變種針對不同情況不同場景提供SM陰影抗鋸齒解決方案,本文實現的只是基本的SM,后面考慮實現某種SM變種,進一步提高陰影的效果。


3d實體模式怎么不顯示陰影。==================引入結束===================

我先貼下源代碼,后面我會關于第二個問題著重講下:


/*------------------------------------------------------------
ShadowMap.cpp -- achieve shadow map
(c) Seamanj.2014/4/28
------------------------------------------------------------*/// phase1 : add view camera & light camera
// phase2 : add objects
// phase3 : add light
// phase4 : add shadow map effect
// phase5 : render the shadow map
// phase6 : render the scene
#include "DXUT.h"
#include "resource.h"#define phase1 1
#define phase2 1
#define phase3 1
#define phase4 1
#define phase5 1
#define phase6 1#if phase1
#include "DXUTcamera.h"
CFirstPersonCamera g_VCamera;
CFirstPersonCamera g_LCamera;
bool                            g_bRightMouseDown = false;// Indicates whether right mouse button is held#endif#if phase2
#include "SDKmesh.h"
#include "SDKmisc.h"
LPCWSTR g_aszMeshFile[] =
{L"BasicColumnScene.x",L"car.x"
};
#define NUM_OBJ (sizeof(g_aszMeshFile)/sizeof(g_aszMeshFile[0]))D3DXMATRIXA16 g_amInitObjWorld[NUM_OBJ] =
{D3DXMATRIXA16( 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f,1.0f ),D3DXMATRIXA16( 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 2.35f, 0.0f,1.0f )
};D3DVERTEXELEMENT9 g_aVertDecl[] =
{{ 0, 0,  D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0 },{ 0, 12, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL,   0 },{ 0, 24, D3DDECLTYPE_FLOAT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0 },D3DDECL_END()
};
//-----------------------------------------------------------------------------
// Name: class CObj
// Desc: Encapsulates a mesh object in the scene by grouping its world matrix
//       with the mesh.
//-----------------------------------------------------------------------------
#pragma warning( disable : 4324 )
struct CObj
{CDXUTXFileMesh m_Mesh;D3DXMATRIXA16 m_mWorld;
};
CObj g_Obj[NUM_OBJ];         // Scene object meshes
#endif#if phase3
D3DLIGHT9                       g_Light;                // The spot light in the scene
CDXUTXFileMesh                  g_LightMesh;
float                           g_fLightFov;            // FOV of the spot light (in radian)
#endif#if phase4
ID3DXEffect*	g_pEffect = NULL;       // D3DX effect interface
#endif#if phase5
#define ShadowMap_SIZE 512
LPDIRECT3DTEXTURE9              g_pTexDef = NULL;       // Default texture for objects
LPDIRECT3DTEXTURE9              g_pShadowMap = NULL;    // Texture to which the shadow map is rendered
LPDIRECT3DSURFACE9              g_pDSShadow = NULL;     // Depth-stencil buffer for rendering to shadow map
D3DXMATRIXA16                   g_mShadowProj;          // Projection matrix for shadow map
#endif//--------------------------------------------------------------------------------------
// Rejects any D3D9 devices that aren't acceptable to the app by returning false
//--------------------------------------------------------------------------------------
bool CALLBACK IsD3D9DeviceAcceptable( D3DCAPS9* pCaps, D3DFORMAT AdapterFormat, D3DFORMAT BackBufferFormat,bool bWindowed, void* pUserContext )
{// Typically want to skip back buffer formats that don't support alpha blendingIDirect3D9* pD3D = DXUTGetD3D9Object();if( FAILED( pD3D->CheckDeviceFormat( pCaps->AdapterOrdinal, pCaps->DeviceType,AdapterFormat, D3DUSAGE_QUERY_POSTPIXELSHADER_BLENDING,D3DRTYPE_TEXTURE, BackBufferFormat ) ) )return false;// Must support pixel shader 2.0if( pCaps->PixelShaderVersion < D3DPS_VERSION( 2, 0 ) )return false;// need to support D3DFMT_R32F render targetif( FAILED( pD3D->CheckDeviceFormat( pCaps->AdapterOrdinal, pCaps->DeviceType,AdapterFormat, D3DUSAGE_RENDERTARGET,D3DRTYPE_CUBETEXTURE, D3DFMT_R32F ) ) )return false;// need to support D3DFMT_A8R8G8B8 render targetif( FAILED( pD3D->CheckDeviceFormat( pCaps->AdapterOrdinal, pCaps->DeviceType,AdapterFormat, D3DUSAGE_RENDERTARGET,D3DRTYPE_CUBETEXTURE, D3DFMT_A8R8G8B8 ) ) )return false;return true;
}//--------------------------------------------------------------------------------------
// Before a device is created, modify the device settings as needed
//--------------------------------------------------------------------------------------
bool CALLBACK ModifyDeviceSettings( DXUTDeviceSettings* pDeviceSettings, void* pUserContext )
{assert( DXUT_D3D9_DEVICE == pDeviceSettings->ver );HRESULT hr;IDirect3D9* pD3D = DXUTGetD3D9Object();D3DCAPS9 caps;V( pD3D->GetDeviceCaps( pDeviceSettings->d3d9.AdapterOrdinal,pDeviceSettings->d3d9.DeviceType,&caps ) );// Turn vsync offpDeviceSettings->d3d9.pp.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE;// If device doesn't support HW T&L or doesn't support 1.1 vertex shaders in HW // then switch to SWVP.if( ( caps.DevCaps & D3DDEVCAPS_HWTRANSFORMANDLIGHT ) == 0 ||caps.VertexShaderVersion < D3DVS_VERSION( 1, 1 ) ){pDeviceSettings->d3d9.BehaviorFlags = D3DCREATE_SOFTWARE_VERTEXPROCESSING;}// Debugging vertex shaders requires either REF or software vertex processing // and debugging pixel shaders requires REF.  
#ifdef DEBUG_VSif( pDeviceSettings->d3d9.DeviceType != D3DDEVTYPE_REF ){pDeviceSettings->d3d9.BehaviorFlags &= ~D3DCREATE_HARDWARE_VERTEXPROCESSING;pDeviceSettings->d3d9.BehaviorFlags &= ~D3DCREATE_PUREDEVICE;pDeviceSettings->d3d9.BehaviorFlags |= D3DCREATE_SOFTWARE_VERTEXPROCESSING;}
#endif
#ifdef DEBUG_PSpDeviceSettings->d3d9.DeviceType = D3DDEVTYPE_REF;
#endif// For the first device created if its a REF device, optionally display a warning dialog boxstatic bool s_bFirstTime = true;if( s_bFirstTime ){s_bFirstTime = false;if( pDeviceSettings->d3d9.DeviceType == D3DDEVTYPE_REF )DXUTDisplaySwitchingToREFWarning( pDeviceSettings->ver );}return true;
}//--------------------------------------------------------------------------------------
// Create any D3D9 resources that will live through a device reset (D3DPOOL_MANAGED)
// and aren't tied to the back buffer size
//--------------------------------------------------------------------------------------
HRESULT CALLBACK OnD3D9CreateDevice( IDirect3DDevice9* pd3dDevice, const D3DSURFACE_DESC* pBackBufferSurfaceDesc,void* pUserContext )
{HRESULT hr;
#if phase2WCHAR str[MAX_PATH];// Initialize the meshesfor( int i = 0; i < NUM_OBJ; ++i ){V_RETURN( DXUTFindDXSDKMediaFileCch( str, MAX_PATH, g_aszMeshFile[i] ) );if( FAILED( g_Obj[i].m_Mesh.Create( pd3dDevice, str ) ) )return DXUTERR_MEDIANOTFOUND;V_RETURN( g_Obj[i].m_Mesh.SetVertexDecl( pd3dDevice, g_aVertDecl ) );g_Obj[i].m_mWorld = g_amInitObjWorld[i];}
#endif
#if phase3// Initialize the light meshV_RETURN( DXUTFindDXSDKMediaFileCch( str, MAX_PATH, L"spotlight.x" ) );if( FAILED( g_LightMesh.Create( pd3dDevice, str ) ) )return DXUTERR_MEDIANOTFOUND;V_RETURN( g_LightMesh.SetVertexDecl( pd3dDevice, g_aVertDecl ) );
#endif
#if phase4// Read the D3DX effect fileV_RETURN( DXUTFindDXSDKMediaFileCch( str, MAX_PATH, L"ShadowMap.fx" ) );// Create the effect LPD3DXBUFFER pErrorBuff;V_RETURN( D3DXCreateEffectFromFile(pd3dDevice,		// associated devicestr,			// effect filenameNULL,			// no preprocessor definitionsNULL,			// no ID3DXInclude interfaceD3DXSHADER_DEBUG,	// compile flagsNULL,			// don't share parameters&g_pEffect,		// return effect&pErrorBuff			// return error messages) );#endifreturn S_OK;
}//--------------------------------------------------------------------------------------
// Create any D3D9 resources that won't live through a device reset (D3DPOOL_DEFAULT) 
// or that are tied to the back buffer size 
//--------------------------------------------------------------------------------------
HRESULT CALLBACK OnD3D9ResetDevice( IDirect3DDevice9* pd3dDevice, const D3DSURFACE_DESC* pBackBufferSurfaceDesc,void* pUserContext )
{HRESULT hr;
#if phase1// Setup the camera's projection parametersfloat fAspectRatio = pBackBufferSurfaceDesc->Width / ( FLOAT )pBackBufferSurfaceDesc->Height;g_VCamera.SetProjParams( D3DX_PI / 4, fAspectRatio, 0.1f, 500.0f );g_LCamera.SetProjParams( D3DX_PI / 4, fAspectRatio, 0.1f, 500.0f );
#endif
#if phase2// Restore the scene objectsfor( int i = 0; i < NUM_OBJ; ++i )V_RETURN( g_Obj[i].m_Mesh.RestoreDeviceObjects( pd3dDevice ) );
#endif
#if phase3V_RETURN( g_LightMesh.RestoreDeviceObjects( pd3dDevice ) );
#endif
#if phase4if( g_pEffect )V_RETURN( g_pEffect->OnResetDevice() );
#endif
#if phase5// Create the default texture (used when a triangle does not use a texture)V_RETURN( pd3dDevice->CreateTexture( 1, 1, 1, D3DUSAGE_DYNAMIC, D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT, &g_pTexDef,NULL ) );D3DLOCKED_RECT lr;V_RETURN( g_pTexDef->LockRect( 0, &lr, NULL, 0 ) );*( LPDWORD )lr.pBits = D3DCOLOR_RGBA( 255, 255, 255, 255 );V_RETURN( g_pTexDef->UnlockRect( 0 ) );// Create the shadow map textureV_RETURN( pd3dDevice->CreateTexture( ShadowMap_SIZE, ShadowMap_SIZE,1, D3DUSAGE_RENDERTARGET,D3DFMT_R32F,D3DPOOL_DEFAULT,&g_pShadowMap,NULL ) );// Create the depth-stencil buffer to be used with the shadow map// We do this to ensure that the depth-stencil buffer is large// enough and has correct multisample type/quality when rendering// the shadow map.  The default depth-stencil buffer created during// device creation will not be large enough if the user resizes the// window to a very small size.  Furthermore, if the device is created// with multisampling, the default depth-stencil buffer will not// work with the shadow map texture because texture render targets// do not support multisample.DXUTDeviceSettings d3dSettings = DXUTGetDeviceSettings();V_RETURN( pd3dDevice->CreateDepthStencilSurface( ShadowMap_SIZE,ShadowMap_SIZE,d3dSettings.d3d9.pp.AutoDepthStencilFormat,D3DMULTISAMPLE_NONE,0,TRUE,&g_pDSShadow,NULL ) );// Initialize the shadow projection matrixD3DXMatrixPerspectiveFovLH( &g_mShadowProj, g_fLightFov, 1, 0.01f, 100.0f );
#endif
#if phase6// Restore the effect variablesV_RETURN( g_pEffect->SetVector( "g_vLightDiffuse", ( D3DXVECTOR4* )&g_Light.Diffuse ) );V_RETURN( g_pEffect->SetFloat( "g_fCosTheta", cosf( g_Light.Theta ) ) );
#endifreturn S_OK;
}//--------------------------------------------------------------------------------------
// Handle updates to the scene.  This is called regardless of which D3D API is used
//--------------------------------------------------------------------------------------
void CALLBACK OnFrameMove( double fTime, float fElapsedTime, void* pUserContext )
{
#if phase1// Update the camera's position based on user input g_VCamera.FrameMove( fElapsedTime );g_LCamera.FrameMove( fElapsedTime );
#endif
}#if phase5
//--------------------------------------------------------------------------------------
// Renders the scene onto the current render target using the current
// technique in the effect.
//--------------------------------------------------------------------------------------
void RenderScene( IDirect3DDevice9* pd3dDevice, bool bRenderShadow, float fElapsedTime, const D3DXMATRIX* pmView,const D3DXMATRIX* pmProj )
{HRESULT hr;// Set the projection matrixV( g_pEffect->SetMatrix( "g_mProj", pmProj ) );// Freely moveable light. Get light parameter// from the light camera.D3DXVECTOR3 v = *g_LCamera.GetEyePt();D3DXVECTOR4 v4;//(0,0,0,1);D3DXVec3Transform( &v4, &v, pmView );V( g_pEffect->SetVector( "g_vLightPos", &v4 ) );*( D3DXVECTOR3* )&v4 = *g_LCamera.GetWorldAhead();v4.w = 0.0f;  // Set w 0 so that the translation part doesn't come to playD3DXVec4Transform( &v4, &v4, pmView );  // Direction in view spaceD3DXVec3Normalize( ( D3DXVECTOR3* )&v4, ( D3DXVECTOR3* )&v4 );V( g_pEffect->SetVector( "g_vLightDir", &v4 ) );// Clear the render buffersV( pd3dDevice->Clear( 0L, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER,0x000000ff, 1.0f, 0L ) );if( bRenderShadow )V( g_pEffect->SetTechnique( "RenderShadow" ) );// Begin the sceneif( SUCCEEDED( pd3dDevice->BeginScene() ) ){if( !bRenderShadow )V( g_pEffect->SetTechnique( "RenderScene" ) );// Render the objectsfor( int obj = 0; obj < NUM_OBJ; ++obj ){D3DXMATRIXA16 mWorldView = g_Obj[obj].m_mWorld;D3DXMatrixMultiply( &mWorldView, &mWorldView, pmView );V( g_pEffect->SetMatrix( "g_mWorldView", &mWorldView ) );LPD3DXMESH pMesh = g_Obj[obj].m_Mesh.GetMesh();UINT cPass;V( g_pEffect->Begin( &cPass, 0 ) );for( UINT p = 0; p < cPass; ++p ){V( g_pEffect->BeginPass( p ) );for( DWORD i = 0; i < g_Obj[obj].m_Mesh.m_dwNumMaterials; ++i ){D3DXVECTOR4 vDif( g_Obj[obj].m_Mesh.m_pMaterials[i].Diffuse.r,g_Obj[obj].m_Mesh.m_pMaterials[i].Diffuse.g,g_Obj[obj].m_Mesh.m_pMaterials[i].Diffuse.b,g_Obj[obj].m_Mesh.m_pMaterials[i].Diffuse.a );V( g_pEffect->SetVector( "g_vMaterial", &vDif ) );if( g_Obj[obj].m_Mesh.m_pTextures[i] )V( g_pEffect->SetTexture( "g_txScene", g_Obj[obj].m_Mesh.m_pTextures[i] ) )elseV( g_pEffect->SetTexture( "g_txScene", g_pTexDef ) )V( g_pEffect->CommitChanges() );V( pMesh->DrawSubset( i ) );}V( g_pEffect->EndPass() );}V( g_pEffect->End() );}
#if phase6// Render lightif( !bRenderShadow )V( g_pEffect->SetTechnique( "RenderLight" ) );D3DXMATRIXA16 mWorldView = *g_LCamera.GetWorldMatrix();D3DXMatrixMultiply( &mWorldView, &mWorldView, pmView );V( g_pEffect->SetMatrix( "g_mWorldView", &mWorldView ) );UINT cPass;LPD3DXMESH pMesh = g_LightMesh.GetMesh();V( g_pEffect->Begin( &cPass, 0 ) );for( UINT p = 0; p < cPass; ++p ){V( g_pEffect->BeginPass( p ) );for( DWORD i = 0; i < g_LightMesh.m_dwNumMaterials; ++i ){D3DXVECTOR4 vDif( g_LightMesh.m_pMaterials[i].Diffuse.r,g_LightMesh.m_pMaterials[i].Diffuse.g,g_LightMesh.m_pMaterials[i].Diffuse.b,g_LightMesh.m_pMaterials[i].Diffuse.a );V( g_pEffect->SetVector( "g_vMaterial", &vDif ) );V( g_pEffect->SetTexture( "g_txScene", g_LightMesh.m_pTextures[i] ) );V( g_pEffect->CommitChanges() );V( pMesh->DrawSubset( i ) );}V( g_pEffect->EndPass() );}V( g_pEffect->End() );
#endifV( pd3dDevice->EndScene() );}
}#endif
//--------------------------------------------------------------------------------------
// Render the scene using the D3D9 device
//--------------------------------------------------------------------------------------
void CALLBACK OnD3D9FrameRender( IDirect3DDevice9* pd3dDevice, double fTime, float fElapsedTime, void* pUserContext )
{HRESULT hr;#if phase2 & !phase4	// Clear the render target and the zbuffer V( pd3dDevice->Clear( 0, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, D3DCOLOR_ARGB( 0, 45, 50, 170 ), 1.0f, 0 ) );// Render the sceneif( SUCCEEDED( pd3dDevice->BeginScene() ) ){// Set world matrix  D3DXMATRIX M;D3DXMatrixIdentity( &M ); // M = identity matrixpd3dDevice->SetTransform(D3DTS_WORLD, &M) ;  // Set view matrix   D3DXMATRIX view  = *g_VCamera.GetViewMatrix() ;  pd3dDevice->SetTransform(D3DTS_VIEW, &view) ;  // Set projection matrix   D3DXMATRIX proj  = *g_VCamera.GetProjMatrix() ;  pd3dDevice->SetTransform(D3DTS_PROJECTION, &proj) ; // Render the objectsLPD3DXMESH pMeshObj;for(int obj = 0; obj < NUM_OBJ; ++obj){pMeshObj = g_Obj[obj].m_Mesh.GetMesh();for( DWORD m = 0; m < g_Obj[obj].m_Mesh.m_dwNumMaterials; ++m ){V( pd3dDevice->SetTexture(0,g_Obj[obj].m_Mesh.m_pTextures[m]));V( pMeshObj->DrawSubset( m ) );}}V( pd3dDevice->EndScene() );}
#endif
#if phase5D3DXMATRIXA16 mLightView;mLightView = *g_LCamera.GetViewMatrix();//// Render the shadow map//LPDIRECT3DSURFACE9 pOldRT = NULL;V( pd3dDevice->GetRenderTarget( 0, &pOldRT ) );LPDIRECT3DSURFACE9 pShadowSurf;if( SUCCEEDED( g_pShadowMap->GetSurfaceLevel( 0, &pShadowSurf ) ) ){pd3dDevice->SetRenderTarget( 0, pShadowSurf );SAFE_RELEASE( pShadowSurf );}LPDIRECT3DSURFACE9 pOldDS = NULL;if( SUCCEEDED( pd3dDevice->GetDepthStencilSurface( &pOldDS ) ) )pd3dDevice->SetDepthStencilSurface( g_pDSShadow );{CDXUTPerfEventGenerator g( DXUT_PERFEVENTCOLOR, L"Shadow Map" );RenderScene( pd3dDevice, true, fElapsedTime, &mLightView, &g_mShadowProj );}if( pOldDS ){pd3dDevice->SetDepthStencilSurface( pOldDS );pOldDS->Release();}pd3dDevice->SetRenderTarget( 0, pOldRT );SAFE_RELEASE( pOldRT );
#endif
#if phase6//// Now that we have the shadow map, render the scene.//const D3DXMATRIX* pmView =  g_VCamera.GetViewMatrix();// Initialize required parameterV( g_pEffect->SetTexture( "g_txShadow", g_pShadowMap ) );// Compute the matrix to transform from view space to// light projection space.  This consists of// the inverse of view matrix * view matrix of light * light projection matrixD3DXMATRIXA16 mViewToLightProj;mViewToLightProj = *pmView;D3DXMatrixInverse( &mViewToLightProj, NULL, &mViewToLightProj );D3DXMatrixMultiply( &mViewToLightProj, &mViewToLightProj, &mLightView );D3DXMatrixMultiply( &mViewToLightProj, &mViewToLightProj, &g_mShadowProj );V( g_pEffect->SetMatrix( "g_mViewToLightProj", &mViewToLightProj ) );{CDXUTPerfEventGenerator g( DXUT_PERFEVENTCOLOR, L"Scene" );RenderScene( pd3dDevice, false, fElapsedTime, pmView, g_VCamera.GetProjMatrix() );}g_pEffect->SetTexture( "g_txShadow", NULL );
#endif
}#if phase1
void CALLBACK MouseProc( bool bLeftButtonDown, bool bRightButtonDown, bool bMiddleButtonDown, bool bSideButton1Down,bool bSideButton2Down, int nMouseWheelDelta, int xPos, int yPos, void* pUserContext )
{g_bRightMouseDown = bRightButtonDown;
}
#endif
//--------------------------------------------------------------------------------------
// Handle messages to the application 
//--------------------------------------------------------------------------------------
LRESULT CALLBACK MsgProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam,bool* pbNoFurtherProcessing, void* pUserContext )
{
#if phase1// Pass all windows messages to camera and dialogs so they can respond to user inputif( WM_KEYDOWN != uMsg || g_bRightMouseDown )g_LCamera.HandleMessages( hWnd, uMsg, wParam, lParam );if( WM_KEYDOWN != uMsg || !g_bRightMouseDown ){g_VCamera.HandleMessages( hWnd, uMsg, wParam, lParam );}
#endifreturn 0;
}//--------------------------------------------------------------------------------------
// Release D3D9 resources created in the OnD3D9ResetDevice callback 
//--------------------------------------------------------------------------------------
void CALLBACK OnD3D9LostDevice( void* pUserContext )
{
#if phase2for( int i = 0; i < NUM_OBJ; ++i )g_Obj[i].m_Mesh.InvalidateDeviceObjects();
#endif
#if phase3g_LightMesh.InvalidateDeviceObjects();
#endif
#if phase4if( g_pEffect )g_pEffect->OnLostDevice();
#endif
#if phase5SAFE_RELEASE( g_pDSShadow );SAFE_RELEASE( g_pShadowMap );SAFE_RELEASE( g_pTexDef );
#endif
}//--------------------------------------------------------------------------------------
// Release D3D9 resources created in the OnD3D9CreateDevice callback 
//--------------------------------------------------------------------------------------
void CALLBACK OnD3D9DestroyDevice( void* pUserContext )
{
#if phase2for( int i = 0; i < NUM_OBJ; ++i )g_Obj[i].m_Mesh.Destroy();
#endif
#if phase3g_LightMesh.Destroy();
#endif
#if phase4SAFE_RELEASE(g_pEffect);
#endif}//--------------------------------------------------------------------------------------
// Initialize everything and go into a render loop
//--------------------------------------------------------------------------------------
INT WINAPI wWinMain( HINSTANCE, HINSTANCE, LPWSTR, int )
{// Enable run-time memory check for debug builds.
#if defined(DEBUG) | defined(_DEBUG)_CrtSetDbgFlag( _CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF );
#endif#if phase1// Initialize the camerag_VCamera.SetScalers( 0.01f, 15.0f );g_LCamera.SetScalers( 0.01f, 8.0f );g_VCamera.SetRotateButtons( true, false, false );g_LCamera.SetRotateButtons( false, false, true );// Set up the view parameters for the cameraD3DXVECTOR3 vFromPt = D3DXVECTOR3( 0.0f, 5.0f, -18.0f );D3DXVECTOR3 vLookatPt = D3DXVECTOR3( 0.0f, -1.0f, 0.0f );g_VCamera.SetViewParams( &vFromPt, &vLookatPt );vFromPt = D3DXVECTOR3( 0.0f, 0.0f, -12.0f );vLookatPt = D3DXVECTOR3( 0.0f, -2.0f, 1.0f );g_LCamera.SetViewParams( &vFromPt, &vLookatPt );
#endif#if phase3// Initialize the spot lightg_fLightFov = D3DX_PI / 2.0f;g_Light.Diffuse.r = 1.0f;g_Light.Diffuse.g = 1.0f;g_Light.Diffuse.b = 1.0f;g_Light.Diffuse.a = 1.0f;g_Light.Position = D3DXVECTOR3( -8.0f, -8.0f, 0.0f );g_Light.Direction = D3DXVECTOR3( 1.0f, -1.0f, 0.0f );D3DXVec3Normalize( ( D3DXVECTOR3* )&g_Light.Direction, ( D3DXVECTOR3* )&g_Light.Direction );g_Light.Range = 10.0f;g_Light.Theta = g_fLightFov / 2.0f;g_Light.Phi = g_fLightFov / 2.0f;
#endif// Set the callback functionsDXUTSetCallbackD3D9DeviceAcceptable( IsD3D9DeviceAcceptable );DXUTSetCallbackD3D9DeviceCreated( OnD3D9CreateDevice );DXUTSetCallbackD3D9DeviceReset( OnD3D9ResetDevice );DXUTSetCallbackD3D9FrameRender( OnD3D9FrameRender );DXUTSetCallbackD3D9DeviceLost( OnD3D9LostDevice );DXUTSetCallbackD3D9DeviceDestroyed( OnD3D9DestroyDevice );DXUTSetCallbackDeviceChanging( ModifyDeviceSettings );DXUTSetCallbackMsgProc( MsgProc );DXUTSetCallbackFrameMove( OnFrameMove );
#if phase1DXUTSetCallbackMouse( MouseProc );
#endif// TODO: Perform any application-level initialization here// Initialize DXUT and create the desired Win32 window and Direct3D device for the applicationDXUTInit( true, true ); // Parse the command line and show msgboxesDXUTSetHotkeyHandling( true, true, true );  // handle the default hotkeysDXUTSetCursorSettings( true, true ); // Show the cursor and clip it when in full screenDXUTCreateWindow( L"3D_Shader_ShadowMap" );DXUTCreateDevice( true, 640, 480 );// Start the render loopDXUTMainLoop();// TODO: Perform any application-level cleanup herereturn DXUTGetExitCode();
}


3d渲染沒有陰影怎么辦?

/*------------------------------------------------------------
ShadowMap.fx -- achieve shadow map
(c) Seamanj.2014/4/28
------------------------------------------------------------*/#define SMAP_SIZE 512#define SHADOW_EPSILON 0.00005ffloat4x4 g_mWorldView;
float4x4 g_mProj;
float4x4 g_mViewToLightProj;  // Transform from view space to light projection space
float4   g_vMaterial;
texture  g_txScene;
texture  g_txShadow;
float3   g_vLightPos;  // Light position in view space
float3   g_vLightDir;  // Light direction in view space
float4   g_vLightDiffuse = float4( 1.0f, 1.0f, 1.0f, 1.0f );  // Light diffuse color
float4   g_vLightAmbient = float4( 0.3f, 0.3f, 0.3f, 1.0f );  // Use an ambient light of 0.3
float    g_fCosTheta;  // Cosine of theta of the spot lightsampler2D g_samScene =
sampler_state
{Texture = <g_txScene>;MinFilter = Point;MagFilter = Linear;MipFilter = Linear;
};sampler2D g_samShadow =
sampler_state
{Texture = <g_txShadow>;MinFilter = Point;MagFilter = Point;MipFilter = Point;AddressU = Clamp;AddressV = Clamp;
};//-----------------------------------------------------------------------------
// Vertex Shader: VertScene
// Desc: Process vertex for scene
//-----------------------------------------------------------------------------
void VertScene( float4 iPos : POSITION,float3 iNormal : NORMAL,float2 iTex : TEXCOORD0,out float4 oPos : POSITION,out float2 Tex : TEXCOORD0,out float4 vPos : TEXCOORD1,out float3 vNormal : TEXCOORD2,out float4 vPosLight : TEXCOORD3 )
{//// Transform position to view space//vPos = mul( iPos, g_mWorldView );//// Transform to screen coord//oPos = mul( vPos, g_mProj );//// Compute view space normal//vNormal = mul( iNormal, (float3x3)g_mWorldView );//// Propagate texture coord//Tex = iTex;//// Transform the position to light projection space, or the// projection space as if the camera is looking out from// the spotlight.//vPosLight = mul( vPos, g_mViewToLightProj );
}//-----------------------------------------------------------------------------
// Pixel Shader: PixScene
// Desc: Process pixel (do per-pixel lighting) for enabled scene
//-----------------------------------------------------------------------------
float4 PixScene( float2 Tex : TEXCOORD0,float4 vPos : TEXCOORD1,float3 vNormal : TEXCOORD2,float4 vPosLight : TEXCOORD3 ) : COLOR
{float4 Diffuse;// vLight is the unit vector from the light to this pixelfloat3 vLight = normalize( float3( vPos - g_vLightPos ) );// Compute diffuse from the lightif( dot( vLight, g_vLightDir ) > g_fCosTheta ) // Light must face the pixel (within Theta){// Pixel is in lit area. Find out if it's// in shadow using 2x2 percentage closest filtering//transform from RT space to texture space.float2 ShadowTexC = 0.5 * vPosLight.xy / vPosLight.w + float2( 0.5, 0.5 );ShadowTexC.y = 1.0f - ShadowTexC.y;// transform to texel spacefloat2 texelpos = SMAP_SIZE * ShadowTexC;// Determine the lerp amounts           float2 lerps = frac( texelpos );//read in bilerp stamp, doing the shadow checksfloat sourcevals[4];sourcevals[0] = (tex2D( g_samShadow, ShadowTexC ) + SHADOW_EPSILON < vPosLight.z / vPosLight.w)? 0.0f: 1.0f;  sourcevals[1] = (tex2D( g_samShadow, ShadowTexC + float2(1.0/SMAP_SIZE, 0) ) + SHADOW_EPSILON < vPosLight.z / vPosLight.w)? 0.0f: 1.0f;  sourcevals[2] = (tex2D( g_samShadow, ShadowTexC + float2(0, 1.0/SMAP_SIZE) ) + SHADOW_EPSILON < vPosLight.z / vPosLight.w)? 0.0f: 1.0f;  sourcevals[3] = (tex2D( g_samShadow, ShadowTexC + float2(1.0/SMAP_SIZE, 1.0/SMAP_SIZE) ) + SHADOW_EPSILON < vPosLight.z / vPosLight.w)? 0.0f: 1.0f;  // lerp between the shadow values to calculate our light amountfloat LightAmount = lerp( lerp( sourcevals[0], sourcevals[1], lerps.x ),lerp( sourcevals[2], sourcevals[3], lerps.x ),lerps.y );// Light itDiffuse = ( saturate( dot( -vLight, normalize( vNormal ) ) ) * LightAmount * ( 1 - g_vLightAmbient ) + g_vLightAmbient )* g_vMaterial;} else{Diffuse = g_vLightAmbient * g_vMaterial;}return tex2D( g_samScene, Tex ) * Diffuse;
}//-----------------------------------------------------------------------------
// Vertex Shader: VertLight
// Desc: Process vertex for the light object
//-----------------------------------------------------------------------------
void VertLight( float4 iPos : POSITION,float3 iNormal : NORMAL,float2 iTex : TEXCOORD0,out float4 oPos : POSITION,out float2 Tex : TEXCOORD0 )
{//// Transform position to view space//oPos = mul( iPos, g_mWorldView );//// Transform to screen coord//oPos = mul( oPos, g_mProj );//// Propagate texture coord//Tex = iTex;
}//-----------------------------------------------------------------------------
// Pixel Shader: PixLight
// Desc: Process pixel for the light object
//-----------------------------------------------------------------------------
float4 PixLight( float2 Tex : TEXCOORD0,float4 vPos : TEXCOORD1 ) : COLOR
{return tex2D( g_samScene, Tex );
}//-----------------------------------------------------------------------------
// Vertex Shader: VertShadow
// Desc: Process vertex for the shadow map
//-----------------------------------------------------------------------------
void VertShadow( float4 Pos : POSITION,float3 Normal : NORMAL,out float4 oPos : POSITION,out float2 Depth : TEXCOORD0 )
{//// Compute the projected coordinates//oPos = mul( Pos, g_mWorldView );oPos = mul( oPos, g_mProj );//// Store z and w in our spare texcoord//Depth.xy = oPos.zw;
}//-----------------------------------------------------------------------------
// Pixel Shader: PixShadow
// Desc: Process pixel for the shadow map
//-----------------------------------------------------------------------------
void PixShadow( float2 Depth : TEXCOORD0,out float4 Color : COLOR )
{//// Depth is z / w//Color = Depth.x / Depth.y;//不要看輸出是白色,結果是有效的//float a = Depth.x / Depth.y;//Color = a * 100 - 99;//Color = (1, 1, 1, a * 100 - 9);//這種賦值方法相當于將最后一個值賦給Color的所有分量//Color = float4(a * 100 - 99,a * 100 - 99,a * 100 - 99,a * 100 - 99);}//-----------------------------------------------------------------------------
// Technique: RenderScene
// Desc: Renders scene objects
//-----------------------------------------------------------------------------
technique RenderScene
{pass p0{VertexShader = compile vs_2_0 VertScene();PixelShader = compile ps_2_0 PixScene();}
}//-----------------------------------------------------------------------------
// Technique: RenderLight
// Desc: Renders the light object
//-----------------------------------------------------------------------------
technique RenderLight
{pass p0{VertexShader = compile vs_2_0 VertLight();PixelShader = compile ps_2_0 PixLight();}
}//-----------------------------------------------------------------------------
// Technique: RenderShadow
// Desc: Renders the shadow map
//-----------------------------------------------------------------------------
technique RenderShadow
{pass p0{VertexShader = compile vs_2_0 VertShadow();PixelShader = compile ps_2_0 PixShadow();}
}


注意:這里我們第一個問題和第三個問題都解決了,我們著重看下第二個問題,將SHADOW_EPSILON改為0.00000f,整個效果如下:

3d怎么不顯示陰影,

這是由于Shadow Map精度造成的自投影。解決方案:如前面仁兄說的那樣,可以把SHADOW_EPSILON改成0.00005f,但是這樣又會出現一個問題

當燈光距離物理較遠時,陰影容易與物體分離。


3ds怎么把圖片貼進去?由于DX API中的偏移只改變了物體在標準設備坐標的Z值,并未改變shader里面的shadow map記錄的值,所以具體的解決方法有待進一步研究。以后有進展了我再補充吧。


可執行程序以及相關源代碼請點擊這里下載



版权声明:本站所有资料均为网友推荐收集整理而来,仅供学习和研究交流使用。

原文链接:https://hbdhgg.com/2/171653.html

发表评论:

本站为非赢利网站,部分文章来源或改编自互联网及其他公众平台,主要目的在于分享信息,版权归原作者所有,内容仅供读者参考,如有侵权请联系我们删除!

Copyright © 2022 匯編語言學習筆記 Inc. 保留所有权利。

底部版权信息