#include "StdAfx.h" #ifndef CODE_INGAME #include "TerrainModifier.h" #include "Terrain.h" #include "TerrainChangeVertexCommand.h" #include "TerrainTextureMgr.h" //#include "Opcode.h" #include #include #include #include "Utility.h" // 静态成员初始化 bool CTerrainModifier::m_bPaintTexture = true; bool CTerrainModifier::m_bPaintVertexColor = false; // add [11/25/2009 hemeng] bool CTerrainModifier::m_bPaintWaterScene = false; // [11/25/2009 hemeng] NiColorA CTerrainModifier::m_kInUseVertexColor = NiColorA::WHITE; NiSourceTexture* CTerrainModifier::m_pkBrushTexture = NULL; CTerrainModifier::ETerrainOperation CTerrainModifier::m_TerrainOperation = TO_FLAT; bool CTerrainModifier::m_bPaintAddTo = true; int CTerrainModifier::m_iOnEditProperty = 0; int CTerrainModifier::m_iStartX = -1; int CTerrainModifier::m_iStartY = -1; int CTerrainModifier::m_iEndX = -1; int CTerrainModifier::m_iEndY = -1; /** *
功能说明:2D平面内判断一个圆与正四边形相交(在此包含也属相交) *
可访问性:global *
注 释: * @param vCenter[in] 圆心 * @param fRadius[in] 半径 * @param vMin[in] 左下点 * @param vMax[in] 右上点 * @return 无 */ static bool CircleInteracrossRectangle( const NiPoint2& vPoint, float fRadius, const NiPoint2& vMin, const NiPoint2& vMax ) { /* D|------|C | | |______| A B */ NiPoint2 A = NiPoint2( vMin.x, vMin.y ); NiPoint2 B = NiPoint2( vMax.x, vMin.y ); NiPoint2 C = NiPoint2( vMin.x, vMax.y ); NiPoint2 D = NiPoint2( vMax.x, vMax.y ); float r = fRadius; float fAB = fabs( vMax.x - vMin.x ); float fAD = fabs( vMax.y - vMin.y ); float fDist_x = fabs( vPoint.x - ( vMin.x+vMax.x)*0.5f ); float fDist_y = fabs( vPoint.y - ( vMin.y+vMax.y)*0.5f ); if ( fDist_x >= ( fAB*0.5 + r ) || fDist_y >= ( fAD/2 + r ) ) return false; else { if ( fDist_x < fAB*0.5f || fDist_y < fAD * 0.5f ) return true; fDist_x -= fAB*0.5f; fDist_y -= fAD*0.5f; if ( (fDist_x*fDist_x + fDist_y*fDist_y) >= (r*r) ) return false; return true; } } HANDLE CTerrainModifier::m_hThread = NULL; HANDLE CTerrainModifier::m_hEvent = NULL; bool CTerrainModifier::m_bNeedThread = false; CTerrainModifier::stPaintThreadBlock CTerrainModifier::m_stPaintThreadBlock( 0, 0, 0, 0, 0, 0, NiPoint2(0,0), 0, 0, 0, false ); /// 线程函数 DWORD CTerrainModifier::ThreadProc( LPVOID lpParam ) { while ( TRUE ) { //CTerrainModifier* pTerrainModifier = (CTerrainModifier*) lpParam; if( CTerrainModifier::NeedThreadDisposal() ) { CTerrainModifier::Disposal(); } } } void CTerrainModifier::SetThreadDisposal( bool bSignal ) { m_bNeedThread = bSignal; m_bNeedThread ? ResetEvent( m_hEvent ) : SetEvent( m_hEvent ); } void CTerrainModifier::Disposal() { _DoPainting( m_stPaintThreadBlock.pTerrain, m_stPaintThreadBlock.pPixelData, m_stPaintThreadBlock.iYFrom, m_stPaintThreadBlock.iYTo, m_stPaintThreadBlock.iXFrom, m_stPaintThreadBlock.iXTo, m_stPaintThreadBlock.ptCenter, m_stPaintThreadBlock.fr, m_stPaintThreadBlock.fR, m_stPaintThreadBlock.fAlpha, m_stPaintThreadBlock.bAddTo ); SetThreadDisposal( false ); } CTerrainModifier::CTerrainModifier() {} CTerrainModifier::~CTerrainModifier(void) {} bool CTerrainModifier::Initialize() { //m_hThread = CreateThread( NULL, 0, (LPTHREAD_START_ROUTINE)ThreadProc, 0, 0, 0 ); //m_hEvent = CreateEvent( 0, 0, 0, 0 ); //return (( m_hThread != NULL ) && ( m_hEvent != NULL )); return true; } void CTerrainModifier::UnInitialize() { if ( m_hThread ) { DWORD dwExitCode; TerminateThread( m_hThread, GetExitCodeThread( m_hThread , &dwExitCode ) ); CloseHandle( m_hThread ); } if ( m_hEvent ) CloseHandle( m_hEvent ); } void CTerrainModifier::AdjustHeight( CTerrain *pTerrain, const NiPoint3& vPos, float fHeight, float fRadius0, float fRadius1, bool bAddTo, CTerrainChangeVertexCommand* pCommand ) { assert( fRadius1 >= fRadius0 ); // 外圈大于内圈 // 获得点击位置的Grid索引 int iGridIndx = pTerrain->GetGridIndex( vPos ); if ( iGridIndx == INVALID_GRID ) return; // 获得该索引位置范围为fRadius1的所有Grid索引 set< int > gridset; pTerrain->GetGridArray( iGridIndx, (WORD)(ceil(fRadius1)), gridset ); // 将这些Grid包含的顶点置入vertexSet set vertexSet; set::iterator it = gridset.begin(); for ( ;it != gridset.end(); ++it ) { for ( int n = 0; n < 4; ++n ) { vertexSet.insert( pTerrain->m_pGrids[ *it ].iPointIndx[n] ); } } ////////////////////////////////////////////////////////////////////////// /// 斜坡地形 bool bMakeIncline = false; map mpIncline; if (m_iStartX != -1 && m_iStartY != -1) { if (m_iEndX != -1 && m_iEndY != -1) { vector vertexOnLine; vector vertexNewHeight; /*pTerrain->GetVerticesInLine(m_iStartX, m_iStartY, m_iEndX, m_iEndY, vertexOnLine, vertexNewHeight); pTerrain->GetVerticesInLine(m_iStartX+1, m_iStartY, m_iEndX+1, m_iEndY, vertexOnLine, vertexNewHeight); pTerrain->GetVerticesInLine(m_iStartX+2, m_iStartY, m_iEndX+2, m_iEndY, vertexOnLine, vertexNewHeight); pTerrain->GetVerticesInLine(m_iStartX+3, m_iStartY, m_iEndX+3, m_iEndY, vertexOnLine, vertexNewHeight); pTerrain->GetVerticesInLine(m_iStartX+4, m_iStartY, m_iEndX+4, m_iEndY, vertexOnLine, vertexNewHeight);*/ pTerrain->MakeIncline(m_iStartX, m_iStartY, m_iEndX, m_iEndY, fRadius1, vertexOnLine, vertexNewHeight); bMakeIncline = true; vertexSet.clear(); vector::iterator itVertex = vertexOnLine.begin(); vector::iterator itHeight = vertexNewHeight.begin(); for (;itVertex != vertexOnLine.end();) { vertexSet.insert(*itVertex); mpIncline[*itVertex] = *itHeight; itVertex++; itHeight++; } m_iStartX = -1; m_iStartY = -1; m_iEndX = -1; m_iEndY = -1; CTerrainModifier::SetMousePos(m_iStartX, m_iStartY, m_iEndX, m_iEndY); } } ////////////////////////////////////////////////////////////////////////// // 顶点平均高度,用于 smooth /*屏蔽原有函数by kblee float fAvgHeight = 0.0f; if (m_TerrainOperation == TO_SMOOTH) { for ( it = vertexSet.begin(); it != vertexSet.end(); ++it ) { fAvgHeight += pTerrain->m_pVertices[*it].z; } fAvgHeight /= vertexSet.size(); } */ bool bLShiftDown = KEY_DOWN(VK_LSHIFT); // 依次改变顶点位置 set chunkset; for ( it = vertexSet.begin(); it != vertexSet.end(); ++it ) { NiPoint3& pt = pTerrain->m_pVertices[*it]; NiPoint2 vDis = NiPoint2( pt.x - vPos.x, pt.y - vPos.y ); float fLength = vDis.Length(); if ( fLength > fRadius1 && !bMakeIncline) { continue; } // 记录顶点的变化,用于 undo/redo tVertexChange vertChange; vertChange.iIndex = (*it); vertChange.fOldHeight = pt.z; float f = 0.0f; // 顶点到内圈的比率 0~1 if ( fLength >= fRadius0 ) { f = (fLength-fRadius0 )/(fRadius1 - fRadius0); } float fBrushForce = ( NiSin( NI_PI*(1.0-f)*0.5f)); // 该位置上笔触力度 if ( m_TerrainOperation == TO_UPPER ) { // 用 fHeight 当作力度 if (!bLShiftDown) { pt.z += abs(fHeight*0.1f) * fBrushForce; } else { pt.z -= abs(fHeight*0.1f) * fBrushForce; } } else if (m_TerrainOperation == TO_FALL ) { if (!bLShiftDown) { pt.z -= abs(fHeight*0.1f) * fBrushForce; } else { pt.z += abs(fHeight*0.1f) * fBrushForce; } } else if (m_TerrainOperation == TO_FLAT ) { float fOffset = ( fHeight - pt.z ) * fBrushForce; pt.z += fOffset; } else if(m_TerrainOperation == TO_SMOOTH) { if (bMakeIncline) { pt.z = mpIncline.find(*it)->second; } else { float fAverageHeight = 0.0f; //平均高度 float fI,fJ; int iCount = 0; for ( fI = 0.0f; fI < COLLISION_DATA_OFFSET*3; fI += COLLISION_DATA_OFFSET ) { for ( fJ = 0.0f; fJ < COLLISION_DATA_OFFSET*3; fJ += COLLISION_DATA_OFFSET ) { NiPoint2 tmpPt = NiPoint2( pt.x+fJ ,pt.y+fI ); fAverageHeight += pTerrain->GetHeight( tmpPt ); } } fAverageHeight /= 9.0f; float fDifference = fAverageHeight - pt.z; // 当前高度与平均高度差值 if ( fHeight < 1.0f )//高度(力度)小于1.0f时设置为1.0f,否则无变化 { fHeight = 1.0f; } pt.z += ( fHeight * 0.01f * fDifference );//这时把高度当作力度来使用 } /*屏蔽原有函数by kblee if (bMakeIncline) { pt.z = mpIncline.find(*it)->second; } else { float fDifference = fAvgHeight - pt.z; // 当前高度与平均高度差值 float fForce = abs(fHeight*0.1f) * fBrushForce; pt.z += (fForce * fDifference); } */ } vertChange.fNewHeight = pt.z; if (NULL != pCommand) { pCommand->AddVertexChange(vertChange); } // 获取该点所在的chunk索引, 预准备发改变通知 int iChunkIndx = pTerrain->GetChunkIndex( pt ); chunkset.insert( iChunkIndx ); if (NULL != pCommand) { pCommand->AddChangedChunk(iChunkIndx); } } // 依次改变顶点的法线, 必须在所有顶点位置改变后完成, 否则可能导致计算无效 for ( it = vertexSet.begin(); it != vertexSet.end(); ++it ) { NiPoint3& n = pTerrain->m_pNormals[*it]; n = CalculateNormal( pTerrain, *it ); //LOG3( "Normal is %.2f, %.2f, %.2f \n", n.x, n.y, n.z ); } // 通知Chunks顶点改变 for ( it = chunkset.begin(); it != chunkset.end(); ++it ) { NotifyChunkVertexChanged( pTerrain, *it ); } pTerrain->SetLastChangedChunk(pTerrain->GetChunkIndex(vPos)); } bool CTerrainModifier::SetBaseTexture( CTerrain *pTerrain, const char *pszBaseText ) { int iChunkNum = pTerrain->m_iChunkNumX * pTerrain->m_iChunkNumY; for ( int i = 0; i < iChunkNum; ++i ) { bool bAddLayer = false; if ( !pTerrain->m_pChunks[i].pChunkMtl->SetTexture( string( pszBaseText ), bAddLayer ) ) return false; } return true; } //bool CTerrainModifier::SetTexture( CTerrain *pTerrain, const char *pszTex, const NiPoint3& vPos, float fAlpha, float fRadius0, float fRadius1, bool bAddTo ) //{ // if ( !pTerrain ) return false; // // // 无纹理或alpha值为0均不处理 // if ( pszTex == 0 || fAlpha <= .0f ) return false; // // // 遍历所有影响到的Chunks // vector vAffectedChunks = _GetAffectedChunks( pTerrain, vPos, fRadius1 ); // if ( vAffectedChunks.size() <= 0 ) return false; // // for ( size_t i = 0; i < vAffectedChunks.size(); ++i ) // { // int n = vAffectedChunks.at( i ); // CTerrainMaterial *pTerrainMtl = pTerrain->m_pChunks[n].pChunkMtl; // int iOldMtlCount = pTerrainMtl->GetUsedLayerCount(); // // 增加纹理 // if ( pTerrainMtl->SetTexture( string( pszTex ) ) ) // { // int iCurMtlCount = pTerrainMtl->GetUsedLayerCount(); // // // 增设shader纹理 // if ( iCurMtlCount != iOldMtlCount ) // { // assert( iCurMtlCount == (iOldMtlCount+1) ); // // NiTexturingProperty* pTexProp = ( NiTexturingProperty * ) // pTerrain->m_pChunks[n].geomData.pTriShape->GetProperty( NiProperty::TEXTURING ); // // NiTexturingProperty::ShaderMap *pShaderMap = NiNew NiTexturingProperty::ShaderMap( // pTerrainMtl->GetTexture( iOldMtlCount ), iOldMtlCount ); // // pTexProp->SetShaderMap( iOldMtlCount, pShaderMap ); // } // } // } // // _Painting( pTerrain, vPos, fAlpha, fRadius0, fRadius1, bAddTo ); // // return true; //} bool CTerrainModifier::PaintTerrain( CTerrain *pTerrain, const char *pszTex, const NiPoint3& vPos, float fAlpha, float fRadius0, float fRadius1, bool bAddTo ) { // modify [11/25/2009 hemeng] if (m_bPaintWaterScene) { _PaintingVertexColor(pTerrain, vPos, fAlpha, fRadius0, fRadius1, true); } else { // 绘制地表纹理 if (strlen(pszTex)>0 && m_bPaintTexture) { // 无纹理或alpha值为0均不处理 if ( pszTex == 0 ) return false; // || fAlpha < .0f 支持 fAlpha 小于 0, 认为是纹理的渐进减弱 bool bResult = true; // 遍历所有影响到的Chunks vector vAffectedChunks = _GetAffectedChunks( pTerrain, vPos, fRadius1 ); for ( size_t i = 0; i < vAffectedChunks.size(); ++i ) { int n = vAffectedChunks.at( i ); CTerrainMaterial *pTerrainMtl = pTerrain->m_pChunks[n].pChunkMtl; int iOldLayer = pTerrainMtl->GetInUseLayer(); bool bAddLayer = false; int iCurLayer = pTerrainMtl->SetTexture( string( pszTex ), bAddLayer); if (iCurLayer < 0) { return false; } // 改变BlendTexture _Painting( pTerrain, n, EPaintChannel(iCurLayer+1), vPos, fAlpha, fRadius0, fRadius1, m_bPaintAddTo ); // 增加纹理 if ( bAddLayer ) { // 增设shader纹理 //assert( iCurMtlCount == (iOldMtlCount + 1) ); NiTexturingProperty* pTexProp = ( NiTexturingProperty * ) pTerrain->m_pChunks[n].geomData.pTriShape->GetProperty( NiProperty::TEXTURING ); NiTexturingProperty::ShaderMap *pShaderMap = NiNew NiTexturingProperty::ShaderMap( pTerrain->m_pChunks[n].pChunkMtl->GetTexture( iCurLayer ), iCurLayer); pTexProp->SetShaderMap( iCurLayer, pShaderMap ); } } } // 绘制顶点颜色 if (m_bPaintVertexColor) { _PaintingVertexColor(pTerrain, vPos, fAlpha, fRadius0, fRadius1, false); } } pTerrain->SetLastChangedChunk(pTerrain->GetChunkIndex(vPos)); return true; } // //void CTerrainModifier::_SetCollisionData( CTerrain *pTerrain, const set& gridSet, bool bSignal ) //{ // set::const_iterator iter = gridSet.begin(); // for ( ; iter != gridSet.end(); ++iter ) // { // // 逻辑设置 // CTerrain::stGrid& grid = pTerrain->m_pGrids[ *iter ]; // grid.iBlocked = bSignal; // // // 显示设置 // NiPoint3 vLeftBtm = pTerrain->m_pVertices[ grid.iPointIndx[0] ]; // NiPoint3 vRightTop = pTerrain->m_pVertices[ grid.iPointIndx[2]]; // // int iChunkIndx = pTerrain->GetChunkIndex( ( vLeftBtm+vRightTop) * 0.5f ); // CTerrain::stChunk& chunk = pTerrain->m_pChunks[iChunkIndx]; // CTerrainMaterial *pMtl = chunk.pChunkMtl; // // int iSize = pMtl->GetBlendTexSize(); // // float fLeft = iSize * ( vLeftBtm.x - chunk.vPosMin.x ) / ( chunk.vPosMax.x - chunk.vPosMin.x ); // float fRight = iSize * ( vRightTop.x - chunk.vPosMin.x ) / ( chunk.vPosMax.x - chunk.vPosMin.x ); // float fBtm = iSize * ( vLeftBtm.y - chunk.vPosMin.y ) / ( chunk.vPosMax.y - chunk.vPosMin.y ); // float fTop = iSize * ( vRightTop.y - chunk.vPosMin.y ) / ( chunk.vPosMax.y - chunk.vPosMin.y ); // // pMtl->SetCollisionDataA( NiRect( fLeft, fRight, fTop, fBtm ), bSignal ); // } //} //void CTerrainModifier::SetCollisionData( CTerrain *pTerrain, const NiPoint3& vPos, float fRadius, bool bSignal ) //{ // set gridset, gridsetfilter; // int iGrid = pTerrain->GetGridIndex( vPos ); // if ( iGrid == INVALID_GRID ) return; // // WORD usOffset = WORD( fRadius / EDIT_UNIT + 1 ); // pTerrain->GetGridArray( iGrid, usOffset, gridset ); // // set::const_iterator iter = gridset.begin(); // for ( ; iter != gridset.end(); ++iter ) // { // CTerrain::stGrid& grid = pTerrain->m_pGrids[ *iter ]; // // int index0 = grid.iPointIndx[0]; // int index2 = grid.iPointIndx[2]; // // NiPoint3& vPos0 = pTerrain->m_pVertices[index0]; // NiPoint3& vPos2 = pTerrain->m_pVertices[index2]; // // NiPoint3 vCenterPos = ( vPos0 + vPos2 ) * 0.5f; // NiPoint2 vDist = NiPoint2( vCenterPos.x - vPos.x, vCenterPos.y - vPos.y ); // float fLen = vDist.Length(); // // if ( fLen < fRadius ) // gridsetfilter.insert( *iter ); // } // // _SetCollisionData( pTerrain, gridsetfilter, bSignal ); //} void CTerrainModifier::SetTerrainSurfaceProperty( CTerrain *pTerrain, const NiPoint3& vPos, float fRadius,bool bDelete, int iProperty ) { if (iProperty == -1) { iProperty = m_iOnEditProperty; } set gridset, gridsetfilter; int iGrid = pTerrain->GetGridIndex( vPos ); if ( iGrid == INVALID_GRID ) return; WORD usOffset = WORD( fRadius / EDIT_UNIT + 1 ); pTerrain->GetGridArray( iGrid, usOffset, gridset ); set::const_iterator iter = gridset.begin(); for ( ; iter != gridset.end(); ++iter ) { CTerrain::stGrid& grid = pTerrain->m_pGrids[ *iter ]; int index0 = grid.iPointIndx[0]; int index2 = grid.iPointIndx[2]; NiPoint3& vPos0 = pTerrain->m_pVertices[index0]; NiPoint3& vPos2 = pTerrain->m_pVertices[index2]; NiPoint3 vCenterPos = ( vPos0 + vPos2 ) * 0.5f; NiPoint2 vDist = NiPoint2( vCenterPos.x - vPos.x, vCenterPos.y - vPos.y ); float fLen = vDist.Length(); if ( fLen < fRadius ) gridsetfilter.insert( *iter ); } _SetTerrainSurfaceProperty( pTerrain, gridsetfilter, iProperty, bDelete ); } void CTerrainModifier::_SetTerrainSurfaceProperty( CTerrain *pTerrain, const set& gridSet, int iProperty, bool bDelete ) { set::const_iterator iter = gridSet.begin(); for ( ; iter != gridSet.end(); ++iter ) { // 逻辑设置 CTerrain::stGrid& grid = pTerrain->m_pGrids[ *iter ]; int iCurrTerrainProperty = 0; CopyLowFourBit(iCurrTerrainProperty,grid.iTerrainProperty); //如果不是删除模式,且当前地形的属性为BLOCK则跳过 if ( iCurrTerrainProperty == 1 && !bDelete ) { continue; } if (bDelete) { if ( iCurrTerrainProperty != iProperty ) { continue; } else { CopyLowFourBit(grid.iTerrainProperty, 0 ); } } else { // 拷贝低4位 CopyLowFourBit(grid.iTerrainProperty, iProperty); } // 显示设置 NiPoint3 vLeftBtm = pTerrain->m_pVertices[ grid.iPointIndx[0] ]; NiPoint3 vRightTop = pTerrain->m_pVertices[ grid.iPointIndx[2]]; int iChunkIndx = pTerrain->GetChunkIndex( ( vLeftBtm+vRightTop) * 0.5f ); CTerrain::stChunk& chunk = pTerrain->m_pChunks[iChunkIndx]; CTerrainMaterial *pMtl = chunk.pChunkMtl; int iSize = pMtl->GetBlendTexSize(); float fLeft = iSize * ( vLeftBtm.x - chunk.vPosMin.x ) / ( chunk.vPosMax.x - chunk.vPosMin.x ); float fRight = iSize * ( vRightTop.x - chunk.vPosMin.x ) / ( chunk.vPosMax.x - chunk.vPosMin.x ); float fBtm = iSize * ( vLeftBtm.y - chunk.vPosMin.y ) / ( chunk.vPosMax.y - chunk.vPosMin.y ); float fTop = iSize * ( vRightTop.y - chunk.vPosMin.y ) / ( chunk.vPosMax.y - chunk.vPosMin.y ); pMtl->SetTerrainPropertyA( NiRect( fLeft, fRight, fTop, fBtm ), grid.iTerrainProperty/*iProperty */); } } /// 设置当前需要显示的 property void CTerrainModifier::SetCurrentTerrainProperty( CTerrain *pTerrain, int iProperty) { if (iProperty<0) { return; } m_iOnEditProperty = iProperty; //// 遍历所有的 grid //int iGridX = pTerrain->GetChunkNumX() * GRIDINCHUNK; //int iGridY = pTerrain->GetChunkNumY() * GRIDINCHUNK; //const CTerrain::stGrid* pGrids = pTerrain->GetGrids(); //for (int i=0; im_pVertices[ pGrids[i].iPointIndx[0] ]; // NiPoint3 vRightTop = pTerrain->m_pVertices[ pGrids[i].iPointIndx[2]]; // int iChunkIndx = pTerrain->GetChunkIndex( ( vLeftBtm+vRightTop) * 0.5f ); // CTerrain::stChunk& chunk = pTerrain->m_pChunks[iChunkIndx]; // CTerrainMaterial *pMtl = chunk.pChunkMtl; // int iSize = pMtl->GetBlendTexSize(); // float fLeft = iSize * ( vLeftBtm.x - chunk.vPosMin.x ) / ( chunk.vPosMax.x - chunk.vPosMin.x ); // float fRight = iSize * ( vRightTop.x - chunk.vPosMin.x ) / ( chunk.vPosMax.x - chunk.vPosMin.x ); // float fBtm = iSize * ( vLeftBtm.y - chunk.vPosMin.y ) / ( chunk.vPosMax.y - chunk.vPosMin.y ); // float fTop = iSize * ( vRightTop.y - chunk.vPosMin.y ) / ( chunk.vPosMax.y - chunk.vPosMin.y ); // pMtl->SetTerrainPropertyA( NiRect( fLeft, fRight, fTop, fBtm ), iProperty ); // } //} } void CTerrainModifier::Smooth( CTerrain *pTerrain, float fRadius, float fPower ) {} void CTerrainModifier::CalculateAllNormals( CTerrain *pTerrain ) { int index = 0; for ( int i = 0; i < pTerrain->m_iVertexY; ++i ) { for ( int j = 0; j < pTerrain->m_iVertexX; ++j ) { NiPoint3& n = pTerrain->m_pNormals[index]; n = CalculateNormal( pTerrain, index ); index++; } } index = 0; for ( int i = 0; i < pTerrain->m_iChunkNumY; ++i ) { for ( int j = 0; j < pTerrain->m_iChunkNumX; ++j ) { NotifyChunkVertexChanged( pTerrain, index ); index++; } } } //////////////////////////////////////////////////////////////////////////// //void CTerrainModifier::_Painting( CTerrain *pTerrain, const NiPoint3& vPos, float fAlpha, float fRadius0, float fRadius1, bool bAddTo ) //{ // // 比例位置 // float fx = vPos.x / (float)pTerrain->m_iTotalX; // float fy = vPos.y / (float)pTerrain->m_iTotalY; // NiPoint2 vPos2D = NiPoint2( fx*BLEND_TEX_SIZE, fy*BLEND_TEX_SIZE ); // // // 比例半径 // float fr = fRadius0 * BLEND_TEX_SIZE / max( pTerrain->m_iTotalX, pTerrain->m_iTotalY ); // float fR = fRadius1 * BLEND_TEX_SIZE / max( pTerrain->m_iTotalX, pTerrain->m_iTotalY ); // // int iXFrom = max( (int)floor( vPos2D.x - fR ), 0 ); // int iXTo = min( (int)ceil( vPos2D.x + fR), BLEND_TEX_SIZE-1 ); // int iYFrom = max( (int)floor( vPos2D.y - fR ), 0 ); // int iYTo = min( (int)ceil( vPos2D.y + fR ), BLEND_TEX_SIZE-1 ); // // NiPixelData *pPixelData = pTerrain->m_spBlendTexture->GetSourcePixelData(); // assert( pPixelData ); // // //#pragma omp parallel for private(pPtr[iChannel]) // int iYToHalf = ( iYTo + iYFrom ) >> 1; // // LOG( "Painting Start\n" ); // m_stPaintThreadBlock = stPaintThreadBlock( pTerrain, pPixelData, iYFrom, iYToHalf, iXFrom, iXTo, vPos2D, fr, fR, fAlpha, bAddTo ); // SetThreadDisposal( true ); // _DoPainting( pTerrain, pPixelData, iYToHalf, iYTo, iXFrom, iXTo, vPos2D, fr, fR, fAlpha, bAddTo ); // LOG( "Painting main end\n" ); // WaitForSingleObject( m_hEvent, INFINITE ); // LOG( "Painting End\n\n") // // pPixelData->MarkAsChanged(); //} void CTerrainModifier::_Painting( CTerrain *pTerrain, int iChunkIndx, EPaintChannel eChannel, const NiPoint3& vPos, float fAlpha, float fRadius0, float fRadius1, bool bAddTo ) { //assert( vPos.x >= pChunk->vPosMin.x && vPos.x <= pChunk->vPosMax.x ); //assert( vPos.y >= pChunk->vPosMin.y && vPos.y <= pChunk->vPosMax.y ); CTerrain::stChunk *pChunk = &( pTerrain->m_pChunks[iChunkIndx] ); int iWidth = pChunk->pChunkMtl->GetBlendTexSize(); // 比例位置 float fx = ( vPos.x - pChunk->vPosMin.x ) / ( pChunk->vPosMax.x - pChunk->vPosMin.x ); float fy = ( vPos.y - pChunk->vPosMin.y ) / ( pChunk->vPosMax.y - pChunk->vPosMin.y ); NiPoint2 vPos2D = NiPoint2( fx * iWidth, fy * iWidth ); // 比例半径 float fRadius0_ = fRadius0 * iWidth / ( pChunk->vPosMax.x - pChunk->vPosMin.x ); float fRadius1_ = fRadius1 * iWidth / ( pChunk->vPosMax.y - pChunk->vPosMin.y ); switch( eChannel ) { case PAINT_R: pChunk->pChunkMtl->SetBlendDataR( vPos2D, fAlpha, fRadius0_, fRadius1_, bAddTo, m_pkBrushTexture); break; case PAINT_G: pChunk->pChunkMtl->SetBlendDataG( vPos2D, fAlpha, fRadius0_, fRadius1_, bAddTo, m_pkBrushTexture); break; case PAINT_B: pChunk->pChunkMtl->SetBlendDataB( vPos2D, fAlpha, fRadius0_, fRadius1_, bAddTo, m_pkBrushTexture); break; default: break; } return; } // 函数作废 void CTerrainModifier::_DoPainting( CTerrain *pTerrain, NiPixelData *pPixelData, int iYFrom, int iYTo, int iXFrom, int iXTo, const NiPoint2& vPos2D, float fr, float fR, float fAlpha, bool bAddTo ) { //if ( nMtlCount == 2 ) iChannel = 2; // R通道 //else if ( nMtlCount == 3 ) iChannel = 1; // G通道 //else if ( nMtlCount == 4 ) iChannel = 0; // B通道 //// 通道索引表 //int iIndexTable[5] = { 0, 0, 2, 1, 0 }; //for( int y = iYFrom; y < iYTo; ++y ) //{ // for ( int x = iXFrom; x < iXTo; ++x ) // { // NiPoint2 vDis = NiPoint2( x - vPos2D.x, y - vPos2D.y ); // float fLength = vDis.Length(); // if ( fLength > fR ) {} // else // { // // 自动识别通道 // int iChannel = 0; // int iChunkIndx = _GetPixelLocationChunk( pTerrain, NiPoint2( float(x), float(y)) ); // int nMtlCount = pTerrain->m_pChunks[iChunkIndx].pChunkMtl->GetUsedLayerCount(); // iChannel = iIndexTable[ nMtlCount ]; // float fVal = fAlpha * 255.0f; // unsigned char* pPtr = (*pPixelData)( x, y ); // if ( fLength <= fr ) // 内半径 // { // //pPtr[iChannel] = ( bAddTo ) ? min( (unsigned char)(pPtr[iChannel]+fVal), 255 ): (unsigned char)fVal; // float fV = pPtr[iChannel]+fVal; // fV = min( fV, 255.0f ); // pPtr[iChannel] = ( bAddTo ) ? unsigned char(fV) : (unsigned char)fVal; // } // else if ( fLength <= fR ) // 外半径 // { // float f = 1-(fLength-fr )/(fR - fr); // if ( bAddTo ) // { // float fOffset = fVal * f; // //pPtr[iChannel] = min( (pPtr[iChannel]+ fVal_), 255 ); // float fV = pPtr[iChannel]+ fOffset; // fV = min( fV, 255.0f ); // pPtr[iChannel] = unsigned char (fV); // } // else // { // float fOffset = ( fVal - pPtr[iChannel] ) * f; // //pPtr[iChannel] = min( 255, ( unsigned char )( pPtr[iChannel]+fOffset ) ); // float fV = pPtr[iChannel]+ fOffset; // fV = min( fV, 255.0f ); // pPtr[iChannel] = unsigned char( fV ); // } // } // } // } //} } void CTerrainModifier::_PaintingVertexColor(CTerrain *pTerrain, const NiPoint3& vPos, float fAlpha, float fRadius0, float fRadius1, bool bPaintWater ) { if (fAlpha < .0f && !m_bPaintWaterScene) return; NiPixelData *pBrushPixelData = NULL; int iBrushTexWidth = 0; int iBrushTexHeight = 0; if (m_pkBrushTexture != NULL) { pBrushPixelData = m_pkBrushTexture->GetSourcePixelData(); iBrushTexWidth = m_pkBrushTexture->GetWidth(); iBrushTexHeight = m_pkBrushTexture->GetHeight(); assert( pBrushPixelData ); } NiPoint2 kTransVector(-(vPos.x-fRadius1), -(vPos.y-fRadius1)); // 从 世界 坐标变换到 brush texture 坐标的变换向量 // 找到所有影响到的Chunks vector vAffectedChunks = _GetAffectedChunks( pTerrain, vPos, fRadius1 ); NiPoint2 kTotalSize = pTerrain->GetTotalSize(); // 地形总尺寸 int iVertexPerRow = pTerrain->GetChunkNumX()*GRIDINCHUNK+1; // 遍历所有被影响的顶点 // 找到四边界 int iLeft = (vPos.x-fRadius1)>0 ? (vPos.x-fRadius1)/EDIT_UNIT : 0; int iRight = (vPos.x+fRadius1)0 ? (vPos.y-fRadius1)/EDIT_UNIT : 0; int iUp = (vPos.y+fRadius1)GetVertex(iIndex); NiPoint2 vDis = NiPoint2( kVertPos.x - vPos.x, kVertPos.y - vPos.y ); float fLength = vDis.Length(); if (fLength>fRadius1) { continue; } float fBrushTextureAlpah = 1.0f; if (m_pkBrushTexture != NULL) { int iBrushTexX = (float)(kVertPos.x+kTransVector.x)/(fRadius1*2)*iBrushTexWidth; int iBrushTexY = (float)(kVertPos.y+kTransVector.y)/(fRadius1*2)*iBrushTexHeight; //int iBrushTexX = (float)(x+kTransVector.x); //int iBrushTexY = (float)(y+kTransVector.y); // 只取 R 通道中的颜色 fBrushTextureAlpah = 1.0f - (*(*pBrushPixelData)(iBrushTexX, iBrushTexY))/255.0f; } float fScale = fLengthGetVertexColor(iIndex); NiColorA kNewColor = kOldColor; if (bPaintWater) { int iScale = fScale * 256; int iOldWater = (1 - kOldColor.a) * 256 * 2; int iNewWater = iOldWater + iScale; if (iNewWater > 256) { iNewWater = 256; } if (iNewWater < 0) { iNewWater = 0; } kNewColor.a = (float)(128 + (256 - iNewWater) / 2) / 256.0f; //// 添加水波 [11/25/2009 hemeng] //if (fScale >= 0.0f) //{ // kNewColor.a = (128.0f / 255.0f) + (1-fScale) / 2; //} //// 删除水波 [11/25/2009 hemeng] //else //{ // if (kNewColor.a < 1.0f) // { // kNewColor.a -= fScale / 2; // } // //} } else { fScale *= fBrushTextureAlpah; float fOldAlpha = kOldColor.a; kNewColor = kOldColor*(1.0-fScale) + (m_kInUseVertexColor*fScale); kNewColor.a = fOldAlpha; } kNewColor.Clamp(); pTerrain->SetVertexColor(iIndex, kNewColor); } } for ( size_t i = 0; i < vAffectedChunks.size(); ++i ) { NotifyChunkVertexChanged(pTerrain, vAffectedChunks.at(i)); } } // 函数作废 __forceinline int CTerrainModifier::_GetPixelLocationChunk( CTerrain *pTerrain, NiPoint2& vPixel ) { //float fx = static_cast< float >( vPixel.x * BLEND_TEXEL_SIZE );//pTerrain->m_iTotalX * //float fy = static_cast< float >( vPixel.y * BLEND_TEXEL_SIZE );//pTerrain->m_iTotalY * //return pTerrain->GetChunkIndex( NiPoint3( fx, fy, 0 ) ); return 0; } // 081008 add by 和萌 /// 查找Gird对应BlendTexture的像素值 unsigned char* CTerrainModifier::_GetBlendPixelByGrid(CTerrain *pTerrain,int iChunkID, NiPoint2 vPos) { CTerrain::stChunk* pChunk = &pTerrain->GetChunks()[iChunkID]; CTerrainMaterial* mtlChunk = pChunk->pChunkMtl; int iUsedLayer = mtlChunk->GetUsedLayerCount(); NiSourceTexturePtr pkBlendTexture = mtlChunk->GetBlendTexture(); NiPixelData* pPixelData = pkBlendTexture->GetSourcePixelData(); // 比例位置 float fx = ( vPos.x - pChunk->vPosMin.x ) / ( pChunk->vPosMax.x - pChunk->vPosMin.x ); float fy = ( vPos.y - pChunk->vPosMin.y ) / ( pChunk->vPosMax.y - pChunk->vPosMin.y ); unsigned int uiBlendTexSize = mtlChunk->GetBlendTexSize(); fx *= uiBlendTexSize; fy *= uiBlendTexSize; unsigned char* pPtr = (*pPixelData)(fx,fy); return pPtr; } /// 由像素混合结果计算地形属性 int CTerrainModifier::_GetRegionPropertyByPixel(CTerrain *pTerrain,int iChunkID,unsigned char* ucPixel) { CTerrainMaterial* mtlChunk = pTerrain->GetChunks()[iChunkID].pChunkMtl; int iLayer = 1; //记录混合纹理的层数 //无混合时ucPixel默认为各通道为0 for (int i = 0; i < 3; i++) { if ( ucPixel[i] != 0.0f ) { iLayer = i + 2; } } float* pBlendFactor = new float[iLayer]; switch(iLayer) { //仅由1层纹理 case 1: pBlendFactor[0] = 1; break; //2层纹理 case 2: if (ucPixel[0] == 255.0f) { int k = 0; } pBlendFactor[1] = ucPixel[0] / 255.0f; pBlendFactor[0] = 1 - ucPixel[0] / 255.0f; break; case 3: pBlendFactor[2] = ucPixel[1] / 255.0f; pBlendFactor[1] = (1 - ucPixel[1] / 255.0f ) * ucPixel[0] / 255.0f; pBlendFactor[0] = (1 - ucPixel[1] / 255.0f) * (1 - ucPixel[0] / 255.0f); break; case 4: pBlendFactor[3] = ucPixel[2] / 255.0f; pBlendFactor[2] = (1 - ucPixel[2] / 255.0f) * ucPixel[1] / 255.0f; pBlendFactor[1] = (1 - ucPixel[2] / 255.0f) * (1 - ucPixel[1] / 255.0f) * ucPixel[0]/ 255.0f; pBlendFactor[0] = (1 - ucPixel[2] / 255.0f) * (1 - ucPixel[1] / 255.0f) * (1 - ucPixel[0]/ 255.0f); break; default: pBlendFactor[0] = 1; break; } float temp = pBlendFactor[0]; int iTexLayer = 0; for (int i = 0; i < iLayer; i++ ) { if ( pBlendFactor[i] > temp) { temp = pBlendFactor[i]; iTexLayer = i; } } if ( iTexLayer < 0) { iTexLayer = 0; } //获得纹理名 const string& strFileName = mtlChunk->GetTextureFile(iTexLayer); //去除路径,仅保留文件名 string strTexName = strFileName.substr( strFileName.find_last_of("/") + 1); return CSceneDesignerConfig::GetInstance()->GetRegionShapyeByMaterial(strTexName); } /// 计算第index个顶点的法线 /* 3 | 2 ____|P____ | 0 | 1 */ const NiPoint3 CTerrainModifier::CalculateNormal( CTerrain *pTerrain, int index ) { int iVertexNum = pTerrain->m_iVertexX * pTerrain->m_iVertexY; assert( index >= 0 && index < iVertexNum ); int ix = index % pTerrain->m_iVertexX; //列索引 int iy = index / pTerrain->m_iVertexX; //行索引 NiPoint3 vNormal = NiPoint3::ZERO; int _ix = ix-1; int ix_ = ix+1; int _iy = iy-1; int iy_ = iy+1; int count = 0; // 共享第0面 if ( _ix >= 0 && _iy >= 0 ) { // 拆分第0面 int index1 = index - 1; int index2 = index - pTerrain->m_iVertexX - 1; NiPoint3 v1 = pTerrain->m_pVertices[index1] - pTerrain->m_pVertices[index]; NiPoint3 v2 = pTerrain->m_pVertices[index2] - pTerrain->m_pVertices[index]; vNormal += v1.Cross(v2); count++; // 拆分第1面 index1 = index2; index2 = index - pTerrain->m_iVertexX; v1 = pTerrain->m_pVertices[index1] - pTerrain->m_pVertices[index]; v2 = pTerrain->m_pVertices[index2] - pTerrain->m_pVertices[index]; vNormal += v1.Cross(v2); count++; } // 共享第1面 if ( ix_ < pTerrain->m_iVertexX && _iy >= 0 ) { int index1 = index - pTerrain->m_iVertexX; int index2 = index + 1; NiPoint3 v1 = pTerrain->m_pVertices[index1] - pTerrain->m_pVertices[index]; NiPoint3 v2 = pTerrain->m_pVertices[index2] - pTerrain->m_pVertices[index]; vNormal += v1.Cross(v2); count++; } // 共享第2面 if ( ix_ < pTerrain->m_iVertexX && iy_ < pTerrain->m_iVertexY ) { // 拆分第0面 int index1 = index + 1; int index2 = index + pTerrain->m_iVertexX + 1; NiPoint3 v1 = pTerrain->m_pVertices[index1] - pTerrain->m_pVertices[index]; NiPoint3 v2 = pTerrain->m_pVertices[index2] - pTerrain->m_pVertices[index]; vNormal += v1.Cross(v2); count++; // 拆分第1面 index1 = index2; index2 = index + pTerrain->m_iVertexX; v1 = pTerrain->m_pVertices[index1] - pTerrain->m_pVertices[index]; v2 = pTerrain->m_pVertices[index2] - pTerrain->m_pVertices[index]; vNormal += v1.Cross(v2); count++; } // 共享第3面 if ( _ix >= 0 && iy_ < pTerrain->m_iVertexY ) { int index1 = index + pTerrain->m_iVertexX; int index2 = index - 1; NiPoint3 v1 = pTerrain->m_pVertices[index1] - pTerrain->m_pVertices[index]; NiPoint3 v2 = pTerrain->m_pVertices[index2] - pTerrain->m_pVertices[index]; vNormal += v1.Cross(v2); count++; } vNormal.Unitize(); //LOG4( "法线计算次数: %d, 法线: %.2f, %.2f, %.2f \n\n", count, vNormal.x, vNormal.y, vNormal.z ); return vNormal; } void CTerrainModifier::CalculateTBN( CTerrain* pTerrain, int index, NiPoint3& vTangent, NiPoint3& vBinormal, NiPoint3& vNormal ) { int iVertexNum = pTerrain->m_iVertexX * pTerrain->m_iVertexY; assert( index >= 0 && index < iVertexNum ); int ix = index % pTerrain->m_iVertexX; //列索引 int iy = index / pTerrain->m_iVertexX; //行索引 vTangent = vBinormal = vNormal = NiPoint3::ZERO; NiPoint3 vFaceTangent, vFaceBinormal; int _ix = ix-1; int ix_ = ix+1; int _iy = iy-1; int iy_ = iy+1; int count = 0; // 共享第0面 if ( _ix >= 0 && _iy >= 0 ) { // 拆分第0面 int index1 = index - 1; int index2 = index - pTerrain->m_iVertexX - 1; NiPoint3 v1 = pTerrain->m_pVertices[index1] - pTerrain->m_pVertices[index]; NiPoint3 v2 = pTerrain->m_pVertices[index2] - pTerrain->m_pVertices[index]; vNormal += v1.Cross(v2); _CalculateFaceTB( pTerrain, index1, index, index2, vFaceTangent, vFaceBinormal ); vTangent += vFaceTangent; vBinormal += vFaceBinormal; count++; // 拆分第1面 index1 = index2; index2 = index - pTerrain->m_iVertexX; v1 = pTerrain->m_pVertices[index1] - pTerrain->m_pVertices[index]; v2 = pTerrain->m_pVertices[index2] - pTerrain->m_pVertices[index]; vNormal += v1.Cross(v2); _CalculateFaceTB( pTerrain, index1, index, index2, vFaceTangent, vFaceBinormal ); vTangent += vFaceTangent; vBinormal += vFaceBinormal; count++; } // 共享第1面 if ( ix_ < pTerrain->m_iVertexX && _iy >= 0 ) { int index1 = index - pTerrain->m_iVertexX; int index2 = index + 1; NiPoint3 v1 = pTerrain->m_pVertices[index1] - pTerrain->m_pVertices[index]; NiPoint3 v2 = pTerrain->m_pVertices[index2] - pTerrain->m_pVertices[index]; vNormal += v1.Cross(v2); _CalculateFaceTB( pTerrain, index1, index, index2, vFaceTangent, vFaceBinormal ); vTangent += vFaceTangent; vBinormal += vFaceBinormal; count++; } // 共享第2面 if ( ix_ < pTerrain->m_iVertexX && iy_ < pTerrain->m_iVertexY ) { // 拆分第0面 int index1 = index + 1; int index2 = index + pTerrain->m_iVertexX + 1; NiPoint3 v1 = pTerrain->m_pVertices[index1] - pTerrain->m_pVertices[index]; NiPoint3 v2 = pTerrain->m_pVertices[index2] - pTerrain->m_pVertices[index]; vNormal += v1.Cross(v2); _CalculateFaceTB( pTerrain, index1, index, index2, vFaceTangent, vFaceBinormal ); vTangent += vFaceTangent; vBinormal += vFaceBinormal; count++; // 拆分第1面 index1 = index2; index2 = index + pTerrain->m_iVertexX; v1 = pTerrain->m_pVertices[index1] - pTerrain->m_pVertices[index]; v2 = pTerrain->m_pVertices[index2] - pTerrain->m_pVertices[index]; vNormal += v1.Cross(v2); _CalculateFaceTB( pTerrain, index1, index, index2, vFaceTangent, vFaceBinormal ); vTangent += vFaceTangent; vBinormal += vFaceBinormal; count++; } // 共享第3面 if ( _ix >= 0 && iy_ < pTerrain->m_iVertexY ) { int index1 = index + pTerrain->m_iVertexX; int index2 = index - 1; NiPoint3 v1 = pTerrain->m_pVertices[index1] - pTerrain->m_pVertices[index]; NiPoint3 v2 = pTerrain->m_pVertices[index2] - pTerrain->m_pVertices[index]; vNormal += v1.Cross(v2); _CalculateFaceTB( pTerrain, index1, index, index2, vFaceTangent, vFaceBinormal ); vTangent += vFaceTangent; vBinormal += vFaceBinormal; count++; } vNormal.Unitize(); vBinormal.Unitize(); vTangent.Unitize(); vTangent = vTangent - vTangent.Dot( vNormal ) * vNormal; vBinormal = vBinormal - vBinormal.Dot( vNormal ) * vNormal - vBinormal.Dot( vTangent ) * vTangent; vTangent.Unitize(); vBinormal.Unitize(); return; } void CTerrainModifier::_CalculateFaceTB( CTerrain *pTerrain, int index0, int index1, int index2, NiPoint3& vFaceTangent, NiPoint3& vFaceBinormal ) { NiPoint3 vEdge1 = pTerrain->m_pVertices[index0] - pTerrain->m_pVertices[index1]; NiPoint3 vEdge2 = pTerrain->m_pVertices[index2] - pTerrain->m_pVertices[index1]; float fDeltaS1 = pTerrain->m_pTexset0[index0].x - pTerrain->m_pTexset0[index1].x; float fDeltaS2 = pTerrain->m_pTexset0[index2].x - pTerrain->m_pTexset0[index1].x; float fDeltaT1 = pTerrain->m_pTexset0[index0].y - pTerrain->m_pTexset0[index1].y; float fDeltaT2 = pTerrain->m_pTexset0[index2].y - pTerrain->m_pTexset0[index1].y; vFaceTangent = vEdge1 * fDeltaT2 - vEdge2 * fDeltaT1; vFaceBinormal = vEdge1 * fDeltaS2 - vEdge2 * fDeltaS1; // 手向性? vFaceTangent.Unitize(); vFaceBinormal.Unitize(); } vector CTerrainModifier::_GetAffectedChunks( CTerrain *pTerrain, const NiPoint3& vPos, float fRadius ) { vector v; int index = 0; for ( int i = 0; i < pTerrain->m_iChunkNumY; ++i ) { for ( int j = 0; j < pTerrain->m_iChunkNumX; ++j ) { //int index = i * m_iChunkNumX + j; if ( CircleInteracrossRectangle( NiPoint2( vPos.x, vPos.y ), fRadius, pTerrain->m_pChunks[index].vPosMin, pTerrain->m_pChunks[index].vPosMax ) ) { v.push_back( index ); } index++; } } return v; } void CTerrainModifier::NotifyChunkVertexChanged( CTerrain *pTerrain, int index ) { // 检查index有效性 if ( index < 0 || index >= pTerrain->m_iChunkNumX*pTerrain->m_iChunkNumY ) return; CTerrain::stChunk::stGeomData& geomData = pTerrain->m_pChunks[index].geomData; // 更新顶点及法线 NiPoint3* pVerts = geomData.pTriShape->GetVertices(); NiPoint3* pNormals = geomData.pTriShape->GetNormals(); NiColorA* pColors = geomData.pTriShape->GetColors(); //NiPoint3* pLineVerts = geomData.pLine->GetVertices(); for ( int n = 0; n < (GRIDINCHUNK+1)*(GRIDINCHUNK+1); ++n ) { pVerts[n] = pTerrain->m_pVertices[geomData.pGlobalVertIndx[n]]; pNormals[n] = pTerrain->m_pNormals[geomData.pGlobalVertIndx[n]]; pColors[n] = pTerrain->m_pVertexClr[geomData.pGlobalVertIndx[n]]; //pLineVerts[2*n] = pVerts[n]; //pLineVerts[2*n+1] = pVerts[n]+pNormals[n]; } // 法线自行计算, 不使用系统提供的算法 //geomData.pTriShape->CalculateNormals(); // 设置更新标志 NiTriShapeDynamicData* pkData = (NiTriShapeDynamicData*)(geomData.pTriShape->GetModelData()); pkData->SetActiveTriangleCount(GRIDINCHUNK*GRIDINCHUNK*2); pkData->SetActiveVertexCount( (GRIDINCHUNK+1)*(GRIDINCHUNK+1) ); pkData->MarkAsChanged(NiGeometryData::VERTEX_MASK | NiGeometryData::NORMAL_MASK | NiGeometryData::COLOR_MASK); } /// 设置当前绘制状态,绘制纹理还是顶点 void CTerrainModifier::SetPaintState(bool bPaintTexture, bool bPaintVertexColor,bool bPatinWaterScene) { m_bPaintTexture = bPaintTexture; m_bPaintVertexColor = bPaintVertexColor; m_bPaintWaterScene = bPatinWaterScene; } /// 设置当前使用的顶点颜色 void CTerrainModifier::SetInUseVertexColor(const NiColorA& kColor) { m_kInUseVertexColor = kColor; } void CTerrainModifier::SetBrushTexture(const char *pszBaseText) { if (pszBaseText == NULL) { m_pkBrushTexture = NULL; } else { m_pkBrushTexture = CTerrainTextureMgr::GetInstance()->GetTexture(pszBaseText); m_pkBrushTexture->LoadPixelDataFromFile(); } } void CTerrainModifier::SetTerrainOp(ETerrainOperation op) { m_TerrainOperation = op; } void CTerrainModifier::SetPaintAddTo(bool bAddTo) { m_bPaintAddTo = bAddTo; } // 081008 add by 和萌 /// 通过纹理设置grid地表属性 void CTerrainModifier::SetRegionPropertyByMaterial(CTerrain* pTerrain) { int iChunkNumX,iChunkNumY; iChunkNumX = pTerrain->m_iChunkNumX; iChunkNumY = pTerrain->m_iChunkNumY; //Grid数据 int iGridX = iChunkNumX * GRIDINCHUNK; int iGridY = iChunkNumX * GRIDINCHUNK; //计算属性 for(int iY = 0; iY < iGridY; iY++) { for(int iX = 0; iX < iGridX; iX++) { int iGridIndex = iY * iGridX + iX; CTerrain::stGrid &grid = pTerrain->m_pGrids[iGridIndex]; NiPoint3 kLB = pTerrain->m_pVertices[grid.iPointIndx[0]]; int iChunkIndex = pTerrain->GetChunkIndex(kLB); NiPoint2 kLB2D = NiPoint2(kLB.x,kLB.y); unsigned char* ucPixel = _GetBlendPixelByGrid(pTerrain,iChunkIndex,kLB2D); int iGridProType = _GetRegionPropertyByPixel(pTerrain,iChunkIndex,ucPixel); //当不是BLOCK属性时更新现有属性 if ((grid.iTerrainProperty & 0x0000000F) != 1) { CopyLowFourBit(grid.iTerrainProperty, iGridProType); } } } //重绘属性纹理 for (int i = 0; i < iGridX * iGridY; i++) { int iTerrPro = pTerrain->m_pGrids[i].iTerrainProperty & 0x0000000f; CTerrain::stGrid &grid = pTerrain->m_pGrids[i]; // 显示设置 NiPoint3 vLeftBtm = pTerrain->m_pVertices[ grid.iPointIndx[0] ]; NiPoint3 vRightTop = pTerrain->m_pVertices[ grid.iPointIndx[2] ]; int iChunkIndx = pTerrain->GetChunkIndex( ( vLeftBtm+vRightTop) * 0.5f ); CTerrain::stChunk& chunk = pTerrain->m_pChunks[iChunkIndx]; CTerrainMaterial *pMtl = chunk.pChunkMtl; int iSize = pMtl->GetBlendTexSize(); float fLeft = iSize * ( vLeftBtm.x - chunk.vPosMin.x ) / ( chunk.vPosMax.x - chunk.vPosMin.x ); float fRight = iSize * ( vRightTop.x - chunk.vPosMin.x ) / ( chunk.vPosMax.x - chunk.vPosMin.x ); float fBtm = iSize * ( vLeftBtm.y - chunk.vPosMin.y ) / ( chunk.vPosMax.y - chunk.vPosMin.y ); float fTop = iSize * ( vRightTop.y - chunk.vPosMin.y ) / ( chunk.vPosMax.y - chunk.vPosMin.y ); pMtl->SetTerrainPropertyA( NiRect( fLeft, fRight, fTop, fBtm ), iTerrPro ); } } /// 将纹理写到地形的 blend texture 的 alpha 通道中 bool CTerrainModifier::ApplyShadowTexture(CTerrain* pTerrain, NiTexturePtr pkSourceShadowTexture) { int iNumChunkX = pTerrain->GetChunkNumX(); int iNumChunkY = pTerrain->GetChunkNumY(); if (pkSourceShadowTexture->GetWidth() != iNumChunkX*BLENDTEX_SIZE ||pkSourceShadowTexture->GetWidth() != iNumChunkX*BLENDTEX_SIZE) { LOG("应用到地形的阴影纹理与地形尺寸不符."); return false; } const char* pszTmpTexFileName = "_tmp_shadow_map.dds"; bool bChanged = true; bool bMipMap = false; bool bNonPow2 = false; NiDX9Renderer* pRenderer = NiDynamicCast( NiDX9Renderer, NiRenderer::GetRenderer() ); LPDIRECT3DBASETEXTURE9 pD3DTex = pRenderer->GetTextureManager() ->PrepareTextureForRendering( pkSourceShadowTexture, bChanged, bMipMap, bNonPow2 ); HRESULT hr = D3DXSaveTextureToFile( pszTmpTexFileName, D3DXIFF_DDS, pD3DTex, NULL ); if ( hr == E_FAIL ) { return false; } // 将纹理载入成 source texture NiTexture::FormatPrefs kPrefs; kPrefs.m_ePixelLayout = NiTexture::FormatPrefs::TRUE_COLOR_32; kPrefs.m_eMipMapped = NiTexture::FormatPrefs::NO; NiSourceTexture::SetDestroyAppDataFlag( false ); NiSourceTexturePtr pkShadowTexture = NiSourceTexture::Create(pszTmpTexFileName); pkShadowTexture->LoadPixelDataFromFile(); pkShadowTexture->SetStatic(false); NiSourceTexture::SetDestroyAppDataFlag( true ); NiPixelData* pShadowTexPixelData = pkShadowTexture->GetSourcePixelData(); if (NULL == pShadowTexPixelData) { LOG("获取阴影纹理像素数据失败."); return false; } CTerrain::stChunk* pChunks = pTerrain->GetChunks(); // 遍历每一个 chunk int idx = 0; for (int i=0; iGetBlendTexture(); // 混合纹理像素数据 NiPixelData* pBlendTexPixelData = pkBlendTexture->GetSourcePixelData(); if (NULL == pBlendTexPixelData) { LOG("获取混合纹理像素数据失败."); return false; } int iOffsetX = j*BLENDTEX_SIZE; int iOffsetY = (iNumChunkY-i-1)*BLENDTEX_SIZE; // 将 ShadowTexture 的对应块拷贝到 blend texture 的 alpha 通道中 for (int m=0; mMarkAsChanged(); idx++; } } SmoothBlendTextureEdge(pTerrain); return true; // 之前 ShadowMapSize 为 128 //int iNumChunkX = pTerrain->GetChunkNumX(); //int iNumChunkY = pTerrain->GetChunkNumY(); //if (pkSourceShadowTexture->GetWidth() != iNumChunkX*SHADOWMAP_SIZE_CHUNK // ||pkSourceShadowTexture->GetWidth() != iNumChunkX*SHADOWMAP_SIZE_CHUNK) //{ // LOG("应用到地形的阴影纹理与地形尺寸不符."); // return false; //} //const char* pszTmpTexFileName = "_tmp_shadow_map.dds"; //bool bChanged = true; //bool bMipMap = false; //bool bNonPow2 = false; //NiDX9Renderer* pRenderer = NiDynamicCast( NiDX9Renderer, NiRenderer::GetRenderer() ); //LPDIRECT3DBASETEXTURE9 pD3DTex = pRenderer->GetTextureManager() // ->PrepareTextureForRendering( pkSourceShadowTexture, bChanged, bMipMap, bNonPow2 ); //HRESULT hr = D3DXSaveTextureToFile( pszTmpTexFileName, D3DXIFF_DDS, pD3DTex, NULL ); //if ( hr == E_FAIL ) //{ // return false; //} //// 将纹理载入成 source texture //// 阴影纹理的像素数据 ////pkShadowTexture->GetSourcePixelData //NiTexture::FormatPrefs kPrefs; //kPrefs.m_ePixelLayout = NiTexture::FormatPrefs::TRUE_COLOR_32; //kPrefs.m_eMipMapped = NiTexture::FormatPrefs::NO; //NiSourceTexture::SetDestroyAppDataFlag( false ); //NiSourceTexturePtr pkShadowTexture = NiSourceTexture::Create(pszTmpTexFileName); //pkShadowTexture->LoadPixelDataFromFile(); //pkShadowTexture->SetStatic(false); //NiSourceTexture::SetDestroyAppDataFlag( true ); //NiPixelData* pShadowTexPixelData = pkShadowTexture->GetSourcePixelData(); //if (NULL == pShadowTexPixelData) //{ // LOG("获取阴影纹理像素数据失败."); // return false; //} //CTerrain::stChunk* pChunks = pTerrain->GetChunks(); //// 遍历每一个 chunk //int idx = 0; //for (int i=0; iGetBlendTexture(); // // 混合纹理像素数据 // NiPixelData* pBlendTexPixelData = pkBlendTexture->GetSourcePixelData(); // if (NULL == pBlendTexPixelData) // { // LOG("获取混合纹理像素数据失败."); // return false; // } // int iOffsetX = j*SHADOWMAP_SIZE_CHUNK; // int iOffsetY = (iNumChunkY-i-1)*SHADOWMAP_SIZE_CHUNK; // // 将 ShadowTexture 的对应块拷贝到 blend texture 的 alpha 通道中 // for (int m=0; mMarkAsChanged(); // idx++; // } //} //return true; } //------------------------------------------------------------------------------ bool CTerrainModifier::SmoothBlendTextureEdge(CTerrain* pkTerrain) { if (pkTerrain == NULL) return false; CTerrain::stChunk* arrChunks = pkTerrain->GetChunks(); int iChunkID = 0; for (int i=0; iGetChunkNumY(); i++) // 列 { for (int j=0; jGetChunkNumX(); j++, iChunkID++) // 行 { // 当前纹理 NiSourceTexturePtr spCurrTexture = arrChunks[iChunkID].pChunkMtl->GetBlendTexture(); NiPixelData* pkCurrPixelData = spCurrTexture->GetSourcePixelData(); if (j != pkTerrain->GetChunkNumX()-1) { // 右侧的 blend texture NiSourceTexturePtr spRightTexture = arrChunks[iChunkID+1].pChunkMtl->GetBlendTexture(); NiPixelData* pkRightPixelData = spRightTexture->GetSourcePixelData(); // smooth 列接缝 for (int k=0; kMarkAsChanged(); pkCurrPixelData->MarkAsChanged(); } if (i != pkTerrain->GetChunkNumY()-1) { // 上侧的 blend texture NiSourceTexturePtr spUpTexture = arrChunks[iChunkID+pkTerrain->GetChunkNumX()].pChunkMtl->GetBlendTexture(); NiPixelData* pkUpPixelData = spUpTexture->GetSourcePixelData(); // smooth 行接缝 for (int k=0; kMarkAsChanged(); pkCurrPixelData->MarkAsChanged(); } } } return true; } //------------------------------------------------------------------------------ /// 将纹理写到地形特定 chunk 的 blend texture 的 alpha 通道 bool CTerrainModifier::ApplyShadowTexture(CTerrain* pTerrain, NiTexturePtr pkTexture, int iChunkID) { int iNumChunkX = pTerrain->GetChunkNumX(); int iNumChunkY = pTerrain->GetChunkNumY(); const char* pszTmpTexFileName = "_tmp_shadow_map.dds"; bool bChanged = true; bool bMipMap = false; bool bNonPow2 = false; NiDX9Renderer* pRenderer = NiDynamicCast( NiDX9Renderer, NiRenderer::GetRenderer() ); LPDIRECT3DBASETEXTURE9 pD3DTex = pRenderer->GetTextureManager() ->PrepareTextureForRendering( pkTexture, bChanged, bMipMap, bNonPow2 ); HRESULT hr = D3DXSaveTextureToFile( pszTmpTexFileName, D3DXIFF_DDS, pD3DTex, NULL ); if ( hr == E_FAIL ) { return false; } // 将纹理载入成 source texture NiTexture::FormatPrefs kPrefs; kPrefs.m_ePixelLayout = NiTexture::FormatPrefs::TRUE_COLOR_32; kPrefs.m_eMipMapped = NiTexture::FormatPrefs::NO; NiSourceTexture::SetDestroyAppDataFlag( false ); NiSourceTexturePtr pkShadowTexture = NiSourceTexture::Create(pszTmpTexFileName); pkShadowTexture->LoadPixelDataFromFile(); pkShadowTexture->SetStatic(false); NiSourceTexture::SetDestroyAppDataFlag( true ); NiPixelData* pShadowTexPixelData = pkShadowTexture->GetSourcePixelData(); if (NULL == pShadowTexPixelData) { LOG("获取阴影纹理像素数据失败."); return false; } CTerrain::stChunk* pChunks = pTerrain->GetChunks(); NiSourceTexturePtr pkBlendTexture = pChunks[iChunkID].pChunkMtl->GetBlendTexture(); // 混合纹理像素数据 NiPixelData* pBlendTexPixelData = pkBlendTexture->GetSourcePixelData(); if (NULL == pBlendTexPixelData) { LOG("获取混合纹理像素数据失败."); return false; } // 将 ShadowTexture 的对应块拷贝到 blend texture 的 alpha 通道中 for (int m=0; mMarkAsChanged(); return true; } //------------------------------------------------------------------------------ bool CTerrainModifier::ApplyVertexColorTexture(CTerrain* pTerrain, NiSourceTexturePtr pkTexture, float fLum) { //int iNumChunkX = pTerrain->GetChunkNumX(); //int iNumChunkY = pTerrain->GetChunkNumY(); //int iNumVertexX = iNumChunkX * GRIDINCHUNK + 1; // 地形 x, y 方向的顶点数量 //int iNumVertexY = iNumChunkY * GRIDINCHUNK + 1; //pkTexture->LoadPixelDataFromFile(); //NiPixelData* pTexPixelData = pkTexture->GetSourcePixelData(); //if (NULL == pTexPixelData) //{ // LOG("获取顶点色纹理像素数据失败."); // return false; //} //int iTexWidth = pTexPixelData->GetWidth(); //int iTexHeight = pTexPixelData->GetHeight(); //NiColorA* arrColors = pTerrain->GetVertexColor(); //int iVertIdx = 0; //// 遍历所有顶点,根据相对 UV 从纹理中获取对应象素颜色 //for (int i=0; i iTexWidth) continue; // for (int y=-2; y<=2; y++) // { // if (n+y < 0 || n+y > iTexHeight) continue; // unsigned char *pColorPtr = (*pTexPixelData)(m+x,n+y); // R += pColorPtr[0]; // G += pColorPtr[1]; // B += pColorPtr[2]; // iNumSamp++; // } // } // R /= iNumSamp; // G /= iNumSamp; // B /= iNumSamp; // // 将颜色转换到 Lab 空间 // float L=0.0f, a = 0.0f, b=0.0f; // RGB2Lab(R, G, B, L, a, b); // if (bFixLum) // { // // 对于 L 小于 50.0f 的区域 (阴影区域?) 将 L 设置为较大值还原其颜色 // if (L < 100.0f-fLum) // { // // 将 L 从1~100 空间映射到 fLum~100 空间 // L = L * (100.0f-fLum)/100.0f + fLum; // Lab2RGB(L, a, b, R, G, B); // NiColorA kColor(R/255.0f, G/255.0f, B/255.0f, 1.0f); // arrColors[iVertIdx++] = kColor; // } // else // { // NiColorA kColor(R/255.0f, G/255.0f, B/255.0f, 1.0f); // arrColors[iVertIdx++] = kColor * fIncMultiple); // } // } // else // { // // 将 L 从1~100 空间映射到 fLum~100 空间 // L = L * (100.0f-fLum)/100.0f + fLum; // Lab2RGB(L, a, b, R, G, B); // NiColorA kColor(R/255.0f, G/255.0f, B/255.0f, 1.0f); // arrColors[iVertIdx++] = kColor; // } // } //} //for (int i=0; iGetChunkNumX(); int iNumChunkY = pTerrain->GetChunkNumY(); int iNumVertexX = iNumChunkX * GRIDINCHUNK + 1; // 地形 x, y 方向的顶点数量 int iNumVertexY = iNumChunkY * GRIDINCHUNK + 1; // chunk 中每行的顶点数 int iNumVertInChunkRow = GRIDINCHUNK + 1; // chunk 中第一个顶点在地形顶点中的二维坐标 int iOffsetX = (iChunkID % iNumChunkX) * GRIDINCHUNK; int iOffsetY = (iChunkID / iNumChunkX) * GRIDINCHUNK; pkTexture->LoadPixelDataFromFile(); NiPixelData* pTexPixelData = pkTexture->GetSourcePixelData(); if (NULL == pTexPixelData) { LOG("获取顶点色纹理像素数据失败."); return false; } int iTexWidth = pTexPixelData->GetWidth(); int iTexHeight = pTexPixelData->GetHeight(); NiColorA* arrColors = pTerrain->GetVertexColor(); // 遍历所有顶点,根据相对 UV 从纹理中获取对应象素颜色 for (int i=0; i iTexWidth) continue; // for (int y=-2; y<=2; y++) // { //if (n+y < 0 || n+y > iTexHeight) continue; unsigned char *pColorPtr = (*pTexPixelData)(m,n); R += pColorPtr[0]; G += pColorPtr[1]; B += pColorPtr[2]; //iNumSamp++; // } //} //R /= iNumSamp; //G /= iNumSamp; //B /= iNumSamp; // 将颜色转换到 Lab 空间 float L=0.0f, a = 0.0f, b=0.0f; RGB2Lab(R, G, B, L, a, b); int iVertIdx = (iOffsetY + i) * iNumVertexX + iOffsetX + j; if (bFixLum) { // 将 L 从1~100 空间映射到 fLum~100 空间 float L2 = L * (100.0f-fLum)/100.0f + fLum; Lab2RGB(L2, a, b, R, G, B); NiColorA kColor(R/255.0f, G/255.0f, B/255.0f, 1.0f); if (L >= fLum) { kColor *= powf(1+(L-fLum)/L*fIncMultiple, 2.0f);//fIncMultiple; } arrColors[iVertIdx++] = kColor; } else { // 将 L 从1~100 空间映射到 fLum~100 空间 L = L * (100.0f-fLum)/100.0f + fLum; Lab2RGB(L, a, b, R, G, B); NiColorA kColor(R/255.0f, G/255.0f, B/255.0f, 1.0f); arrColors[iVertIdx++] = kColor; } //// 将 L 从1~100 空间映射到 fLum~100 空间 //L = L * (100.0f-fLum)/100.0f + fLum; //Lab2RGB(L, a, b, R, G, B); //NiColorA kColor(R/255.0f, G/255.0f, B/255.0f, 1.0f); //int iVertIdx = (iOffsetY + i) * iNumVertexX + iOffsetX + j; //arrColors[iVertIdx] = kColor; } } NotifyChunkVertexChanged(pTerrain, iChunkID); return true; } //------------------------------------------------------------------------------ /// 从地形 chunk 的 blend texture alpha 通道中获取阴影纹理 NiSourceTexturePtr CTerrainModifier::ExtractShadowTexture(CTerrain* pTerrain) { int iNumChunkX = pTerrain->GetChunkNumX(); int iNumChunkY = pTerrain->GetChunkNumY(); NiTexture::FormatPrefs kPrefs; kPrefs.m_ePixelLayout = NiTexture::FormatPrefs::TRUE_COLOR_32; kPrefs.m_eMipMapped = NiTexture::FormatPrefs::NO; NiPixelData *pPixelData = NiNew NiPixelData( BLENDTEX_SIZE*iNumChunkX, BLENDTEX_SIZE*iNumChunkY, NiPixelFormat::RGBA32 ); NiSourceTexture::SetDestroyAppDataFlag( false ); NiSourceTexturePtr pkShadowTexture = NiSourceTexture::Create( pPixelData ); if ( !pkShadowTexture ) return NULL; pkShadowTexture->SetStatic( false ); NiSourceTexture::SetDestroyAppDataFlag( true ); CTerrain::stChunk* pChunks = pTerrain->GetChunks(); // 遍历每一个 chunk int idx = 0; for (int i=0; iGetBlendTexture(); // 混合纹理像素数据 NiPixelData* pBlendTexPixelData = pkBlendTexture->GetSourcePixelData(); if (NULL == pBlendTexPixelData) { LOG("获取混合纹理像素数据失败."); return false; } int iOffsetX = j*BLENDTEX_SIZE; int iOffsetY = (iNumChunkY-i-1)*BLENDTEX_SIZE; // 将 ShadowTexture 的对应块拷贝到 blend texture 的 alpha 通道中 for (int m=0; mMarkAsChanged(); return pkShadowTexture; //int iNumChunkX = pTerrain->GetChunkNumX(); //int iNumChunkY = pTerrain->GetChunkNumY(); //NiTexture::FormatPrefs kPrefs; //kPrefs.m_ePixelLayout = NiTexture::FormatPrefs::TRUE_COLOR_32; //kPrefs.m_eMipMapped = NiTexture::FormatPrefs::NO; //NiPixelData *pPixelData = NiNew NiPixelData( SHADOWMAP_SIZE_CHUNK*iNumChunkX, SHADOWMAP_SIZE_CHUNK*iNumChunkY, NiPixelFormat::RGBA32 ); //NiSourceTexture::SetDestroyAppDataFlag( false ); //NiSourceTexturePtr pkShadowTexture = NiSourceTexture::Create( pPixelData ); //if ( !pkShadowTexture ) // return NULL; //pkShadowTexture->SetStatic( false ); //NiSourceTexture::SetDestroyAppDataFlag( true ); //CTerrain::stChunk* pChunks = pTerrain->GetChunks(); //// 遍历每一个 chunk //int idx = 0; //for (int i=0; iGetBlendTexture(); // // 混合纹理像素数据 // NiPixelData* pBlendTexPixelData = pkBlendTexture->GetSourcePixelData(); // if (NULL == pBlendTexPixelData) // { // LOG("获取混合纹理像素数据失败."); // return false; // } // int iOffsetX = j*SHADOWMAP_SIZE_CHUNK; // int iOffsetY = (iNumChunkY-i-1)*SHADOWMAP_SIZE_CHUNK; // // 将 ShadowTexture 的对应块拷贝到 blend texture 的 alpha 通道中 // for (int m=0; mMarkAsChanged(); //return pkShadowTexture; } // 函数未使用 bool CTerrainModifier::RayTestShadowProcess( CTerrain *pTerrain, const NiVisibleArray &kGeometryArray, const NiPoint3& vLitDir, int iChunkID) { // 遍历地形所有 blend texture.从每个象素位置向反灯光方向做射线。如果与物件碰撞,说明该像素在阴影中 //int iNumChunkX = pTerrain->GetChunkNumX(); //int iNumChunkY = pTerrain->GetChunkNumY(); CTerrain::stChunk* pChunks = pTerrain->GetChunks(); NiPoint3 kRayDir = -vLitDir; NiPick kPick; kPick.SetPickType(NiPick::FIND_FIRST); kPick.SetIntersectType(NiPick::TRIANGLE_INTERSECT); kPick.SetCoordinateType(NiPick::WORLD_COORDINATES); kPick.SetFrontOnly(false); kPick.SetSortType(NiPick::NO_SORT); int idx = iChunkID; //for (int i=0; iGetBlendTexture(); // 混合纹理像素数据 NiPixelData* pBlendTexPixelData = pkBlendTexture->GetSourcePixelData(); if (NULL == pBlendTexPixelData) { LOG("获取混合纹理像素数据失败."); return false; } //int iOffsetX = j*GRIDINCHUNK; //int iOffsetY = i*GRIDINCHUNK; // 将 ShadowTexture 的对应块拷贝到 blend texture 的 alpha 通道中 for (int m=0; mGetHeight(kPixelPos)+0.1f; //NiPoint3 kOrigin(kPixelPos.x, kPixelPos.y, fHeight); //// 遍历所有物件,判断与射线是否碰撞 //for (unsigned int k=0; kMarkAsChanged(); // } //} return true; } void CTerrainModifier::SetMousePos(int iPosX1, int iPosY1, int iPoxX2, int iPosY2) { m_iStartX = iPosX1; m_iStartY = iPosY1; m_iEndX = iPoxX2; m_iEndY = iPosY2; } void CTerrainModifier::ComputeTerrainHeight(CTerrain *pTerrain, float& iLow, float& iHeigh) { if (pTerrain == NULL) { return; } int m_iVertexX = pTerrain->GetChunkNumX()*GRIDINCHUNK + 1; int m_iVertexY = pTerrain->GetChunkNumY()*GRIDINCHUNK + 1; for ( int y = 0; y < m_iVertexY; ++y ) { for ( int x = 0; x < m_iVertexX; ++x ) { float iheight = pTerrain->GetVertexHeight(x, y); if (x == 0 && y == 0) { iLow = iheight; iHeigh = iheight; } if (iheight >= iHeigh) { iHeigh = iheight; } else if (iheight <= iLow) { iLow = iheight; } } } } bool CTerrainModifier::ExportTerrainHeightMap(CTerrain *pTerrain, const char *pszTexFile,float& fLow,float& fHeigh) { if (pTerrain==NULL || pszTexFile == NULL) { return false; } // 统计地形高度区间 ComputeTerrainHeight(pTerrain,fLow,fHeigh); float fRange = fHeigh - fLow; // 区间范围 //获取图像的长和宽 int iVertexX = pTerrain->GetChunkNumX()*GRIDINCHUNK + 1; int iVertexY = pTerrain->GetChunkNumY()*GRIDINCHUNK + 1; // 创建文件 FILE* pRawFile = NULL; if (NULL == (pRawFile = fopen(pszTexFile, "wb"))) { return false; } for ( int y = 0; y < iVertexY; ++y ) // 遍历列 { for ( int x = 0; x < iVertexX; ++x ) // 遍历行 { // 将所有顶点高度映射到 0~65535 区间 float fValue = pTerrain->GetVertexHeight(x, y); unsigned short usValue = (unsigned short)(((fValue - fLow ) / fRange) * 65535 + 0.5f); fwrite(&usValue, sizeof(unsigned short), 1, pRawFile); } } fclose(pRawFile); return true; } bool CTerrainModifier::LoadTerrainHeightMap(CTerrain * pTerrain, const char * pszTexFile, CTerrainChangeVertexCommand* pCommand,float fLow,float fHeigh) { if (pTerrain==NULL || pszTexFile == NULL) { return false; } // 读取文件 FILE* pRawFile = fopen(pszTexFile, "rb"); if (pRawFile == NULL) { return false; } //获取图像的长和宽 int iVertexX = pTerrain->GetChunkNumX()*GRIDINCHUNK + 1; int iVertexY = pTerrain->GetChunkNumY()*GRIDINCHUNK + 1; int iNumVertices = iVertexX * iVertexY; int iNumChunks = pTerrain->GetChunkNumX() * pTerrain->GetChunkNumY(); float fRange = fHeigh - fLow; // 高度区间 for ( int y = 0; y < iVertexY; ++y ) // 遍历列 { for ( int x = 0; x < iVertexX; ++x ) // 遍历行 { unsigned short usValue; fread(&usValue, sizeof(unsigned short), 1, pRawFile); // 将 0~65535 区间的值映射到 fLow 到 fHeigh 区间 float fTerrainHeight = (usValue/65535.0f) * fRange + fLow; // 实际地形高度 int iPointIndex = y*(pTerrain->GetChunkNumX()*GRIDINCHUNK+1) + x; NiPoint3& pt = pTerrain->m_pVertices[iPointIndex]; // 记录顶点的变化,用于 undo/redo tVertexChange vertChange; vertChange.iIndex = iPointIndex; vertChange.fOldHeight = pt.z; pt.z = fTerrainHeight; vertChange.fNewHeight = pt.z; if (NULL != pCommand) { pCommand->AddVertexChange(vertChange); } } } fclose(pRawFile); // 依次改变顶点的法线, 必须在所有顶点位置改变后完成, 否则可能导致计算无效 for (int i=0; im_pNormals[i]; n = CalculateNormal( pTerrain, i); } // 通知Chunks顶点改变 for (int i=0; iSetLastChangedChunk(iNumChunks-1); return true; } /// 设置地形顶点 alpha 值 //void CTerrainModifier::SetTerrainVertexAlpha(CTerrain* pTerrain, set& gridSet, float fAlpha) void CTerrainModifier::SetTerrainVertexHidden(CTerrain* pTerrain, set& gridSet, bool bHidden) { // [11/24/2009 hemeng] float fAlpha = (128.0f / 255.0f); // 地形顶点alpha : 0-fAlpha 表示地表隐藏,水波值为1-fAlpha // fAlpha-1,表示地表不隐藏,水波值为1-alpha // 1 表示地表不隐藏,无水波 // 获取地形所有顶点色,顶点位置 NiColorA* pColor = pTerrain->GetVertexColor(); const NiPoint3* pVert = pTerrain->GetVertices(); // 地形在 X 方向的 grid 数和顶点数 int iNumGridX = pTerrain->GetChunkNumX() * GRIDINCHUNK; int iNumGridY = pTerrain->GetChunkNumY() * GRIDINCHUNK; int iNumVertX = iNumGridX + 1; set affectChunkSet; // 有顶点变化的 chunks set::iterator iter = gridSet.begin(); while (iter != gridSet.end()) { int iGridIdx = *iter; // grid 的 x, y 坐标 int iX = iGridIdx % iNumGridX; int iY = iGridIdx / iNumGridX; // 顶点索引 int iVertIdx = iY * iNumVertX + iX; pColor[iVertIdx].a = fAlpha; // 地形隐藏 [11/24/2009 hemeng] if (bHidden) { if (pColor[iVertIdx].a >= fAlpha) { pColor[iVertIdx].a -= fAlpha; } else { float fTmp = pColor[iVertIdx].a; int i = 0; } } else { if (pColor[iVertIdx].a < fAlpha) { pColor[iVertIdx].a += fAlpha; } else { float fTmp = pColor[iVertIdx].a; int i = 0; } } affectChunkSet.insert(pTerrain->GetChunkIndex(pVert[iVertIdx])); // 处理最右侧和最上侧的顶点 if (iX == iNumGridX-1) { // 最右侧 grid //pColor[iVertIdx+1].a = fAlpha; pColor[iVertIdx + 1].a = pColor[iVertIdx].a; } if (iY == iNumGridY-1) { // 最上侧 grid pColor[iVertIdx+iNumVertX].a = pColor[iVertIdx].a; } if (iX==iNumGridX-1 && iY==iNumGridY-1) { pColor[iVertIdx+iNumVertX+1].a = pColor[iVertIdx].a; } iter++; } iter = affectChunkSet.begin(); while (iter != affectChunkSet.end()) { NotifyChunkVertexChanged(pTerrain, *iter); iter++; } } void CTerrainModifier::SetTerrainSurfaceProperty( CTerrain *pTerrain, const set& gridSet, int iProperty, bool bDelete ) { _SetTerrainSurfaceProperty(pTerrain, gridSet, iProperty, bDelete); } //------------------------------------------------------------------------------ bool CTerrainModifier::ApplyTextureToTerrain(CTerrain* pkTerrain, int iLayer, const char* pszTextureFile) { if (pkTerrain==NULL || iLayer<0 || iLayer>=4 || pszTextureFile==NULL) return false; // 遍历所有 chunk, 应用纹理到 iLayer 层 CTerrain::stChunk* arrChunks = pkTerrain->GetChunks(); int iNumChunks = pkTerrain->GetChunkNumX() * pkTerrain->GetChunkNumY(); for (int i=0; iReplaceTexture(iLayer, pszTextureFile); } return true; } //------------------------------------------------------------------------------ #endif