⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 shader_motionblur.cpp

📁 游戏编程精华02-含有几十个游戏编程例子
💻 CPP
📖 第 1 页 / 共 2 页
字号:
/******************************************************************************

  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 + -