📄 depthoffield.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 <crtdbg.h>
#include "eb_effect.h"
#include "nvtex.h"
#include "nvdevice.h"
#include "..\CommonSrc\NV_Error.h"
#include "DepthOfField.h"
#include "Constants.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 CDepthOfField();
}
}
float const CDepthOfField::kCloseClip = 0.1f; // in m
float const CDepthOfField::kFarClip = 520.0f; // in m
// min and max focus distance in cm
// (focusing beyond 200m is equivalent to infinity, even for 600mm lenses.)
// (focusing closer than the texture-resolution does not make sense)
// Even so, this technique does not work well for wide-angle lenses with
// close focusing: the distance to camera texture resolution is just not there
// to do that (in addition total depth-resolution is only linear 8bits), so this
// technique as coded here is really mostly for tele-photo zooms with far-focuses, i.e.,
// following rally-cars, race-cars, etc., etc.)
float const CDepthOfField::kMinFocusDistance = kMaxFocusDistance/kConfusionLookupHeight;
float const CDepthOfField::kMaxFocusDistance = 20000.0;
// only allow "normal" thru tele-photo lenses
float const CDepthOfField::kMinFocalLength = 3.0f; // in cm
float const CDepthOfField::kMaxFocalLength = 60.0f; // in cm
// 35mm film is actually 3.6 cm wide!
float const CDepthOfField::kFilmDimension = 3.6f;
// this constant describes how much the circle of confusion espands
// when applying the 9-sample box-filter to the texture
float const CDepthOfField::kBlurFactor = 1.5f;
CDepthOfField::CDepthOfField()
: m_pNVDevice(NULL)
, mbWireFrame (false)
, meDisplayOption(SHOW_COLORS)
, mbUsesVolumes(false)
, mpMouseUI(NULL)
, mCamLookDirection(0.0f, 0.0f, 1.0f)
, mFStop ( 1.0f)
, mFocalLength ( 20.0f) // in cm
, mFocusDistance( 2536.0f) // in cm
, mWorldBoxDimensions( 150.0f, 150.0f, 150.0f ) // in m!
, mpWorldBoxVertices(NULL)
, mpWorldBoxIndices (NULL)
, m_dwBlurVertexShader(0)
, m_dwBlurPixelShader(0)
, m_dwWorldVertexShader(0)
, m_dwWorldPixelShader(0)
, m_dwWorldNoDoFPixelShader(0)
, m_dwTetraVertexShader(0)
, m_dwTetraPixelShader(0)
, m_dwTetraNoDoFPixelShader(0)
, m_dwDepthOfFieldPixelShader(0)
, m_dwShowBlurrinessShader(0)
, mpQuadVertexBuffer(NULL)
, mpTetrahedronVertices(NULL)
, mpTetrahedronIndices (NULL)
, mpBackbufferColor(NULL)
, mpBackbufferDepth(NULL)
, mpDepthTarget(NULL)
, mpCircleOfConfusionLookup(NULL)
, mpVolCircleOfConfusionLookup(NULL)
, mpObjectTexture(NULL)
{
m_strEffectName = "Depth of Field";
m_strEffectLocation = "Pixel Shaders\\Image Processing";
m_strEffectPixelShader = GetFilePath("Tetrahedron.nvp");
m_strEffectVertexShader = GetFilePath("World.nvv");
for (DWORD i = 0; i < 6; i++)
mpWorldTextures[i] = NULL;
}
CDepthOfField::~CDepthOfField()
{
Free();
}
HRESULT CDepthOfField::ConfirmDevice(D3DCAPS8* pCaps, DWORD dwBehavior, D3DFORMAT Format)
{
// check vertex shading support
if(D3DSHADER_VERSION_MAJOR(pCaps->VertexShaderVersion) < 1)
{
m_strLastError = "Device does not support vertex shaders!";
return E_FAIL;
}
if(D3DSHADER_VERSION_MINOR(pCaps->VertexShaderVersion) < 1)
{
m_strLastError = "Device does not support 1.1 vertex shaders!";
return E_FAIL;
}
// check simultaneous texture support
if(pCaps->MaxSimultaneousTextures < 4)
{
m_strLastError = "Device does not support 4 simultaneous textures!";
return E_FAIL;
}
// check pixel shader support
if(D3DSHADER_VERSION_MAJOR(pCaps->PixelShaderVersion) < 1)
{
m_strLastError = "Device does not support pixel shaders!";
return E_FAIL;
}
if(D3DSHADER_VERSION_MINOR(pCaps->PixelShaderVersion) < 1)
{
m_strLastError = "Device does not support 1.1 pixel shaders!";
return E_FAIL;
}
if(pCaps->MaxTextureBlendStages < 8)
{
m_strLastError = "Device does not support 8 register combiners!";
return E_FAIL;
}
mbUsesVolumes = (pCaps->TextureCaps & D3DPTEXTURECAPS_VOLUMEMAP) != 0;
return S_OK;
}
void CDepthOfField::UpdateProperties()
{
EBEffect::UpdateProperties();
// Options
AddProperty(new EBProperty("Wireframe", OBJECT_MEMBER(mbWireFrame), EBTYPE_BOOL_PROP));
EBEnumProperty* pEnumProp = new EBEnumProperty("Display Options", OBJECT_MEMBER(meDisplayOption), EBTYPE_DWORD_PROP);
pEnumProp->AddEnumerant(new EBEnumValue(pEnumProp, "Show Colors", (DWORD)SHOW_COLORS, EBTYPE_DWORD_PROP));
pEnumProp->AddEnumerant(new EBEnumValue(pEnumProp, "Show Depth", (DWORD)SHOW_DEPTH, EBTYPE_DWORD_PROP));
pEnumProp->AddEnumerant(new EBEnumValue(pEnumProp, "Show Blurriness", (DWORD)SHOW_BLURRINESS, EBTYPE_DWORD_PROP));
AddProperty(pEnumProp);
// Vertex shaders
m_pVertexShaderEnum->AddEnumerant(new EBEnumValue(m_pVertexShaderEnum, "World Rendering", GetFilePath("World.nvv"), EBTYPE_STRING_PROP));
m_pVertexShaderEnum->AddEnumerant(new EBEnumValue(m_pVertexShaderEnum, "Object Rendering", GetFilePath("Tetrahedron.nvv"), EBTYPE_STRING_PROP));
m_pVertexShaderEnum->AddEnumerant(new EBEnumValue(m_pVertexShaderEnum, "Screen-Quad Rendering", GetFilePath("Blur.nvv"), EBTYPE_STRING_PROP));
// Pixel shaders
m_pPixelShaderEnum->AddEnumerant(new EBEnumValue(m_pPixelShaderEnum, "Object Rendering", GetFilePath("Tetrahedron.nvp"), EBTYPE_STRING_PROP));
m_pPixelShaderEnum->AddEnumerant(new EBEnumValue(m_pPixelShaderEnum, "Screen-Quad Rendering", GetFilePath("World.nvp"), EBTYPE_STRING_PROP));
m_pPixelShaderEnum->AddEnumerant(new EBEnumValue(m_pPixelShaderEnum, "Texture Blurring", GetFilePath("Blur.nvp"), EBTYPE_STRING_PROP));
m_pPixelShaderEnum->AddEnumerant(new EBEnumValue(m_pPixelShaderEnum, "Depth of Field Combination", GetFilePath("DepthOfFieldBlend.nvp"), EBTYPE_STRING_PROP));
}
HRESULT CDepthOfField::Initialize(IDirect3DDevice8* pDev)
{
HRESULT hr;
ZeroMemory(&m_bKey[0], sizeof(bool) * kMaxVKey);
// get the device
m_pD3DDev = pDev;
pDev->AddRef();
m_pNVDevice = new NVDevice(pDev);
//initialize mouse UI
D3DVIEWPORT8 viewport;
RECT rect;
m_pD3DDev->GetViewport(&viewport);
rect.left = rect.top = 0;
rect.bottom = viewport.Height;
rect.right = viewport.Width;
mpMouseUI = new MouseUI(rect, true);
mpMouseUI->SetRotationalSensitivityFactor(1.0f);
CreateTextureRenderTarget();
hr = InitBlurRendering();
if (FAILED(hr))
{
m_strLastError = "Failed to initialise blur rendering";
return hr;
}
hr = InitWorldRendering();
if (FAILED(hr))
{
m_strLastError = "Failed to initialise world rendering";
return hr;
}
hr = InitTetrahedronRendering();
if (FAILED(hr))
{
m_strLastError = "Failed to initialise tetrahedron rendering";
return hr;
}
UpdateCameraParameters();
GenerateCircleOfConfusionTexture();
return S_OK;
}
HRESULT CDepthOfField::InitBlurRendering()
{
HRESULT hr;
// create the vertex and pixel shaders for filtering the rendering target
vector<DWORD> Declaration;
Declaration.push_back(D3DVSD_STREAM(0));
Declaration.push_back(D3DVSD_REG(0, D3DVSDT_FLOAT3));
Declaration.push_back(D3DVSD_REG(1, D3DVSDT_FLOAT2));
Declaration.push_back(D3DVSD_END());
hr = LoadAndCreateShader(GetFilePath("Blur.vso"), &Declaration[0], 0, SHADERTYPE_VERTEX, &m_dwBlurVertexShader);
if (FAILED(hr))
return hr;
hr = LoadAndCreateShader(GetFilePath("Blur.pso"), NULL, 0, SHADERTYPE_PIXEL, &m_dwBlurPixelShader);
if (FAILED(hr))
return hr;
hr = LoadAndCreateShader(GetFilePath("DepthOfFieldBlend.pso"), NULL, 0, SHADERTYPE_PIXEL, &m_dwDepthOfFieldPixelShader);
if (FAILED(hr))
return hr;
hr = LoadAndCreateShader(GetFilePath("ShowBlurriness.pso"), NULL, 0, SHADERTYPE_PIXEL, &m_dwShowBlurrinessShader);
if (FAILED(hr))
return hr;
// create vertex buffer
hr = m_pD3DDev->CreateVertexBuffer( 4 * sizeof(tQuadVertex), D3DUSAGE_WRITEONLY | D3DUSAGE_DYNAMIC, 0, D3DPOOL_DEFAULT, &mpQuadVertexBuffer);
if (FAILED(hr))
return hr;
tQuadVertex *pBuff;
if (mpQuadVertexBuffer)
{
hr = mpQuadVertexBuffer->Lock(0, 4 * sizeof(tQuadVertex),(BYTE**)&pBuff, 0);
if (FAILED(hr))
{
m_strLastError = "Couldn't lock buffer!";
return hr;
}
for (int i = 0; i < 4; ++i)
{
pBuff->mPosition = D3DXVECTOR3((i==0 || i==1) ? -1.0f : 1.0f,
(i==0 || i==3) ? -1.0f : 1.0f,
0.0f);
pBuff->mTexture = D3DXVECTOR2((i==0 || i==1) ? 0.0f : 1.0f,
(i==0 || i==3) ? 1.0f : 0.0f);
pBuff++;
}
mpQuadVertexBuffer->Unlock();
}
D3DSURFACE_DESC ddsd;
mpTextureFiltered[0]->GetLevelDesc(0, &ddsd);
CreateAndWriteUVOffsets(ddsd.Width, ddsd.Height);
return S_OK;
}
HRESULT CDepthOfField::InitWorldRendering()
{
HRESULT hr;
// create the vertex and pixel shaders for rendering of world objects
vector<DWORD> Declaration;
Declaration.push_back(D3DVSD_STREAM(0));
Declaration.push_back(D3DVSD_REG(0, D3DVSDT_FLOAT3));
Declaration.push_back(D3DVSD_REG(2, D3DVSDT_FLOAT2));
Declaration.push_back(D3DVSD_END());
hr = LoadAndCreateShader(GetFilePath("World.vso"), &Declaration[0], 0, SHADERTYPE_VERTEX, &m_dwWorldVertexShader);
if (FAILED(hr))
return hr;
hr = LoadAndCreateShader(GetFilePath("World.pso"), NULL, 0, SHADERTYPE_PIXEL, &m_dwWorldPixelShader);
if (FAILED(hr))
return hr;
hr = LoadAndCreateShader(GetFilePath("WorldNoDoFLookup.pso"), NULL, 0, SHADERTYPE_PIXEL, &m_dwWorldNoDoFPixelShader);
if (FAILED(hr))
return hr;
CreateWorldCube();
return S_OK;
}
HRESULT CDepthOfField::InitTetrahedronRendering()
{
HRESULT hr;
// create the vertex and pixel shaders for rendering of objects within the world
vector<DWORD> Declaration;
Declaration.push_back(D3DVSD_STREAM(0));
Declaration.push_back(D3DVSD_REG(0, D3DVSDT_FLOAT3));
Declaration.push_back(D3DVSD_REG(1, D3DVSDT_FLOAT3));
Declaration.push_back(D3DVSD_REG(2, D3DVSDT_FLOAT2));
Declaration.push_back(D3DVSD_END());
hr = LoadAndCreateShader(GetFilePath("Tetrahedron.vso"), &Declaration[0], 0, SHADERTYPE_VERTEX, &m_dwTetraVertexShader);
if (FAILED(hr))
return hr;
hr = LoadAndCreateShader(GetFilePath("Tetrahedron.pso"), NULL, 0, SHADERTYPE_PIXEL, &m_dwTetraPixelShader);
if (FAILED(hr))
return hr;
hr = LoadAndCreateShader(GetFilePath("TetrahedronNoDoFLookup.pso"), NULL, 0, SHADERTYPE_PIXEL, &m_dwTetraNoDoFPixelShader);
if (FAILED(hr))
return hr;
CreateTetrahedron();
return S_OK;
}
HRESULT CDepthOfField::SetBlurRenderState()
{
m_pD3DDev->SetRenderState(D3DRS_FILLMODE, D3DFILL_SOLID);
m_pD3DDev->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_SELECTARG1);
m_pD3DDev->SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_TEXTURE);
m_pD3DDev->SetTextureStageState(0, D3DTSS_COLORARG2, D3DTA_DIFFUSE);
m_pD3DDev->SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_DISABLE);
for (int i = 0; i < 4; ++i)
{
m_pD3DDev->SetTextureStageState(i, D3DTSS_MAGFILTER, D3DTEXF_LINEAR);
m_pD3DDev->SetTextureStageState(i, D3DTSS_MINFILTER, D3DTEXF_LINEAR);
m_pD3DDev->SetTextureStageState(i, D3DTSS_MIPFILTER, D3DTEXF_NONE);
m_pD3DDev->SetTextureStageState(i, D3DTSS_ADDRESSU, D3DTADDRESS_CLAMP);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -