terrain.cpp
来自「x3d_new.rar」· C++ 代码 · 共 497 行 · 第 1/2 页
CPP
497 行
SVertexData* pVertices = NULL;
if(FAILED(rPatch.m_pVB->Lock(0, nPatchVertexCount, (LPVOID*)&pVertices, 0)))return E_FAIL;
// 开始设置法线顶点数据
int nIndex = 0;
int nNormalIndex = 0;
for(int iz = 0; iz < nPatchBorderSize; ++iz)
{
for(int ix = 0; ix < nPatchBorderSize; ++ix)
{
pNormalVertices[nNormalIndex].position = pVertices[nIndex].position;
pNormalVertices[nNormalIndex].diffuse = D3DCOLOR_ARGB(255, 0, 255, 0);
pNormalVertices[nNormalIndex + 1].position = pVertices[nIndex].position + pVertices[nIndex].normal;
pNormalVertices[nNormalIndex + 1].diffuse = D3DCOLOR_ARGB(128, 128, 128, 128);
nNormalIndex += 2;
nIndex += 1;
}
}
if(FAILED(rPatch.m_pVBNormal->Unlock()))return E_FAIL;
if(FAILED(rPatch.m_pVB->Unlock()))return E_FAIL;
}
}
return D3D_OK;
}
// 子节点所在片区对应的"米"字索引顶点
ERiceIgnore ri_child[4] = {RI_RB, RI_LB, RI_RT, RI_LT};
// 临节点对应的"米"字索引顶点
ERiceIgnore ri_neighbor[4] = {RI_LEFT, RI_TOP, RI_RIGHT, RI_BOTTOM};
HRESULT CTerrain::SetupIndexBuffer()
{
assert(m_pDevice);
assert(m_pDeviceCaps);
assert(m_field.IsValid());
DWORD dwTempIndices[24]; // 每个"块" 最多包含 8 * 3 = 24 个顶点索引
STile tileBegin;
STile tileMap;
int nTierCount = m_nSize / m_nPatchSize;
int nPatchBorderSize = m_nPatchSize + 1;
int nPatchVertexCount = nPatchBorderSize * nPatchBorderSize;
int nBytePerIndex = m_pDeviceCaps->MaxVertexIndex > 65536 ? 4 : 2;
for(int ipz = 0; ipz < nTierCount; ++ipz)
{
for(int ipx = 0; ipx < nTierCount; ++ipx)
{
SPatch& rPatch = m_Patchs[ipz * nTierCount + ipx];
rPatch.m_nIndexCount = 0; // 初始为0
// 得到地形块的所有Tile
STile* pTiles;
int nTileCount;
tileBegin.SetData(
ipx * m_nPatchSize + (m_nPatchSize >> 1),
ipz * m_nPatchSize + (m_nPatchSize >> 1), m_nPatchSize);
if(!m_field.GetPatchTiles(&tileBegin, &pTiles, &nTileCount))return false;
// 设置索引
assert(rPatch.m_pIB);
LPBYTE pIndices;
if(FAILED(rPatch.m_pIB->Lock(0, 0, (LPVOID*)&pIndices, 0)))return E_FAIL;
for(int i = 0; i < nTileCount; ++i)
{
unsigned int uTemplateIndex = 0;
const SQuarterData rQuarterData = m_field.GetQuarterData(pTiles[i].m_cx, pTiles[i].m_cz);
// ...子节点
if(rQuarterData.m_uFlag & (1 << 0)) uTemplateIndex |= ri_child[0]; // 0
if(rQuarterData.m_uFlag & (1 << 1)) uTemplateIndex |= ri_child[1]; // 1
if(rQuarterData.m_uFlag & (1 << 2)) uTemplateIndex |= ri_child[2]; // 2
if(rQuarterData.m_uFlag & (1 << 3)) uTemplateIndex |= ri_child[3]; // 3
// ...临节点
int nx, nz;
nx = pTiles[i].m_cx - pTiles[i].m_size;
nz = pTiles[i].m_cz;
if(m_field.IsPosInField(nx, nz))
{
if(m_field.GetQuarterData(nx, nz).m_uValue == 0) // 0
uTemplateIndex |= ri_neighbor[0];
}
nx = pTiles[i].m_cx;
nz = pTiles[i].m_cz - pTiles[i].m_size;
if(m_field.IsPosInField(nx, nz))
{
if(m_field.GetQuarterData(nx, nz).m_uValue == 0) // 1
uTemplateIndex |= ri_neighbor[1];
}
nx = pTiles[i].m_cx + pTiles[i].m_size;
nz = pTiles[i].m_cz;
if(m_field.IsPosInField(nx, nz))
{
if(m_field.GetQuarterData(nx, nz).m_uValue == 0) // 2
uTemplateIndex |= ri_neighbor[2];
}
nx = pTiles[i].m_cx;
nz = pTiles[i].m_cz + pTiles[i].m_size;
if(m_field.IsPosInField(nx, nz))
{
if(m_field.GetQuarterData(nx, nz).m_uValue == 0) // 3
uTemplateIndex |= ri_neighbor[3];
}
// 映射指定"块"的索引值
tileMap.SetData(
pTiles[i].m_cx - m_nPatchSize * ipx,
pTiles[i].m_cz - m_nPatchSize * ipz, pTiles[i].m_size);
MapIndices(dwTempIndices, &tileMap);
const SRiceIndicesTemplate* pTemplate = m_RiceIndicesMng.GetTemplate(uTemplateIndex);
// 写入索引
for(int iIndex = 0; iIndex < (pTemplate->m_nIndicesNum); ++iIndex)
{
LPBYTE pData = (LPBYTE)&dwTempIndices[pTemplate->m_pIndices[iIndex]];
memcpy(pIndices + rPatch.m_nIndexCount * nBytePerIndex, pData, nBytePerIndex);
++rPatch.m_nIndexCount;
}
}
if(FAILED(rPatch.m_pIB->Unlock()))return E_FAIL;
}
}
return D3D_OK;
}
void CTerrain::Render()
{
assert(m_pDevice);
int nBorderSize = m_field.GetBorderSize();
// 设置材质
m_pDevice->SetMaterial(&m_Material);
// 设置放大贴图过滤模式 - 线性
m_pDevice->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR);
m_pDevice->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR);
// 设置多重纹理,实现细节贴图
m_pDevice->SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_TEXTURE);
//m_pDevice->SetTextureStageState(0, D3DTSS_COLORARG2, D3DTA_DIFFUSE);
m_pDevice->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_SELECTARG1);
m_pDevice->SetTextureStageState(0, D3DTSS_TEXCOORDINDEX, 0);
m_pDevice->SetTexture(0, m_pTexture);
m_pDevice->SetTextureStageState(1, D3DTSS_COLORARG1, D3DTA_CURRENT);
m_pDevice->SetTextureStageState(1, D3DTSS_COLORARG2, D3DTA_TEXTURE);
m_pDevice->SetTextureStageState(1, D3DTSS_COLOROP, D3DTOP_ADDSIGNED);
m_pDevice->SetTextureStageState(1, D3DTSS_TEXCOORDINDEX, 1);
m_pDevice->SetTexture(1, m_pDetailTexture);
// 绘制
m_pDevice->SetRenderState(D3DRS_FILLMODE, GetFillMode());
m_pDevice->SetFVF(SVertexData::FVF);
int nPatchBorderSize = m_nPatchSize + 1;
int nPatchVertexCount = nPatchBorderSize * nPatchBorderSize;
int nTierCount = m_nSize / m_nPatchSize;
int nPatchCount = nTierCount * nTierCount;
for(int i = 0; i < nPatchCount; ++i)
{
SPatch& rPatch = m_Patchs[i];
m_pDevice->SetStreamSource(0, rPatch.m_pVB, 0, sizeof(SVertexData));
m_pDevice->SetIndices(rPatch.m_pIB);
m_pDevice->DrawIndexedPrimitive(D3DPT_TRIANGLELIST, 0, 0, nPatchVertexCount, 0, rPatch.m_nIndexCount / 3);
}
// 绘制法线?
if(m_bDrawNormal)
{
for(int i = 0; i < nPatchCount; ++i)
{
SPatch& rPatch = m_Patchs[i];
m_pDevice->SetTexture(0, NULL);
m_pDevice->SetRenderState(D3DRS_FILLMODE, D3DFILL_SOLID);
m_pDevice->SetStreamSource(0, rPatch.m_pVBNormal, 0, sizeof(SNormalVertexData));
m_pDevice->SetFVF(SNormalVertexData::FVF);
m_pDevice->DrawPrimitive(D3DPT_LINELIST, 0, nPatchBorderSize * nPatchBorderSize);
}
}
}
void CTerrain::RandomHeight(float fRoughness /*= 0.5f*/, float fSlab /*= 0.5f*/, int nBlur /*= 2*/)
{
// 随机生成高度数据
m_field.RandomHeight(fRoughness, fSlab, nBlur);
// 创建模型
SetupGeometry();
// 创建法线模型
//SetupNormalGeometry();
// 创建纹理
assert(m_pTexture);
m_TexturePainter.PaintTexture(&m_pTexture);
}
void CTerrain::UpdateDetail(CCamera* pCamera, int nEyeshot)
{
assert(m_field.IsValid());
// 更新细节程度
// 注意:1.由于地形的高度并不是原始的高度数据,所以这里要对摄像机的位置进行调整
// 2.划分的最大"块"尺寸应小于或等于片区尺寸
CCamera cameraTemp = *pCamera;
cameraTemp.GetPosition()->y /= m_fHeightScale;
m_field.UpdateQuarters(&cameraTemp, nEyeshot, m_nPatchSize);
// 更新索引
SetupIndexBuffer();
}
void CTerrain::MapIndices(LPDWORD pOut, const STile* pTile)
{
int nPatchBorderSize = m_nPatchSize + 1;
/*0*/ *(pOut++) = pTile->m_cz * nPatchBorderSize + pTile->m_cx;
/*1*/ *(pOut++) = *(pOut - 1) + (pTile->m_size >> 1);
/*2*/ *(pOut++) = *(pOut - 1) - nPatchBorderSize * (pTile->m_size >> 1);
/*3*/ *(pOut++) = *(pOut - 1) - (pTile->m_size >> 1);
/*4*/ *(pOut++) = *(pOut - 1) - (pTile->m_size >> 1);
/*5*/ *(pOut++) = *(pOut - 1) + nPatchBorderSize * (pTile->m_size >> 1);
/*6*/ *(pOut++) = *(pOut - 1) + nPatchBorderSize * (pTile->m_size >> 1);
/*7*/ *(pOut++) = *(pOut - 1) + (pTile->m_size >> 1);
/*8*/ *(pOut++) = *(pOut - 1) + (pTile->m_size >> 1);
}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?