📄 depthoffield.cpp
字号:
// reset offsets to 0
offset.x = 0.0f;
m_pD3DDev->SetVertexShaderConstant(CV_UV_OFFSET_TO_USE, &offset, 1);
hr = m_pD3DDev->DrawPrimitive(D3DPT_TRIANGLEFAN, 0, 2);
return hr;
}
HRESULT CDepthOfField::CreateTextureRenderTarget()
{
HRESULT hr;
// first simply create the circle of confusion look up map
// This texture could be 3D (if available) or 2D or 1D. Trade-off
// which parameters vary by how much and how often what size texture
// can be regenerated.
if (mbUsesVolumes)
{
hr = m_pD3DDev->CreateVolumeTexture( kConfusionLookupWidth, kConfusionLookupHeight, kConfusionLookupDepth,
1, 0, D3DFMT_A8R8G8B8, D3DPOOL_MANAGED,
&mpVolCircleOfConfusionLookup );
if( FAILED(hr) )
{
m_strLastError = "Could not create volume texture!";
return E_FAIL;
}
}
else
{
hr = m_pD3DDev->CreateTexture( kConfusionLookupWidth, kConfusionLookupHeight,
1, 0, D3DFMT_A8R8G8B8, D3DPOOL_MANAGED,
&mpCircleOfConfusionLookup );
if( FAILED(hr) )
{
m_strLastError = "Could not create 2D look-up texture!";
return E_FAIL;
}
}
// get a pointer to the current back-buffer (so we can restore it later)
m_pD3DDev->GetRenderTarget( &mpBackbufferColor );
m_pD3DDev->GetDepthStencilSurface( &mpBackbufferDepth );
_ASSERT( mpBackbufferColor != NULL );
_ASSERT( mpBackbufferDepth != NULL );
// get the description for the texture we want to filter
D3DSURFACE_DESC ddsd;
mpBackbufferColor->GetDesc(&ddsd);
// set ddsd width/height to next smaller power of 2
// we loose some precision, but it is hard to tell, yet the smaller
// size is much higher performance as we have to filter many fewer pixels...
int logWidth = static_cast<int>(logf(static_cast<float>(ddsd.Width)) /logf(2.0f));
int logHeight = static_cast<int>(logf(static_cast<float>(ddsd.Height))/logf(2.0f));
ddsd.Width = pow(2, logWidth );
ddsd.Height = pow(2, logHeight);
// make a depth buffer to go with the first texture
hr = m_pD3DDev->CreateDepthStencilSurface(ddsd.Width, ddsd.Height, // use color's width/height!!!
D3DFMT_D24X8, D3DMULTISAMPLE_NONE,
&mpDepthTarget);
// create new textures just like the current texture
// these will be used as filter-targets and sources
for (int i = 0; i < 3; ++i)
{
hr = m_pD3DDev->CreateTexture(ddsd.Width, ddsd.Height, 1,
D3DUSAGE_RENDERTARGET, D3DFMT_A8R8G8B8,
D3DPOOL_DEFAULT, &mpTextureFiltered[i]);
hr = mpTextureFiltered[i]->GetSurfaceLevel(0, &mpFilterTarget[i]);
// set our render target to the new and shiny textures without depth
hr = m_pD3DDev->SetRenderTarget(mpFilterTarget[i], (i==0) ? mpDepthTarget : NULL);
if (FAILED(hr))
{
m_strLastError = "Can't SetRenderTarget to new surface!\n";
_ASSERT(false);
return E_FAIL;
}
}
for (i = 0; i < 2; ++i)
{
hr = m_pD3DDev->CreateTexture(ddsd.Width, ddsd.Height, 1,
D3DUSAGE_RENDERTARGET, D3DFMT_A8R8G8B8,
D3DPOOL_DEFAULT, &mpTempTexture[i]);
hr = mpTempTexture[i]->GetSurfaceLevel(0, &mpTempTarget[i]);
// set our render target to the new and shiny textures without depth
hr = m_pD3DDev->SetRenderTarget(mpTempTarget[i], NULL);
if (FAILED(hr))
{
m_strLastError = "Can't SetRenderTarget to new surface!\n";
_ASSERT(false);
return E_FAIL;
}
}
// switch back to conventional back-buffer
hr = m_pD3DDev->SetRenderTarget(mpBackbufferColor, mpBackbufferDepth);
if (FAILED(hr))
{
m_strLastError = "Can't SetRenderTarget to original back-buffer surfaces!\n";
_ASSERT(false);
return E_FAIL;
}
return S_OK;
}
void CDepthOfField::CreateAndWriteUVOffsets(int width, int height)
{
// set-up offset to achieve a nine-sample box-filter centered
// over each texel.
float const kPerTexelWidth = 1.0f/static_cast<float>(width);
float const kPerTexelHeight = 1.0f/static_cast<float>(height);
float const noOffsetX[4] = { 0.0f, 0.0f, 0.0f, 0.0f};
float const noOffsetY[4] = { 0.0f, 0.0f, 0.0f, 0.0f};
int i;
// nine sample box filter
float const s = 2.0f/3.0f;
float const box9OffsetX[4] = { 0.0f,
0.0f,
2.0f * s * kPerTexelWidth,
2.0f * s * kPerTexelWidth };
float const box9OffsetY[4] = { 0.0f,
2.0f * s * kPerTexelHeight,
2.0f * s * kPerTexelHeight,
0.0f };
// write all these offsets to constant memory
for (i = 0; i < 4; ++i)
{
D3DXVECTOR4 noOffset( noOffsetX[i], noOffsetY[i], 0.0f, 0.0f);
D3DXVECTOR4 actualOffset(box9OffsetX[i], box9OffsetY[i], 0.0f, 0.0f);
m_pD3DDev->SetVertexShaderConstant(CV_UV_T0_NO_OFFSET + 2*i, &noOffset, 1);
m_pD3DDev->SetVertexShaderConstant(CV_UV_T0_TYPE1 + 2*i, &actualOffset, 1);
}
}
HRESULT CDepthOfField::CreateWorldCube()
{
HRESULT hr;
tQuadVertex *pVertices;
WORD *pIndices;
int i, j, k;
// first do the textures
string cubeFaceTextures[6] = { "skybox_left.dds",
"wood.dds",
"skybox_front.dds",
"skybox_back.dds",
"skybox_top.dds",
"skybox_right.dds"
};
for (i = 0; i < 6; i++)
{
mpWorldTextures[i] = new NVTexture();
hr = mpWorldTextures[i]->CreateFromFile(m_pD3DDev, GetFilePath(cubeFaceTextures[i]));
if (FAILED(hr))
{
m_strLastError = cubeFaceTextures[i];
_ASSERT(false);
return hr;
}
}
// now lets allocate vertices and indices for the cube faces
hr = m_pD3DDev->CreateVertexBuffer(kNumVertices * sizeof(tQuadVertex), D3DUSAGE_WRITEONLY, 0, D3DPOOL_MANAGED, &mpWorldBoxVertices);
hr = mpWorldBoxVertices->Lock(0, kNumVertices * sizeof(tQuadVertex),(BYTE**)&pVertices, 0);
if (FAILED(hr))
{
m_strLastError = "Could not create/lock vertex buffer!";
return hr;
}
hr = m_pD3DDev->CreateIndexBuffer(kNumIndices * sizeof(WORD), D3DUSAGE_WRITEONLY, D3DFMT_INDEX16, D3DPOOL_MANAGED, &mpWorldBoxIndices);
hr = mpWorldBoxIndices->Lock(0, kNumIndices * sizeof(WORD),(BYTE**)&pIndices, 0);
if (FAILED(hr))
{
m_strLastError = "Could not create/lock index buffer!";
return hr;
}
// Set up the vertices for the cube engulfing the world.
// Note: to prevent tiling problems, the u/v coords are knocked slightly inwards.
float const kFloorTextureRepeat = 2.0f * mWorldBoxDimensions.x;
D3DXVECTOR3 vertexCube[8] = { D3DXVECTOR3(-1.0f,-1.0f,-1.0f),
D3DXVECTOR3(-1.0f,-1.0f, 1.0f),
D3DXVECTOR3(-1.0f, 1.0f,-1.0f),
D3DXVECTOR3(-1.0f, 1.0f, 1.0f),
D3DXVECTOR3( 1.0f,-1.0f,-1.0f),
D3DXVECTOR3( 1.0f,-1.0f, 1.0f),
D3DXVECTOR3( 1.0f, 1.0f,-1.0f),
D3DXVECTOR3( 1.0f, 1.0f, 1.0f) };
D3DXVECTOR2 uvCube[4] = { D3DXVECTOR2( 0.0f, 0.0f),
D3DXVECTOR2( 0.0f, 1.0f),
D3DXVECTOR2( 1.0f, 0.0f),
D3DXVECTOR2( 1.0f, 1.0f) };
// right: 0 1 2 3
// top: 0 1 4 5
// front: 0 2 4 6
// back: 1 3 5 7
// bottom: 2 3 6 7
// left: 4 5 6 7
D3DXVECTOR3 ul, ur, ll, lr;
D3DXVECTOR3 upper, lower, position;
D3DXVECTOR2 ulUV, urUV, llUV, lrUV;
D3DXVECTOR2 upperUV, lowerUV, uv;
float x, y;
// each face is tesselated (see kNumQuadsPerSide in .h file)
// to avoid interpolation errors for computing per-pixel distances
for (i = 0; i < 6; ++i) // for each face
{
if (i == 1) // bottom face is special
{
ul = D3DXVECTOR3(-1.0f, 0.0001f,-1.0f);
ur = D3DXVECTOR3(-1.0f, 0.0001f, 1.0f);
ll = D3DXVECTOR3( 1.0f, 0.0001f,-1.0f);
lr = D3DXVECTOR3( 1.0f, 0.0001f, 1.0f);
ulUV = D3DXVECTOR2(0.0f, 0.0f);
urUV = D3DXVECTOR2(0.0f, kFloorTextureRepeat);
llUV = D3DXVECTOR2(kFloorTextureRepeat, 0.0f);
lrUV = D3DXVECTOR2(kFloorTextureRepeat, kFloorTextureRepeat);
}
else
{
ul = vertexCube[(i<3)? 0 : (int)pow(2, i-3)];
ur = vertexCube[(i<3)? 1 + i/2 :3+2*((i-3)/2)];
ll = vertexCube[(i<3)? 2 + 2*((i+1)/2) : 5+((i-2)/2)];
lr = vertexCube[(i<3)? 3+(3*i+1)/2 : 7];
ulUV = uvCube[0];
urUV = uvCube[1];
llUV = uvCube[2];
lrUV = uvCube[3];
}
for (j = 0; j < kNumQuadsPerSide+1; ++j) // march in y
{
y = static_cast<float>(j)/static_cast<float>(kNumQuadsPerSide);
for (k = 0; k < kNumQuadsPerSide+1; ++k) // march in x
{
x = static_cast<float>(k)/static_cast<float>(kNumQuadsPerSide);
upper = (1.f-x)*ul + x*ur;
lower = (1.f-x)*ll + x*lr;
position = (1.f-y)*upper + y*lower;
upperUV = (1.f-x)*ulUV + x*urUV;
lowerUV = (1.f-x)*llUV + x*lrUV;
uv = (1.f-y)*upperUV + y*lowerUV;
*pVertices++ = tQuadVertex( position, uv );
}
}
}
// Set up the indices for the cube
for (i = 0; i < 6; ++i) // for each cube face
for (j = 0; j < kNumQuadsPerSide; ++j) // for each strip
for (k = 0; k < (kNumQuadsPerSide + 1); ++k)
{
*pIndices++ = k + j *(kNumQuadsPerSide+1) + i*kNumVerticesPerFace;
*pIndices++ = k + (j+1)*(kNumQuadsPerSide+1) + i*kNumVerticesPerFace;
}
mpWorldBoxVertices->Unlock();
mpWorldBoxIndices->Unlock();
return S_OK;
}
HRESULT CDepthOfField::CreateTetrahedron()
{
HRESULT hr;
tTetrahedronVertex *pVertices;
WORD *pIndices;
// get the texture
mpObjectTexture = new NVTexture();
hr = mpObjectTexture->CreateFromFile(m_pD3DDev, GetFilePath("ObjectTexture.dds"));
if (FAILED(hr))
{
m_strLastError = "Could not find ObjectTexture.dds";
_ASSERT(false);
return hr;
}
// now lets allocate vertices and indices for the tetrahedron
hr = m_pD3DDev->CreateVertexBuffer( 12 * sizeof(tTetrahedronVertex), D3DUSAGE_WRITEONLY, 0, D3DPOOL_MANAGED, &mpTetrahedronVertices);
hr = mpTetrahedronVertices->Lock(0, 12 * sizeof(tTetrahedronVertex),(BYTE**)&pVertices, 0);
if (FAILED(hr))
{
m_strLastError = "Could not create/lock vertex buffer!";
return hr;
}
hr = m_pD3DDev->CreateIndexBuffer( 12 * sizeof(WORD), D3DUSAGE_WRITEONLY, D3DFMT_INDEX16, D3DPOOL_MANAGED, &mpTetrahedronIndices);
hr = mpTetrahedronIndices->Lock(0, 12 * sizeof(WORD),(BYTE**)&pIndices, 0);
if (FAILED(hr))
{
m_strLastError = "Could not create/lock index buffer!";
return hr;
}
D3DXVECTOR2 uvCoord[3] = { D3DXVECTOR2(0.0f, 0.0f),
D3DXVECTOR2(0.0f, 1.0f),
D3DXVECTOR2(1.0f, 1.0f) };
D3DXVECTOR3 vertexPosition[4] = { D3DXVECTOR3(0.0f, 0.0f, 0.0f),
D3DXVECTOR3(0.0f, 1.0f, 0.0f),
D3DXVECTOR3(0.5f, 0.5f, 0.0f),
D3DXVECTOR3(0.0f, 0.5f,-0.5f) };
float const oneOverSqrt3 = 1.0f/sqrt(3.0f);
D3DXVECTOR3 triangleNormal[4] = { D3DXVECTOR3(-1.0f, 0.0f, 0.0f),
D3DXVECTOR3( 0.0f, 0.0f, 1.0f),
D3DXVECTOR3( oneOverSqrt3, -oneOverSqrt3, -oneOverSqrt3),
D3DXVECTOR3( oneOverSqrt3, oneOverSqrt3, -oneOverSqrt3) };
// first triangle
*pVertices++ = tTetrahedronVertex(vertexPosition[0], triangleNormal[0], uvCoord[0]);
*pVertices++ = tTetrahedronVertex(vertexPosition[1], triangleNormal[0], uvCoord[1]);
*pVertices++ = tTetrahedronVertex(vertexPosition[3], triangleNormal[0], uvCoord[2]);
// second triangle
*pVertices++ = tTetrahedronVertex(vertexPosition[0], triangleNormal[1], uvCoord[0]);
*pVertices++ = tTetrahedronVertex(vertexPosition[2], triangleNormal[1], uvCoord[1]);
*pVertices++ = tTetrahedronVertex(vertexPosition[1], triangleNormal[1], uvCoord[2]);
// third triangle
*pVertices++ = tTetrahedronVertex(vertexPosition[0], triangleNormal[2], uvCoord[0]);
*pVertices++ = tTetrahedronVertex(vertexPosition[3], triangleNormal[2], uvCoord[1]);
*pVertices++ = tTetrahedronVertex(vertexPosition[2], triangleNormal[2], uvCoord[2]);
// last triangle
*pVertices++ = tTetrahedronVertex(vertexPosition[1], triangleNormal[3], uvCoord[0]);
*pVertices++ = tTetrahedronVertex(vertexPosition[2], triangleNormal[3], uvCoord[1]);
*pVertices++ = tTetrahedronVertex(vertexPosition[3], triangleNormal[3], uvCoord[2]);
// indices are easy: simple triangle list in order
for (int i = 0; i < 12; ++i)
*pIndices++ = i;
mpTetrahedronVertices->Unlock();
mpTetrahedronIndices->Unlock();
return S_OK;
}
HRESULT CDepthOfField::GenerateCircleOfConfusionTexture()
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -