相信大家都应该玩过CS或者CF吧,游戏里面有个喷图功能,就是按一个T键就能在墙上或者地板上喷出自己预先设定的图案.

而刚好这就是我们这个Shader所需实现的内容.由于没有潜伏者的贴图,我只有从这个图里用PS扣一个Alpha通道出来,我后面会讲具体操作

下面就起跟我一起进入亮瞎氪金狗眼的3D世界吧

国际惯例上图先:

怎么样?过瘾吧,这样的话,到处乱喷,估计保卫者都快疯掉了,呵呵!!!!!!!!!

好了,进入正题,讲下原理:

投影贴图是从灯光处看到世界坐标系的原点从而建立VIEW矩阵,物体在灯光中视椎体的位置仍然由物体的MODEL矩阵来控制,然后通过PROJECTION矩阵转成标准设备坐标,由于标准设备坐标的范围为(-1,1),但是纹理坐标的范围为(0,1),所以我们需要将其移动到(0,1)

投影贴图的矩阵变换

In the rendering pipeline, geometry outside the frustum is clipped. However, when we generate projective texture coordinates by projecting the geometry from the
point of view of the light projector, no clipping is done — we simply project vertices. Consequently, geometry outside the projector's frustum receives projective texture coordinates outside the [0, 1] range.

这里有两种方法来处理位于视椎体外面的点,一种方法:就是为灯光设置一个锥形照射范围,这样超过这个范围的点将不会映射,第二种方法,我们检测纹理坐标,如何超出了(0,1)的范围,我们就不要映射了.

这里我们采用了第二种方法:

float2 uv = texCoordProj.xy / texCoordProj.w;
if( uv.x < 0.0f || uv.x > 1.0f || uv.y < 0.0f || uv.y > 1.0f  )
{
return diffuseLighting;
}

另外,我们会发现,视椎体的前后都会投影,

The second issue is that back-projection artifacts can appear when the q coordinate is negative.
Back-projection refers to the texture being projected on surfaces that are behind the light source (or
projector).

There are several ways to avoid artifacts when q is negative:
1.Use culling to draw only geometry that is in front of the light source.
2.Use clip planes to remove geometry that is behind the light source.
3.Fold the back-projection factor into a 3D attenuation texture.
4.Use a fragment program to check when q is negative.
The first two solutions are tedious to implement; the fragment program solution is simple and efficient but
requires an advanced fragment profile. Just check the value of the q coordinate. If q is negative, you can
ignore the projective texture computation and output black.

这里我们采用第4种方法

if( texCoordProj.w < 0 )
{
return diffuseLighting;
}

好了,这里讲下PS相关的内容,为了将潜伏者从原图中扣出来,去掉背景的影响,我们需要新建一个Alpha通道,然后在Alpha通道里用多边形套索工具,自己慢慢把它扣出来,最后保存为32位的tga格式,将alpha通道保存进去

alpha通道

然后在片断着色器中,我们采用混合的方式,将其显示出来

return textureColor * textureColor.w + (1.0 - textureColor.w) * diffuseLighting;

最后再来一个暴雪的LOGO吧

是不是有点像放电影的赶脚,呵呵.

好了,贴下源代码

/*------------------------------------------------------------
3D_Shader_ProjectivetTexturing.cpp -- achieve projective texturing
(c) Seamanj.2013/8/30
------------------------------------------------------------*/
#include "DXUT.h"
#include "resource.h" // phase1 : add camera
// phase2 : add wall
// phase3 : add light and shader
// phase4 : add animation
// phase5 : add objects in space
// phase6 : add projective texture
#define phase1 1
#define phase2 1
#define phase3 1
#define phase4 1
#define phase5 1
#define phase6 1
#if phase1
#include "DXUTcamera.h"
CModelViewerCamera g_Camera;
#endif #if phase2
// Vertex Buffer
LPDIRECT3DVERTEXBUFFER9 g_pVB = NULL;
// Index Buffer
LPDIRECT3DINDEXBUFFER9 g_pIB = NULL;
#endif #if phase3
#include "SDKmisc.h"//加载文件时会用到
ID3DXEffect* g_pEffect = NULL; // D3DX effect interface
D3DXHANDLE g_hTech = 0;
D3DXHANDLE g_hWorldViewProj = NULL;
D3DXHANDLE g_hWorld = NULL;
D3DXHANDLE g_hWorldInv = NULL;
D3DXHANDLE g_hLightPosition = NULL; ID3DXMesh* g_pLightSphereMesh = 0;
static float g_fLightAngle = -0.4; /* Angle light rotates around scene. */
static float g_fLightHeight = 2.0f; /* Vertical height of light. */ #endif #if phase4
static bool g_bAnimation = false;
short g_sDirection = 1;
#endif #if phase5
ID3DXMesh* g_pSphereMesh = 0;
ID3DXMesh* g_pTeapotMesh = 0;
#endif #if phase6
IDirect3DTexture9* g_pTex = NULL;
D3DXHANDLE g_hTex = NULL;
D3DXHANDLE g_hTextureMatrix = NULL;
#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 blending
IDirect3D9* pD3D = DXUTGetD3D9Object();
if( FAILED( pD3D->CheckDeviceFormat( pCaps->AdapterOrdinal, pCaps->DeviceType,
AdapterFormat, D3DUSAGE_QUERY_POSTPIXELSHADER_BLENDING,
D3DRTYPE_TEXTURE, BackBufferFormat ) ) )
return false; return true;
} //--------------------------------------------------------------------------------------
// Before a device is created, modify the device settings as needed
//--------------------------------------------------------------------------------------
bool CALLBACK ModifyDeviceSettings( DXUTDeviceSettings* pDeviceSettings, void* pUserContext )
{
#if phase1
pDeviceSettings->d3d9.pp.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE;
#endif 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 )
{
#if phase1
// Setup the camera's view parameters
D3DXVECTOR3 vecEye( 0.0f, 0.0f, -5.0f );
D3DXVECTOR3 vecAt ( 0.0f, 0.0f, -0.0f );
g_Camera.SetViewParams( &vecEye, &vecAt );
FLOAT fObjectRadius=1;
//摄像机缩放的3个参数
g_Camera.SetRadius( fObjectRadius * 3.0f, fObjectRadius * 0.5f, fObjectRadius * 20.0f );
g_Camera.SetEnablePositionMovement( true ); #endif
#if phase3
HRESULT hr;
// Create vertex shader
WCHAR str[MAX_PATH];
// Read the D3DX effect file
V_RETURN( DXUTFindDXSDKMediaFileCch( str, MAX_PATH, L"ProjectiveTexturing.fx" ) );
// Create the effect
LPD3DXBUFFER pErrorBuff;
V_RETURN( D3DXCreateEffectFromFile(
pd3dDevice, // associated device
str, // effect filename
NULL, // no preprocessor definitions
NULL, // no ID3DXInclude interface
D3DXSHADER_DEBUG, // compile flags
NULL, // don't share parameters
&g_pEffect, // return effect
&pErrorBuff // return error messages
) );
//pErrorBuff
// Get handle
g_hTech = g_pEffect->GetTechniqueByName("MyTechnique"); g_hWorldViewProj = g_pEffect->GetParameterByName(0, "g_mWorldViewProj");
g_hLightPosition = g_pEffect->GetParameterByName(0, "g_lightPosition");
g_hWorld = g_pEffect->GetParameterByName(0, "g_mWorld");
g_hWorldInv = g_pEffect->GetParameterByName(0, "g_mWorldInv"); D3DXCreateSphere(pd3dDevice, 0.15, 30, 30, &g_pLightSphereMesh, 0); #endif
#if phase5
D3DXCreateSphere(pd3dDevice, 2.0f, 40, 40, &g_pSphereMesh, 0);
D3DXCreateTeapot(pd3dDevice, &g_pTeapotMesh, 0);
#endif
#if phase6 g_hTextureMatrix = g_pEffect->GetParameterByName(0, "g_mTextureMatrix");
g_hTex = g_pEffect->GetParameterByName(0, "g_tex");
D3DXCreateTextureFromFile(pd3dDevice, L"cf.tga", &g_pTex);
#endif
return S_OK;
} #if phase2
struct MyVertexFormat
{
FLOAT x, y, z;
FLOAT nx, ny, nz;
};
#define FVF_VERTEX (D3DFVF_XYZ | D3DFVF_NORMAL )
static HRESULT initVertexIndexBuffer(IDirect3DDevice9* pd3dDevice)
{
static const MyVertexFormat Vertices[] =
{
//floor
{ 12, -2, -12, 0, 1, 0 },
{ -12, -2, -12, 0, 1, 0 },
{ -12, -2, 12 , 0, 1, 0 },
{ 12, -2, 12, 0, 1, 0 },
//front
{ -12, -2, -12,0, 0, 1 },
{ 12, -2, -12,0, 0, 1 },
{ 12, 10, -12,0, 0, 1 },
{ -12, 10, -12, 0, 0, 1},
//back
{ 12, -2, 12 ,0, 0, -1 },
{ -12, -2, 12 ,0, 0, -1 },
{ -12, 10, 12 ,0, 0, -1},
{ 12, 10, 12,0, 0, -1 },
//ceiling { -12, 10, -12,0, -1, 0 },
{ 12, 10, -12,0, -1, 0 },
{ 12, 10, 12,0, -1, 0 },
{ -12, 10, 12,0, -1, 0},
//left
{ -12, -2, 12,1, 0, 0 },
{ -12, -2, -12,1, 0, 0 },
{ -12, 10, -12,1, 0, 0 },
{-12, 10, 12,1, 0, 0 },
//-right
{ 12, -2, -12,-1, 0, 0 },
{ 12, -2, 12,-1, 0, 0 },
{12, 10, 12,-1, 0, 0},
{12, 10, -12,-1, 0, 0 }
};
if (FAILED(pd3dDevice->CreateVertexBuffer(sizeof(Vertices),
0, FVF_VERTEX,
D3DPOOL_DEFAULT,
&g_pVB, NULL))) {
return E_FAIL;
}
void* pVertices;
if (FAILED(g_pVB->Lock(0, 0, /* map entire buffer */
&pVertices, 0))) {
return E_FAIL;
}
memcpy(pVertices, Vertices, sizeof(Vertices));
g_pVB->Unlock(); // Create and initialize index buffer
static const WORD Indices[] =
{
0, 1, 2,
0, 2, 3, 4, 5, 6,
4, 6, 7, 8, 9, 10,
8,10, 11, 12,13,14,
12,14,15, 16,17,18,
16,18,19, 20,21,22,
20,22,23
};
if (FAILED(pd3dDevice->CreateIndexBuffer(sizeof(Indices),
D3DUSAGE_WRITEONLY,
D3DFMT_INDEX16,
D3DPOOL_DEFAULT,
&g_pIB, NULL))) {
return E_FAIL;
}
void* pIndices;
if (FAILED(g_pIB->Lock(0, 0, /* map entire buffer */
&pIndices, 0))) {
return E_FAIL;
}
memcpy(pIndices, Indices, sizeof(Indices));
g_pIB->Unlock();
return S_OK;
} #endif
//--------------------------------------------------------------------------------------
// 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 )
{
#if phase3
HRESULT hr;
if( g_pEffect )
V_RETURN( g_pEffect->OnResetDevice() );
#endif
#if phase2
pd3dDevice->SetRenderState( D3DRS_CULLMODE, D3DCULL_NONE );
//Setup the camera's projection parameters
float fAspectRatio = pBackBufferSurfaceDesc->Width / ( FLOAT )pBackBufferSurfaceDesc->Height; g_Camera.SetProjParams( D3DX_PI / 2, fAspectRatio, 0.1f, 5000.0f );
g_Camera.SetWindow( pBackBufferSurfaceDesc->Width, pBackBufferSurfaceDesc->Height );
g_Camera.SetButtonMasks( MOUSE_LEFT_BUTTON, MOUSE_WHEEL, MOUSE_RIGHT_BUTTON );
#endif
#if !phase1
return S_OK;
#else
return initVertexIndexBuffer(pd3dDevice);
#endif } #if phase4
static const double my2Pi = 2.0 * 3.14159265358979323846;
#endif
//--------------------------------------------------------------------------------------
// 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
g_Camera.FrameMove( fElapsedTime );
#endif
#if phase4
if( g_bAnimation )
{
if( g_fLightHeight > 9.0f)
g_sDirection = -1;
else if( g_fLightHeight < -1.5f )
g_sDirection = 1;
g_fLightHeight += 0.0002 * g_sDirection;
g_fLightAngle += 0.0002;
if( g_fLightAngle > my2Pi)
{
g_fLightAngle -= my2Pi;
} }
#endif
} #if phase6
static void buildTextureMatrix(D3DXMATRIXA16& textureMatrix,
const D3DXMATRIXA16& modelMatrix,
const D3DXMATRIXA16& viewMatrix
)//需要modelMatrix是因为需要了解物体在灯光的视椎体里面的位置
{
D3DXMATRIXA16 projMatrix;
D3DXMATRIXA16 RangeMappingMatrix(
0.5, 0, 0, 0,
0, 0.5, 0, 0,
0, 0,0.5, 0,
0.5, 0.5,0.5, 1);
D3DXMatrixPerspectiveFovLH(&projMatrix, 50.0f * 3.14f / 180.0f , 1.72f, 0.25, 20.0);
textureMatrix = modelMatrix * viewMatrix * projMatrix * RangeMappingMatrix;
}
static void buildLightViewMatrix(D3DXMATRIXA16& lightViewMatrix,const D3DXVECTOR3 *pLightPosition )
{
D3DXMatrixLookAtLH(&lightViewMatrix, pLightPosition,
&D3DXVECTOR3(0, 0, 0), &D3DXVECTOR3(0, -1, 0));//看世界坐标系中的原点
}
#endif
//--------------------------------------------------------------------------------------
// Render the scene using the D3D9 device
//--------------------------------------------------------------------------------------
void CALLBACK OnD3D9FrameRender( IDirect3DDevice9* pd3dDevice, double fTime, float fElapsedTime, void* pUserContext )
{
HRESULT hr;
#if phase3
const float lightPosition[4] = { 6*sin(g_fLightAngle),
g_fLightHeight,
6*cos(g_fLightAngle), 1 };
#endif
// 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 scene
if( SUCCEEDED( pd3dDevice->BeginScene() ) )
{
#if phase3
UINT iPass, cPasses;
D3DXMATRIXA16 mWorldViewProjection,mWorld,mWorldInv;
#if phase6
D3DXMATRIXA16 mLightViewMatrix, mTextureMatrix;
#endif
V(g_pEffect->SetTechnique(g_hTech));
V( g_pEffect->Begin( &cPasses, 0 ) );
for( iPass = 0; iPass < cPasses; iPass++ )
{
V( g_pEffect->BeginPass( iPass ) ); //set light position
V( g_pEffect->SetFloatArray( g_hLightPosition, lightPosition, 4) );
#if phase6
//set texture
V( g_pEffect->SetTexture( g_hTex, g_pTex) );
#endif
#if phase2//build wall
#if phase5
// Set world matrix
D3DXMatrixIdentity(&mWorld);
V( g_pEffect->SetMatrix( g_hWorld, &mWorld) );
// Set world inverse matrix
D3DXMatrixInverse(&mWorldInv, NULL, &mWorld);
V( g_pEffect->SetMatrix( g_hWorldInv, &mWorldInv) );
// set worldviewproj matrix
mWorldViewProjection = mWorld * *g_Camera.GetViewMatrix() * *g_Camera.GetProjMatrix();
V( g_pEffect->SetMatrix( g_hWorldViewProj, &mWorldViewProjection) );
#endif
#if phase6
// set light view matrix
buildLightViewMatrix(mLightViewMatrix, &D3DXVECTOR3(lightPosition[0], lightPosition[1], lightPosition[2]) );
// set texture matrix
buildTextureMatrix(mTextureMatrix, mWorld, mLightViewMatrix);
V( g_pEffect->SetMatrix( g_hTextureMatrix, &mTextureMatrix) );
#endif pd3dDevice->SetRenderState(D3DRS_CULLMODE, D3DCULL_CCW);
V( g_pEffect->CommitChanges() );
pd3dDevice->SetStreamSource(0, g_pVB, 0, sizeof(MyVertexFormat));
pd3dDevice->SetIndices(g_pIB);//sets the current index buffer.
pd3dDevice->SetFVF(FVF_VERTEX);//Sets the current vertex stream declaration.
pd3dDevice->DrawIndexedPrimitive(D3DPT_TRIANGLELIST, 0, 0, 24, 0, 12);
#endif
#if phase5
// Set world matrix
D3DXMatrixTranslation(&mWorld, 2, 0, 0);
V( g_pEffect->SetMatrix( g_hWorld, &mWorld) ); // Set world inverse matrix
D3DXMatrixInverse(&mWorldInv, NULL, &mWorld);
V( g_pEffect->SetMatrix( g_hWorldInv, &mWorldInv) ); // set worldviewproj matrix
mWorldViewProjection = mWorld * *g_Camera.GetViewMatrix() * *g_Camera.GetProjMatrix();
V( g_pEffect->SetMatrix( g_hWorldViewProj, &mWorldViewProjection) );
#if phase6
// set light view matrix
buildLightViewMatrix(mLightViewMatrix, &D3DXVECTOR3(lightPosition[0], lightPosition[1], lightPosition[2]) );
// set texture matrix
buildTextureMatrix(mTextureMatrix, mWorld, mLightViewMatrix);
V( g_pEffect->SetMatrix( g_hTextureMatrix, &mTextureMatrix) );
#endif V( g_pEffect->CommitChanges() );
g_pSphereMesh->DrawSubset(0);
// set teapot world matrix
// Set world matrix
D3DXMatrixTranslation(&mWorld, -2, 1, 0);
V( g_pEffect->SetMatrix( g_hWorld, &mWorld) ); // Set world inverse matrix
D3DXMatrixInverse(&mWorldInv, NULL, &mWorld);
V( g_pEffect->SetMatrix( g_hWorldInv, &mWorldInv) ); // set worldviewproj matrix
mWorldViewProjection = mWorld * *g_Camera.GetViewMatrix() * *g_Camera.GetProjMatrix();
V( g_pEffect->SetMatrix( g_hWorldViewProj, &mWorldViewProjection) ); #if phase6
// set light view matrix
buildLightViewMatrix(mLightViewMatrix, &D3DXVECTOR3(lightPosition[0], lightPosition[1], lightPosition[2]) );
// set texture matrix
buildTextureMatrix(mTextureMatrix, mWorld, mLightViewMatrix);
V( g_pEffect->SetMatrix( g_hTextureMatrix, &mTextureMatrix) );
#endif
V( g_pEffect->CommitChanges() );
g_pTeapotMesh->DrawSubset(0); #endif
V( g_pEffect->EndPass() );
}
V( g_pEffect->End() );
#endif #if phase3
pd3dDevice->SetRenderState(D3DRS_LIGHTING, false);
// Set world matrix
D3DXMATRIX M;
D3DXMatrixIdentity( &M ); // M = identity matrix
D3DXMatrixTranslation(&M, lightPosition[0], lightPosition[1], lightPosition[2]);
pd3dDevice->SetTransform(D3DTS_WORLD, &M) ;
//这里三角形更像是世界坐标中静止的物体(比如墙)因为按W它会相对与摄像机会动,不像茶壶总在摄像机前面,相对于摄像机静止
// Set view matrix
D3DXMATRIX view = *g_Camera.GetViewMatrix() ;
pd3dDevice->SetTransform(D3DTS_VIEW, &view) ;
// Set projection matrix
D3DXMATRIX proj = *g_Camera.GetProjMatrix() ;
pd3dDevice->SetTransform(D3DTS_PROJECTION, &proj) ;
g_pLightSphereMesh->DrawSubset(0);
#endif
V( pd3dDevice->EndScene() );
}
} //--------------------------------------------------------------------------------------
// Handle messages to the application
//--------------------------------------------------------------------------------------
LRESULT CALLBACK MsgProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam,
bool* pbNoFurtherProcessing, void* pUserContext )
{
#if phase1
g_Camera.HandleMessages( hWnd, uMsg, wParam, lParam );
#endif
return 0;
} //--------------------------------------------------------------------------------------
// Release D3D9 resources created in the OnD3D9ResetDevice callback
//--------------------------------------------------------------------------------------
void CALLBACK OnD3D9LostDevice( void* pUserContext )
{
#if phase1
SAFE_RELEASE(g_pVB);
SAFE_RELEASE(g_pIB);
#endif
#if phase3
if( g_pEffect )
g_pEffect->OnLostDevice();
#endif
} //--------------------------------------------------------------------------------------
// Release D3D9 resources created in the OnD3D9CreateDevice callback
//--------------------------------------------------------------------------------------
void CALLBACK OnD3D9DestroyDevice( void* pUserContext )
{
#if phase3 SAFE_RELEASE(g_pEffect);
SAFE_RELEASE(g_pLightSphereMesh); #endif
#if phase5
SAFE_RELEASE(g_pSphereMesh);
SAFE_RELEASE(g_pTeapotMesh);
#endif
#if phase6
SAFE_RELEASE(g_pTex);
#endif
}
#if phase4
void CALLBACK OnKeyboardProc(UINT character, bool is_key_down, bool is_alt_down, void* user_context)
{
if(is_key_down)
{
switch(character)
{
case VK_SPACE:
g_bAnimation = !g_bAnimation;
break;
}
}
}
#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 // Set the callback functions
DXUTSetCallbackD3D9DeviceAcceptable( IsD3D9DeviceAcceptable );
DXUTSetCallbackD3D9DeviceCreated( OnD3D9CreateDevice );
DXUTSetCallbackD3D9DeviceReset( OnD3D9ResetDevice );
DXUTSetCallbackD3D9FrameRender( OnD3D9FrameRender );
DXUTSetCallbackD3D9DeviceLost( OnD3D9LostDevice );
DXUTSetCallbackD3D9DeviceDestroyed( OnD3D9DestroyDevice );
DXUTSetCallbackDeviceChanging( ModifyDeviceSettings );
DXUTSetCallbackMsgProc( MsgProc );
DXUTSetCallbackFrameMove( OnFrameMove );
#if phase4
DXUTSetCallbackKeyboard( OnKeyboardProc );
#endif
// TODO: Perform any application-level initialization here // Initialize DXUT and create the desired Win32 window and Direct3D device for the application
DXUTInit( true, true ); // Parse the command line and show msgboxes
DXUTSetHotkeyHandling( true, true, true ); // handle the default hotkeys
DXUTSetCursorSettings( true, true ); // Show the cursor and clip it when in full screen
DXUTCreateWindow( L"3D_Shader_ProjectivetTexturing" );
DXUTCreateDevice( true, 640, 480 ); // Start the render loop
DXUTMainLoop(); // TODO: Perform any application-level cleanup here return DXUTGetExitCode();
}
/*--------------------------------------------------------------------------
ProjectiveTexturing.fx -- Projective texturing shader
(c) Seamanj.2013/8/30
--------------------------------------------------------------------------*/ //--------------------------------------------------------------------------------------
// Global variables
//--------------------------------------------------------------------------------------
float4x4 g_mWorldViewProj;
float4x4 g_mWorld;
float4x4 g_mWorldInv;
float4x4 g_mTextureMatrix;
float3 g_lightPosition; texture g_tex;
//-----------------------------------------------------------------------------
// Sampler
//----------------------------------------------------------------------------- sampler2D g_sam =
sampler_state
{
Texture = <g_tex>;
MinFilter = Linear;
MagFilter = Linear;
MipFilter = Linear;
AddressU = Border;
AddressV = Border;
};
//--------------------------------------------------------------------------------------
// Vertex shader output structure
//--------------------------------------------------------------------------------------
struct VS_Output {
float4 position : POSITION;
float4 diffuseLighting : COLOR;
float4 texCoordProj : TEXCOORD0;
}; //--------------------------------------------------------------------------------------
// Vertex shader
//--------------------------------------------------------------------------------------
VS_Output MyVertexEntry(float4 position : POSITION,float3 normal : NORMAL)
{
VS_Output OUT; OUT.position = mul ( position, g_mWorldViewProj); OUT.texCoordProj = mul(position, g_mTextureMatrix); // Compute diffuse lighting
normal = mul(normal, transpose((float3x3)g_mWorldInv));
float3 N = normalize(normal);
position = mul( position, g_mWorld );//在世界坐标系中计算光照
float3 L = normalize(g_lightPosition - position.xyz);
OUT.diffuseLighting = float4(1,1,1,1) * max(dot(N, L), 0); return OUT;
} //--------------------------------------------------------------------------------------
// Pixel shader
//--------------------------------------------------------------------------------------
float4 MyPixelEntry(float4 diffuseLighting : COLOR, float4 texCoordProj : TEXCOORD0) : COLOR
{
float2 uv = texCoordProj.xy / texCoordProj.w;
//如果纹理坐标超出了(0,1)范围以及投影椎体的后面都不要映射
if( uv.x < 0.0f || uv.x > 1.0f || uv.y < 0.0f || uv.y > 1.0f || texCoordProj.w < 0 )
{
return diffuseLighting;
}
uv.x = 1 - uv.x;//由于建立灯光的view矩阵时采用的是左手坐标系,所以转成纹理坐标需要左右相反
float4 textureColor = tex2D(g_sam, uv); return textureColor * textureColor.w + (1.0 - textureColor.w) * diffuseLighting;
} //--------------------------------------------------------------------------------------
// Renders scene to render target
//--------------------------------------------------------------------------------------
technique MyTechnique
{
pass P0
{
VertexShader = compile vs_2_0 MyVertexEntry();
PixelShader = compile ps_2_0 MyPixelEntry();
}
}

可执行程序以及相关源代码请点击这里下载

3DShader之投影贴图(Projective Texturing)的更多相关文章

  1. 投影纹理映射(Projective Texture Mapping)

    摘抄“GPU Programming And Cg Language Primer 1rd Edition” 中文名“GPU编程与CG语言之阳春白雪下里巴人”  投影纹理映射( Projective ...

  2. OpenGL 4.0 GLSL 实现 投影纹理映射(Projective Texture Mapping) (转)

    http://blog.csdn.net/zhuyingqingfen/article/details/19331721   分类: GLSL  投影纹理映射 (projective texture ...

  3. 投影纹理映射(Projective Texture Mapping) 【转】

    摘抄“GPU Programming And Cg Language Primer 1rd Edition” 中文名“GPU编程与CG语言之阳春白雪下里巴人”  投影纹理映射( Projective ...

  4. 3DShader之移位贴图(Displacement Mapping)

    我们知道法线贴图是只是改了物体的法线属性,用来计算光照,但是并没有改变物体本身的网格.但是移位贴图就不一样了,它会移动物体的顶点.我用移位贴图做了个海洋,好了,上了图再讲: 注意看海的边缘的顶点,已经 ...

  5. 3DShader之法线贴图(normal mapping)

    凹凸贴图(bump mapping)实现的技术有几种,normal mapping属于其中的一种,这里实现在物体的坐标系空间中实现的,国际惯例,上图先: 好了讲下原理 可以根据高度图生成法线量图,生成 ...

  6. 根据花瓶的侧面投影图,用Matlab绘制花瓶的三维立体图

    现有一花瓶侧面投影如图 问题: 1)    做出该花瓶三维立体图: 2)    计算其表面积:  计算其体积. 第一次参加数学建模,从来没有接触过Matlab语言,一上来就碰到这种数字图像处理的问题就 ...

  7. uv纹理坐标设定与贴图规则

    1.什么是UV?   对于三维模型,有两个最重要的坐标系统,一是顶点的位置(X,Y,Z)坐标,另一个就是UV坐标.什么是UV?简单的说,就是贴图影射到模型表面的依据. 完整的说,其实应该是UVW(因为 ...

  8. 【ZZ】 DShader之位移贴图(Displacement Mapping)

    http://www.myexception.cn/other/1397638.html DShader之位移贴图(Displacement Mapping) www.MyException.Cn   ...

  9. [比较老的文章]三维渲染引擎 OGRE 与 OSG 的比较综述

    1 .引言随着计算机可视化.虚拟现实技术的飞速发展,人们对实时真实感渲染以及场景复杂度提出了更高的要求.传统的直接使用底层图形接口如OpenGL.DirectX开发图形应用的模式越来越暴露出开发复杂性 ...

随机推荐

  1. QT 获取文件MD5值

    /* 方法1 */ QFile theFile(fileNamePath); theFile.open(QIODevice::ReadOnly); QByteArray ba = QCryptogra ...

  2. uva11536 Smallest Sub-Array

    Thinking about it: 我的思路跟sliding window有点类似.假设已经确定了一个区间[l, r],序列中从 l 到 r 恰好包含了[1, K]的各个元素,则从 r 开始继续迭代 ...

  3. 用git上传项目到github

    1 git  clone  github仓库地址 2 git add . 3 git  commit -m "changes log" 4 git remote add origi ...

  4. 使用jodconverter和swftools实现文件在线预览

    参考:仿百度文库解决方案(四)——利用JODConverter调用OpenOffice.org服务转换文档为PDF 文档在线预览主要用到如下两个工具 1,安装openoffice(同时下载jodcon ...

  5. hdu4370 0 or 1【最短路+建图】

    转载请注明出处,谢谢:http://www.cnblogs.com/KirisameMarisa/p/4297627.html   ---by 墨染之樱花 题目链接:http://acm.hdu.ed ...

  6. 用Aspose.Cells控件读取Excel

    Aspose是一个很强大的控件,可以用来操作word,excel,ppt等文件,用这个控件来导入.导出数据非常方便.其中Aspose.Cells就是用来操作Excel的,功能有很多.我所用的是最基本的 ...

  7. 专门针对初学者的Node.js教程

    转载原文:http://www.csdn.net/article/2013-08-28/2816731-absolute-beginners-guide-to-nodejs Node.js的教程并不缺 ...

  8. 遇见Lambda

    转自:http://www.cnblogs.com/allenlooplee/archive/2012/07/03/2574119.html 在学习generate时候发现C++中的匿名函数,上面博文 ...

  9. js去除首尾空格

    简单的:str = jQuery.trim(str); var temp = " aa b "; console.log("cc" + temp); temp ...

  10. 解决Sublime Text3莫名的中文乱码问题

    有好几回用Sublime Text3写着中英混杂的文字的时候,会突然就弹出警告说什么编码不行,然后点击确定后,原来的中文全都乱码了: 然后即使按ctrl+z撤回也没用,重新打开也没用,用记事本的转换a ...