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 + -
显示快捷键?