📄 shader_motionblur.cpp
字号:
/******************************************************************************
Copyright (C) 1999, 2000 NVIDIA Corporation
This file is provided without support, instruction, or implied warranty of any
kind. NVIDIA makes no guarantee of its fitness for a particular purpose and is
not liable under any circumstances for any damages or loss whatsoever arising
from the use or inability to use this file or items derived from it.
******************************************************************************/
#include "eb_effect.h"
#include "nvmesh.h"
#include "nvdevice.h"
#include "shader_MotionBlur.h"
#include "MotionBlur.h"
using namespace nv_objects;
using namespace std;
DECLARE_EFFECT_MAIN()
extern "C"
{
__declspec(dllexport) unsigned int GetNumEffects() { return 1; }
__declspec(dllexport) EBEffect* CreateEffect(unsigned int EffectNum)
{
return new CShaderMotionBlur();
}
}
void CShaderMotionBlur::UpdateProperties()
{
EBEffect::UpdateProperties();
AddProperty(new EBProperty("Wireframe", OBJECT_MEMBER(mbWireFrame), EBTYPE_BOOL_PROP));
EBEnumProperty* pEnumProp = new EBEnumProperty("Blur Length Options", OBJECT_MEMBER(meBlurLengthOption), EBTYPE_DWORD_PROP);
pEnumProp->AddEnumerant(new EBEnumValue(pEnumProp, "0.5x Blur Length", (DWORD)HALFxBLURLENGTH, EBTYPE_DWORD_PROP));
pEnumProp->AddEnumerant(new EBEnumValue(pEnumProp, "1.0x Blur Length", (DWORD)ONExBLURLENGTH, EBTYPE_DWORD_PROP));
pEnumProp->AddEnumerant(new EBEnumValue(pEnumProp, "1.5x Blur Length", (DWORD)ONEHALFxBLURLENGTH,EBTYPE_DWORD_PROP));
AddProperty(pEnumProp);
AddProperty(new EBProperty("Enable Motion Blur", OBJECT_MEMBER(m_bEnableMotionBlur), EBTYPE_BOOL_PROP));
AddProperty(new EBProperty("Speed 2x", OBJECT_MEMBER(m_bEnableSpeed2x), EBTYPE_BOOL_PROP));
AddProperty(new EBProperty("Pause", OBJECT_MEMBER(m_bPause), EBTYPE_BOOL_PROP));
m_pVertexShaderEnum->AddEnumerant(new EBEnumValue(m_pVertexShaderEnum, "Motion Blur", GetFilePath("MotionBlur.nvv"), EBTYPE_STRING_PROP));
}
CShaderMotionBlur::CShaderMotionBlur()
: m_pNVDevice(NULL)
, m_pFloorMesh(NULL)
, m_pBlurredObjectMesh(NULL)
, m_pBlurredObjectMap(NULL)
, m_pBlurredObjectVB(NULL)
, m_bEnableMotionBlur( true )
, m_bEnableSpeed2x( false )
, m_bPause( false )
, meBlurLengthOption( ONExBLURLENGTH )
, mbWireFrame ( false )
{
for (int i = 6; --i >= 0; )
{
m_pBlurredObjectIB[i] = NULL;
}
m_strEffectName = "Motion Blur";
m_strEffectLocation = "Vertex Shaders\\Deformation";
m_strEffectPixelShader = "";
m_strEffectVertexShader = GetFilePath("MotionBlur.nvv");
}
CShaderMotionBlur::~CShaderMotionBlur()
{
Free();
}
#pragma optimize ("", off)
HRESULT CShaderMotionBlur::Initialize(IDirect3DDevice8* pDev)
{
HRESULT hr;
m_pD3DDev = pDev;
pDev->AddRef();
m_pNVDevice = new NVMotionBlurDevice(pDev, this);
DWORD dwVBFlags = D3DUSAGE_WRITEONLY;
LPD3DXBUFFER pCode = NULL;
DWORD declaration[] =
{
D3DVSD_STREAM(0),
D3DVSD_REG(D3DVSDE_POSITION, D3DVSDT_FLOAT3),
D3DVSD_REG(D3DVSDE_NORMAL, D3DVSDT_FLOAT3),
D3DVSD_REG(D3DVSDE_TEXCOORD0,D3DVSDT_FLOAT2),
D3DVSD_END()
};
m_dwMotionBlurShader = 0;
hr = LoadAndCreateShader(GetFilePath("MotionBlur.vso"), &declaration[0], 0, SHADERTYPE_VERTEX, &m_dwMotionBlurShader);
if (FAILED(hr))
return hr;
std::string const objectNameToLoad("tiger");
// Load the blurred object x file and extract its mesh
m_pBlurredObjectMesh = new NVMesh();
hr = m_pBlurredObjectMesh->Create(m_pNVDevice, GetFilePath(objectNameToLoad + ".x"));
if (FAILED(hr))
{
m_strLastError = "Could not load " + GetFilePath(objectNameToLoad + ".x");
return hr;
}
m_pBlurredObjectMesh->SetFVF(m_pNVDevice, MOTIONBLURVERTEX_FVF);
m_pBlurredObjectMesh->SetVertexShader(m_dwMotionBlurShader);
m_pBlurredObjectMesh->RestoreDeviceObjects(m_pNVDevice);
hr = D3DXCreateTextureFromFileEx(m_pD3DDev,
GetFilePath(objectNameToLoad + ".dds").c_str(),
D3DX_DEFAULT,
D3DX_DEFAULT,
0,
0,
D3DFMT_UNKNOWN,
D3DPOOL_MANAGED,
D3DX_FILTER_LINEAR,
D3DX_FILTER_LINEAR,
0,
NULL,
NULL,
&m_pBlurredObjectMap);
if (FAILED(hr))
{
m_strLastError = "Could not load texture " + GetFilePath(objectNameToLoad + ".dds");
return hr;
}
// Compute a (somewhat)-minimum radius sphere around the object
// and store that diameter in the vertex shader constant area.
FLOAT radius;
FLOAT maxRadius = 0.0f;
int const kStride = D3DXGetFVFVertexSize(m_pBlurredObjectMesh->GetSysMemMesh()->GetFVF());
D3DXVECTOR3 *pVertices;
m_numVertices = m_pBlurredObjectMesh->GetSysMemMesh()->GetNumVertices();
m_pBlurredObjectMesh->GetSysMemMesh()->GetVertexBuffer( &m_pBlurredObjectVB );
m_pBlurredObjectVB->Lock( 0, 0, (BYTE**)&pVertices, 0 );
int i;
for (i = m_numVertices; --i >= 0; )
{
FLOAT x = pVertices->x;
FLOAT y = pVertices->y;
FLOAT z = pVertices->z;
radius = sqrtf( x*x + y*y + z*z );
if (maxRadius < radius)
maxRadius = radius;
pVertices = (D3DXVECTOR3*) (((BYTE*)pVertices) + kStride);
}
m_pBlurredObjectVB->Unlock();
FLOAT const kFudge = 2.0f;
m_OneOverExtent = kFudge/maxRadius;
IDirect3DIndexBuffer8* pIB;
D3DINDEXBUFFER_DESC ddsdDescIB;
m_pBlurredObjectMesh->GetSysMemMesh()->GetIndexBuffer( &pIB );
pIB->GetDesc(&ddsdDescIB);
switch (ddsdDescIB.Format)
{
case D3DFMT_INDEX16:
m_numIndices = ddsdDescIB.Size / 2;
break;
case D3DFMT_INDEX32:
m_numIndices = ddsdDescIB.Size / 4;
break;
default:
m_numIndices = 0;
assert(false);
break;
}
// copy the indices into my private index buffers
BYTE* pSrc;
BYTE* pDest;
D3DXVECTOR3 *pVector[6];
WORD index[6];
FLOAT curAvgX, curAvgY, curAvgZ;
FLOAT nextAvgX, nextAvgY, nextAvgZ;
int j, k;
pIB->Lock(0, ddsdDescIB.Size, &pSrc, D3DLOCK_READONLY | D3DLOCK_NOSYSLOCK );
m_pBlurredObjectVB->Lock( 0, 0, (BYTE**)&pVertices, 0 );
for (i = 6; --i >= 0; )
{
hr = pDev->CreateIndexBuffer(ddsdDescIB.Size, 0, ddsdDescIB.Format,
D3DPOOL_DEFAULT, &(m_pBlurredObjectIB[i]) );
assert( ! FAILED(hr) );
m_pBlurredObjectIB[i]->Lock(0, ddsdDescIB.Size, &pDest, D3DLOCK_NOSYSLOCK );
memcpy(pDest, pSrc, ddsdDescIB.Size);
// sort the indices so that triangles are ordered in in/decreasing x/y/z
// I could potentially also pre-backface cull all triangles with
// Normal dot fromCam > 1/sqrt(2.0) for each of the IndexBuffers.
// Some other time maybe.
bool bSorted = false;
while (! bSorted)
{
bSorted = true;
for (j = 0; j < m_numIndices-3; j += 3 )
{
for (k = 6; --k >= 0; )
{
index[k] = *((WORD *) (pDest + 2*(j+k)));
pVector[k] = (D3DXVECTOR3*) (((BYTE*)pVertices) + index[k] * kStride);
}
curAvgX = (pVector[0]->x + pVector[1]->x + pVector[2]->x);
nextAvgX = (pVector[3]->x + pVector[4]->x + pVector[5]->x);
curAvgY = (pVector[0]->y + pVector[1]->y + pVector[2]->y);
nextAvgY = (pVector[3]->y + pVector[4]->y + pVector[5]->y);
curAvgZ = (pVector[0]->z + pVector[1]->z + pVector[2]->z);
nextAvgZ = (pVector[3]->z + pVector[4]->z + pVector[5]->z);
bool bSwap;
switch (i)
{
case 0:
bSwap = (curAvgX > nextAvgX); // fromCam = -x
break;
case 1:
bSwap = (curAvgX < nextAvgX); // fromCam = +x
break;
case 2:
bSwap = (curAvgY > nextAvgY); // fromCam = -y
break;
case 3:
bSwap = (curAvgY < nextAvgY); // fromCam = +y
break;
case 4:
bSwap = (curAvgZ > nextAvgZ); // fromCam = -z
break;
case 5:
bSwap = (curAvgZ < nextAvgZ); // fromCam = +z
break;
}
if (bSwap)
{
bSorted = false;
// swap triangles by swapping all three indices
for (k = 3; --k >= 0; )
{
*((WORD *) (pDest + 2*(j+k ))) = index[k+3];
*((WORD *) (pDest + 2*(j+k+3))) = index[k];
}
}
}
}
m_pBlurredObjectIB[i]->Unlock();
}
m_pBlurredObjectVB->Unlock();
pIB->Unlock();
SAFE_RELEASE( pIB );
// Load the seafloor x file and extract its mesh
m_pFloorMesh = new NVMesh();
hr = m_pFloorMesh->Create(m_pNVDevice, GetFilePath("seafloor.x"));
if (FAILED(hr))
{
m_strLastError = "Could not create seafloor.x";
return hr;
}
m_pFloorMesh->SetFVF(m_pNVDevice, MOTIONBLURVERTEX_FVF);
m_pFloorMesh->SetVertexShader(m_dwMotionBlurShader);
IDirect3DVertexBuffer8* pVB;
// Add some "hilliness" to the terrain
if( SUCCEEDED( m_pFloorMesh->GetSysMemMesh()->GetVertexBuffer( &pVB ) ) )
{
MotionBlurVertex* pVertices;
DWORD dwNumVertices = m_pFloorMesh->GetSysMemMesh()->GetNumVertices();
pVB->Lock( 0, 0, (BYTE**)&pVertices, 0 );
for( DWORD i=0; i<dwNumVertices; i++ )
{
pVertices[i].Position.y += (rand()/(FLOAT)RAND_MAX);
pVertices[i].Position.y += (rand()/(FLOAT)RAND_MAX);
pVertices[i].Position.y += (rand()/(FLOAT)RAND_MAX);
pVertices[i].Texture.x *= 10;
pVertices[i].Texture.y *= 10;
}
pVB->Unlock();
pVB->Release();
}
m_pFloorMesh->RestoreDeviceObjects(m_pNVDevice);
// set up render state
m_pD3DDev->SetRenderState( D3DRS_LIGHTING, FALSE );
m_pD3DDev->SetRenderState( D3DRS_CULLMODE, D3DCULL_CCW );
m_pD3DDev->SetRenderState( D3DRS_FOGENABLE, FALSE);
m_pD3DDev->SetRenderState( D3DRS_DITHERENABLE, FALSE );
m_pD3DDev->SetRenderState( D3DRS_SPECULARENABLE, FALSE );
m_pD3DDev->SetRenderState( D3DRS_ZENABLE, TRUE );
m_pD3DDev->SetTextureStageState(0, D3DTSS_MINFILTER, D3DTEXF_LINEAR );
m_pD3DDev->SetTextureStageState(0, D3DTSS_MAGFILTER, D3DTEXF_LINEAR );
m_pD3DDev->SetTextureStageState(0, D3DTSS_MIPFILTER, D3DTEXF_LINEAR);
m_pD3DDev->SetRenderState( D3DRS_ALPHABLENDENABLE, TRUE);
m_pD3DDev->SetRenderState( D3DRS_SRCBLEND, D3DBLEND_SRCALPHA );
m_pD3DDev->SetRenderState( D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -