📄 shader_blinnreflect.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.
Comments:
******************************************************************************/
#include "eb_effect.h"
#include "CA_Water.h"
#include "nvdevice.h"
#include "nvmesh.h"
#include "NV_Error.h"
#include "shader_dot3_util.h"
#include "shader_BlinnReflect.h"
#include "Constants.h"
#include "PixelConstants.h"
#include "nvtexture.h"
#include <vector>
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 CShaderBlinnReflect();
}
}
HRESULT CShaderBlinnReflect::ConfirmDevice(D3DCAPS8* pCaps, DWORD dwBehavior, D3DFORMAT Format)
{
if (!(pCaps->TextureCaps & D3DPTEXTURECAPS_CUBEMAP))
{
m_strLastError = "Device does not support cubemaps!";
return E_FAIL;
}
if (!(pCaps->TextureCaps & D3DPTEXTURECAPS_PROJECTED))
{
m_strLastError = "Device does not support 3 element texture coordinates!";
return E_FAIL;
}
if (!(pCaps->MaxTextureBlendStages >= 4))
{
m_strLastError = "Not enough texture blend stages!";
return E_FAIL;
}
if(D3DSHADER_VERSION_MAJOR(pCaps->PixelShaderVersion) < 1)
{
m_strLastError = "Device does not support pixel shaders!";
return E_FAIL;
}
if(!(pCaps->DevCaps & D3DDEVCAPS_RTPATCHES) )
{
m_strLastError = "Device does not support RTPATCHES!";
return E_FAIL;
}
return S_OK;
}
#define STR_INCREASEBUMPSCALE "Bump scale increase (+)"
#define STR_DECREASEBUMPSCALE "Bump scale decrease (-)"
#define STR_RESETPATCH "Reset patch offset (HOME)"
#define STR_MOREOPTION "Hit F1 for more options!"
void CShaderBlinnReflect::UpdateProperties()
{
EBEffect::UpdateProperties();
AddProperty(new EBTriggerProperty(STR_INCREASEBUMPSCALE));
AddProperty(new EBTriggerProperty(STR_DECREASEBUMPSCALE));
AddProperty(new EBTriggerProperty(STR_RESETPATCH));
AddProperty(new EBTriggerProperty(STR_MOREOPTION));
EBEnumProperty* pEnumProp = new EBEnumProperty("Display Options", OBJECT_MEMBER(m_eDisplayOption), EBTYPE_DWORD_PROP);
if (m_bSupportsQWVU)
pEnumProp->AddEnumerant(new EBEnumValue(pEnumProp, "8 Bit Signed BumpMap", (DWORD)DISPLAY_BLINN8BITSIGNED, EBTYPE_DWORD_PROP));
AddProperty(pEnumProp);
if (m_bSupportsPatches)
{
AddProperty(new EBProperty("Show Bezier-Patch", OBJECT_MEMBER(m_bUsePatch), EBTYPE_BOOL_PROP));
}
AddProperty(new EBProperty("Wireframe", OBJECT_MEMBER(m_bWireframe), EBTYPE_BOOL_PROP));
AddProperty(new EBProperty("Pause geometry animation", OBJECT_MEMBER(m_bPause), EBTYPE_BOOL_PROP));
// Vertex shaders
m_pVertexShaderEnum->AddEnumerant(new EBEnumValue(m_pVertexShaderEnum, "Texture Space", GetFilePath("blinn_reflect.nvv"), EBTYPE_STRING_PROP));
m_pVertexShaderEnum->AddEnumerant(new EBEnumValue(m_pVertexShaderEnum, "Simple Transform", GetFilePath("dot3_transform.nvv"), EBTYPE_STRING_PROP));
// Pixel shaders
m_pPixelShaderEnum->AddEnumerant(new EBEnumValue(m_pPixelShaderEnum, "Per-pixel Bump Reflections", GetFilePath("blinn_reflect.nvp"), EBTYPE_STRING_PROP));
}
CShaderBlinnReflect::CShaderBlinnReflect()
: m_eDisplayOption(DISPLAY_BLINN8BITSIGNED),
m_pPatchBuffer(NULL),
m_pVertexBuffer(NULL),
m_pIndexBuffer(NULL),
m_fAngle(0.0f),
m_pLightMesh(NULL),
m_pNVDevice(NULL),
m_pBumpMapQWVU(NULL),
m_pBumpMapHILO(NULL),
m_pGlossMap(NULL),
m_bUsePatch(true),
m_dwBlinnPixelShader(0),
m_dwBlinnVertexShader(0),
m_dwTransformShader(0),
m_dwBlinnPatchVertexShader(0),
m_dwTransformPatchShader(0),
m_pCubeTexture(NULL),
m_bSupportsPatches(true),
m_pUI(NULL),
m_bWireframe(false),
m_bPause(true),
m_fBumpScale(0.25f),
m_pCA_Water(NULL)
{
m_strEffectName = "Dynamic Normal Map"; // A string holding the name of the effect
m_strEffectLocation = "Pixel Shaders\\Bump Mapping";
m_strEffectPixelShader = GetFilePath("blinn_reflect.nvp");
m_strEffectVertexShader = GetFilePath("blinn_reflect.nvv");
}
CShaderBlinnReflect::~CShaderBlinnReflect()
{
Free();
}
#define TEX_SCALE 3.0f
HRESULT CShaderBlinnReflect::GenerateSphere(D3DXVECTOR3& vCenter, FLOAT fRadius, WORD wNumRings, WORD wNumSections, FLOAT sx, FLOAT sy, FLOAT sz)
{
FLOAT x, y, z, v, rsintheta; // Temporary variables
WORD i, j, n, m; // counters
D3DXVECTOR3 vPoint;
HRESULT hr;
SAFE_RELEASE(m_pVertexBuffer);
SAFE_RELEASE(m_pIndexBuffer);
//Generate space for the required triangles and vertices.
WORD wNumTriangles = (wNumRings + 1) * wNumSections * 2;
DWORD dwNumIndices = wNumTriangles*3;
DWORD dwNumVertices = (wNumRings + 1) * wNumSections + 2;
m_dwNumVertices = dwNumVertices;
m_dwNumIndices = wNumTriangles * 3;
m_dwNumFaces = wNumTriangles;
hr = m_pD3DDev->CreateVertexBuffer(dwNumVertices * sizeof(Dot3Vertex), 0, 0, D3DPOOL_MANAGED, &m_pVertexBuffer);
if (FAILED(hr))
{
return hr;
}
hr = m_pD3DDev->CreateIndexBuffer(3 * wNumTriangles * sizeof(WORD), 0, D3DFMT_INDEX16, D3DPOOL_MANAGED, &m_pIndexBuffer);
if (FAILED(hr))
{
return hr;
}
Dot3Vertex* pVertices;
WORD* pIndices;
m_pVertexBuffer->Lock(0, 0, (BYTE**)&pVertices, 0);
m_pIndexBuffer->Lock(0, 0, (BYTE**)&pIndices, 0);
// Generate vertices at the top and bottom points.
D3DXVECTOR3 vTopPoint = vCenter + D3DXVECTOR3( 0.0f, +sy*fRadius, 0.0f);
D3DXVECTOR3 vBotPoint = vCenter + D3DXVECTOR3( 0.0f, -sy*fRadius, 0.0f);
D3DXVECTOR3 vNormal = D3DXVECTOR3( 0.0f, 1.0f, 0.0f );
pVertices[0] = Dot3Vertex( D3DXVECTOR3(vTopPoint.x, vTopPoint.y, vTopPoint.z), D3DXVECTOR3(vNormal.x, vNormal.y, vNormal.z), D3DXVECTOR2(0.0f, 0.0f) );
pVertices[dwNumVertices-1] = Dot3Vertex( D3DXVECTOR3(vBotPoint.x, vBotPoint.y, vBotPoint.z), D3DXVECTOR3(-vNormal.x, -vNormal.y, -vNormal.z), D3DXVECTOR2(0.0f, 0.0f) );
// Generate vertex points for rings
FLOAT dtheta = (float)(D3DX_PI / (wNumRings + 2)); //Angle between each ring
FLOAT dphi = (float)(2*D3DX_PI / (wNumSections)); //Angle between each section
FLOAT theta = dtheta;
n = 1; //vertex being generated, begins at 1 to skip top point
for( i = 0; i < (wNumRings+1); i++ )
{
y = fRadius * (float)cos(theta); // y is the same for each ring
v = theta / D3DX_PI; // v is the same for each ring
rsintheta = fRadius * (float)sin(theta);
FLOAT phi = 0.0f;
for( j = 0; j < wNumSections; j++ )
{
x = rsintheta * (float)sin(phi);
z = rsintheta * (float)cos(phi);
FLOAT u = 1.0f - (FLOAT)(phi / (2 * D3DX_PI) );
assert(u <= 1.001f);
assert(u >= 0.0f);
vPoint = vCenter + D3DXVECTOR3( sx*x, sy*y, sz*z );
vNormal = D3DXVECTOR3( x/fRadius, y/fRadius, z/fRadius );
D3DXVec3Normalize(&vNormal, &vNormal);
pVertices[n] = Dot3Vertex( D3DXVECTOR3(vPoint.x, vPoint.y, vPoint.z), D3DXVECTOR3(vNormal.x, vNormal.y, vNormal.z), D3DXVECTOR2(u * TEX_SCALE, v * TEX_SCALE) );
phi += dphi;
++n;
}
theta += dtheta;
}
// Generate triangles for top and bottom caps.
for( i = 0; i < wNumSections; i++ )
{
pIndices[3*i+0] = 0;
pIndices[3*i+1] = i + 1;
pIndices[3*i+2] = 1 + ((i + 1) % wNumSections);
pIndices[3*(wNumTriangles - wNumSections + i)+0] = (WORD)( dwNumVertices - 1 );
pIndices[3*(wNumTriangles - wNumSections + i)+1] = (WORD)( dwNumVertices - 2 - i );
pIndices[3*(wNumTriangles - wNumSections + i)+2] = (WORD)( dwNumVertices - 2 -
((1 + i) % wNumSections) );
}
// Generate triangles for the rings
m = 1; // first vertex in current ring,begins at 1 to skip top point
n = wNumSections; // triangle being generated, skip the top cap
for( i = 0; i < wNumRings; i++ )
{
for( j = 0; j < (wNumSections); j++ )
{
pIndices[3*n+0] = m + j;
pIndices[3*n+1] = m + wNumSections + j;
pIndices[3*n+2] = m + wNumSections + ((j + 1) % wNumSections);
pIndices[3*(n+1)+0] = pIndices[3*n+0];
pIndices[3*(n+1)+1] = pIndices[3*n+2];
pIndices[3*(n+1)+2] = m + ((j + 1) % wNumSections);
n += 2;
}
m += wNumSections;
}
m_pVertexBuffer->Unlock();
m_pIndexBuffer->Unlock();
return S_OK;
}
HRESULT CShaderBlinnReflect::GenerateQuad(D3DXVECTOR3& vCenter, FLOAT fRadius)
{
SAFE_RELEASE(m_pVertexBuffer);
SAFE_RELEASE(m_pIndexBuffer);
m_dwNumVertices = 4;
m_dwNumIndices = 6;
m_dwNumFaces = m_dwNumIndices / 3;
m_pD3DDev->CreateVertexBuffer(m_dwNumVertices * sizeof(Dot3Vertex), 0, 0, D3DPOOL_MANAGED, &m_pVertexBuffer);
m_pD3DDev->CreateIndexBuffer(m_dwNumIndices * sizeof(WORD), 0, D3DFMT_INDEX16, D3DPOOL_MANAGED, &m_pIndexBuffer);
Dot3Vertex* pVertices;
WORD* pIndices;
m_pVertexBuffer->Lock(0, 0, (BYTE**)&pVertices, 0);
m_pIndexBuffer->Lock(0, 0, (BYTE**)&pIndices, 0);
pVertices[0] = Dot3Vertex(D3DXVECTOR3(vCenter.x - fRadius, vCenter.y + fRadius, 0.0f), D3DXVECTOR3(0.0f, 0.0f, -1.0f), D3DXVECTOR2(0.0f, 0.0f));
pVertices[1] = Dot3Vertex(D3DXVECTOR3(vCenter.x + fRadius, vCenter.y + fRadius, 0.0f), D3DXVECTOR3(0.0f, 0.0f, -1.0f), D3DXVECTOR2(1.0f * TEX_SCALE, 0.0f));
pVertices[2] = Dot3Vertex(D3DXVECTOR3(vCenter.x - fRadius, vCenter.y - fRadius, 0.0f), D3DXVECTOR3(0.0f, 0.0f, -1.0f), D3DXVECTOR2(0.0f, 1.0f * TEX_SCALE));
pVertices[3] = Dot3Vertex(D3DXVECTOR3(vCenter.x + fRadius, vCenter.y - fRadius, 0.0f), D3DXVECTOR3(0.0f, 0.0f, -1.0f), D3DXVECTOR2(1.0f * TEX_SCALE, 1.0f * TEX_SCALE));
pIndices[0] = 0;
pIndices[1] = 1;
pIndices[2] = 2;
pIndices[3] = 2;
pIndices[4] = 1;
pIndices[5] = 3;
m_pVertexBuffer->Unlock();
m_pIndexBuffer->Unlock();
return S_OK;
}
HRESULT CShaderBlinnReflect::GenerateSplinePatch()
{
HRESULT hr;
SAFE_RELEASE(m_pPatchBuffer);
// first alloc the buffers
int const kNumCtrlPts = 4 * 4;
hr = m_pD3DDev->CreateVertexBuffer(kNumCtrlPts * sizeof(Dot3Vertex),
D3DUSAGE_RTPATCHES|D3DUSAGE_DYNAMIC|D3DUSAGE_WRITEONLY,
0, D3DPOOL_DEFAULT, &m_pPatchBuffer);
// then do not do anything with it: AnimateSplinePatch will generate *all* data!
return hr;
}
HRESULT CShaderBlinnReflect::AnimateSplinePatch(EBTimer* pTimer)
{
Dot3Vertex* pVertices;
static const float fZOffset = 0.0f;
m_pPatchBuffer->Lock(0, 0, (BYTE**)&pVertices, D3DLOCK_DISCARD);
// re-initialize positions
int i, j;
for(i = 0; i < 4; i++)
{
for(j = 0; j < 4; j++)
{
pVertices[4*i + j].Position = D3DXVECTOR3(j - 1.5f, 1.5f - i, fZOffset);
pVertices[4*i + j].Position *= 0.25f;
}
}
float anim_disp_scale = 0.65f;
if (!m_bPause)
{
// modify central control points
m_ctrl1 = (fZOffset + anim_disp_scale * sinf(1.0f + 0.5f * pTimer->GetDuration()));
m_ctrl2 = (fZOffset + anim_disp_scale * sinf(2.0f + 0.35f * pTimer->GetDuration()));
m_ctrl3 = (fZOffset + anim_disp_scale * sinf(3.0f + 0.6f * pTimer->GetDuration()));
m_ctrl4 = (fZOffset + anim_disp_scale * sinf(4.0f + 0.1f * pTimer->GetDuration()));
}
pVertices[4*1 + 1].Position.z = m_ctrl1;
pVertices[4*2 + 1].Position.z = m_ctrl2;
pVertices[4*1 + 2].Position.z = m_ctrl3;
pVertices[4*2 + 2].Position.z = m_ctrl4;
// compute d/dv Position
D3DXVECTOR3 mesh[16];
for(i=0; i < 3; i++)
for(j=0; j < 4; j++)
mesh[4*i + j] = pVertices[4*i + j].Position - pVertices[4*(i+1) + j].Position;
ElevateToCubicMesh(mesh, 4, 3);
for(i=0; i < 4; i++)
for(j=0; j < 4; j++)
pVertices[4*i + j].T = mesh[4*i + j];
// dp/du
for(i=0; i < 4; i++)
for(j=0; j < 3; j++)
mesh[4*i + j] = pVertices[4*i + j].Position - pVertices[4*i + j+1].Position;
ElevateToCubicMesh(mesh, 3, 4);
for(i=0; i < 4; i++)
for(j=0; j < 4; j++)
pVertices[4*i + j].S = mesh[4*i + j];
return S_OK;
}
void CShaderBlinnReflect::ElevateToCubicMesh(D3DXVECTOR3 *pControlMesh,
unsigned int uOrder,
unsigned int vOrder) const
{
// Can transform constant, linear, quadratic, or cubic in either u/v
// to fully cubic in both u and v.
assert(uOrder >= 1 && uOrder <= 4);
assert(vOrder >= 1 && vOrder <= 4);
// mesh is assumed to be a 4x4 grid of D3DXVECTOR3, the upper left
// uOrder by vOrder corner is assumed to be populated with values and
// the elevation result is returned in the full 4x4 mesh.
D3DXMATRIX const allElevators[3] = {D3DXMATRIX(1.0f, 1.0f, 1.0f, 1.0f,
0.0f, 0.0f, 0.0f, 0.0f,
0.0f, 0.0f, 0.0f, 0.0f,
0.0f, 0.0f, 0.0f, 0.0f),
D3DXMATRIX(1.0f, 0.75f, 0.25f, 0.0f,
0.0f, 0.25f, 0.75f, 1.0f,
0.0f, 0.0f, 0.0f, 0.0f,
0.0f, 0.0f, 0.0f, 0.0f),
D3DXMATRIX(1.0f, 1.f/3.f, 0.0f, 0.0f,
0.0f, 2.f/3.f, 2.f/3.f, 0.0f,
0.0f, 0.0f, 1.f/3.f, 1.0f,
0.0f, 0.0f, 0.0f, 0.0f) };
D3DXMATRIX const *pElevator;
float const *pConstVec3Base;
float *pVec3Base;
int const kFloatsInVec = 3;
int i, j;
// elevate in x-direction first (since we are only applying linear equations,
// order don't matter)
if (uOrder < 4)
{
// determine elevation level (and transpose since D3DX uses row-vecs...)
pElevator = &allElevators[uOrder-1];
D3DXVECTOR3 row [kFloatsInVec];
D3DXVECTOR4 elevRow[kFloatsInVec];
for (i = 0; i < vOrder; ++i)
{
// copy the row of points to be elevated
pConstVec3Base = (float const *)(&(pControlMesh[4*i]));
for (j = 0; j < kFloatsInVec; ++j)
row[j] = D3DXVECTOR3( *(pConstVec3Base + j),
*(pConstVec3Base + kFloatsInVec + j),
*(pConstVec3Base + 2*kFloatsInVec + j));
// elevate
for (j = 0; j < kFloatsInVec; ++j)
D3DXVec3Transform(&(elevRow[j]), &(row[j]), pElevator);
// and write result back into pControlMesh
pVec3Base = (float *)(&(pControlMesh[4*i]));
for (j = 0; j < kFloatsInVec; ++j)
{
*(pVec3Base + j + 0*kFloatsInVec) = elevRow[j].x;
*(pVec3Base + j + 1*kFloatsInVec) = elevRow[j].y;
*(pVec3Base + j + 2*kFloatsInVec) = elevRow[j].z;
*(pVec3Base + j + 3*kFloatsInVec) = elevRow[j].w;
}
}
}
// we are now guaranteed that the first vOrder rows are fully populated
// now elevate the v-direction
if (vOrder < 4)
{
// determine elevation level (and transpose since D3DX uses row-vecs...)
pElevator = &allElevators[vOrder-1];
D3DXVECTOR3 column[kFloatsInVec];
D3DXVECTOR4 elevColumn[kFloatsInVec];
for (i = 0; i < 4; ++i)
{
// copy the column of points to be elevated
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -