programming/direct3d

다이렉트x 3d 지형 - 맵툴

mainep 2024. 7. 26. 10:15

 

기본적인 vertex up & down, 다이얼로그를 사용한 증감률과 반지름 조절이 가능하다.

 

void CTERRAIN::Intersect( BOOL RBT, BOOL LBT, HWND gm_hWnd, BOOL mouseMove )
{
LPCUSTOMVERTEX pVertices, pCirVertices; //VB에 사용할 구조체 포인터
WORD *pIndices; //IB에 사용될 WORD 포인터
D3DXVECTOR3 centerPos; //삼각형을 이루는 각 한쌍의 인덱스중 좌측 상단의 vetex
BOOL intersect = FALSE; //픽킹의 성공여부
float scale[3] = {0.0f,}; //IntersectTriangle에 인자로 넘겨줄 scale배열
D3DXVECTOR3 orig, dir( 0.0f, -1.0f, 0.0f ); //원의 픽킹에 사용될 변수
static WORD realIBTotalSize = 8 * 8 * 6; //index의 총 길이
static BOOL first = TRUE; //첫 로딩의 판단
static DWORD sNum = 0; //VB의 번호
static DWORD referSNum = 0, referENum = 0; //참조메모리의 시작인덱스와 끝인덱스
static float lenthMinSize = (m_radiusSize * m_intervalRate -0.5f * m_intervalRate)*(m_radiusSize * m_intervalRate -0.5f * m_intervalRate); //원의 최소값의 제곱
static float lenthMaxSize = (m_radiusSize * m_intervalRate +0.5f * m_intervalRate)*(m_radiusSize * m_intervalRate +0.5f * m_intervalRate); //원의 최대값의 제곱
//원 리사이즈시 변수 초기화
if( m_reSize )
{
first = TRUE;
sNum = 0;
referSNum = 0, referENum = 0;
lenthMinSize = (m_radiusSize * m_intervalRate -0.5f * m_intervalRate)*(m_radiusSize * m_intervalRate -0.5f * m_intervalRate);
lenthMaxSize = (m_radiusSize * m_intervalRate +0.5f * m_intervalRate)*(m_radiusSize * m_intervalRate +0.5f * m_intervalRate);
m_reSize = FALSE;
}
//첫 로딩
if( first )
{
//가상 메모리로 픽킹된 삼각형의 좌측 상단 vertex를 구한다.
for( DWORD i = 0; i < m_rIndexTotalSize; i+=3 )
{
if( IntersectTriangle( m_pickOrig, m_pickDir,
m_pReferVB[m_pReferIB[i]], m_pReferVB[m_pReferIB[i+1]], m_pReferVB[m_pReferIB[i+2]],
&scale[0], &scale[1], &scale[2] ) )
{
m_pickPos = m_pickOrig + ( m_pickDir * scale[0] );
centerPos = m_pReferVB[m_pReferIB[(i%2 == 0) ? i+1 : i]] + D3DXVECTOR3( 1.0f, 0.0f, -1.0f);
referSNum = ((i - m_rIndexRoadSize[0])) > m_rIndexTotalSize ? 0 : (i - m_rIndexRoadSize[0]);
referENum = (referSNum + m_rIndexRoadSize[1]) > m_rIndexTotalSize ? m_rIndexTotalSize : (referSNum + m_rIndexRoadSize[1]);
first = FALSE;
}
}
//위에서 구한 centerPos로 VB의 시작 번호를 구한다.
for( short i = m_virtualVBSize / 2; i < m_vbSizeZ-m_virtualVBSize/2; i++ )
{
for( short k = m_virtualVBSize / 2; k < m_vbSizeX-m_virtualVBSize/2; k++ )
{
WORD vbNum = i * m_vbSizeX + k;
DWORD cnt = 0;
m_ppTerVB[vbNum]->Lock( 0, 0, (void**)&pVertices, 0 );
for( WORD a = 0; a < 9; a++ )
{
for( WORD b = 0; b < 9; b++)
{
D3DXVECTOR3 tempV = pVertices[cnt++].v;
tempV.y = 0.0f;
if( tempV == centerPos )
{
sNum = i * m_vbSizeX + k;
}
}
}
m_ppTerVB[vbNum]->Unlock();
}
}
}
//이후의 로딩
else if( !first )
{
for( DWORD i = referSNum; i < referENum; i+=3 )
{
if( IntersectTriangle( m_pickOrig, m_pickDir,
m_pReferVB[m_pReferIB[i]], m_pReferVB[m_pReferIB[i+1]], m_pReferVB[m_pReferIB[i+2]],
&scale[0], &scale[1], &scale[2] ) )
{
m_pickPos = m_pickOrig + ( m_pickDir * scale[0] );
centerPos = m_pReferVB[m_pReferIB[(i%2 == 0) ? i+1 : i]] + D3DXVECTOR3( 1.0f, 0.0f, -1.0f);
referSNum = ((i - m_rIndexRoadSize[0])) > m_rIndexTotalSize ? 0 : (i - m_rIndexRoadSize[0]);
referENum = (referSNum + m_rIndexRoadSize[1]) > m_rIndexTotalSize ? m_rIndexTotalSize : (referSNum + m_rIndexRoadSize[1]);
break;
}
}
DWORD cnt = 0;
m_pCirVB->Lock(0, 0, (void**)&pCirVertices, 0 );
m_pTerIB->Lock(0, 0, (void**)&pIndices, 0 );
for( short i =0; i < m_virtualVBSize; i++ )
{
for( short k = 0; k < m_virtualVBSize; k++)
{
DWORD vbNum = sNum + ((m_vbSizeX) * i) + k - m_fixedVBPoint;
m_ppTerVB[vbNum]->Lock( 0, 0, (void**)&pVertices, 0 );
if( !intersect )
{
DWORD cnt = 0;
for( WORD a = 0; a < 9; a++ )
{
for( WORD b = 0; b < 9; b++)
{
D3DXVECTOR3 tempV = pVertices[cnt++].v;
tempV.y = 0.0f;
if( tempV == centerPos )
{
sNum = vbNum;
intersect = TRUE;
}
}
}
}
if( mouseMove )
{


//가상의 원의 위치와 VB의 삼각형이 픽킹을 하지는지 구해낸후
//실제 원의 y값을 증감 시킨다.
for( WORD m = 0; m < realIBTotalSize; m+=3 )
{
D3DXVECTOR3 tempV = pVertices[pIndices[m]].v;
tempV.y = 0.0f;
float checkLen = D3DXVec3LengthSq(&(tempV - m_pickPos));
if(checkLen < lenthMaxSize && checkLen > lenthMinSize)
{
for(short b = 0; b < m_cirTic; b++)
{
pCirVertices[b].v.x = m_pReferCir[b].x + m_pickPos.x;
pCirVertices[b].v.z = m_pReferCir[b].z + m_pickPos.z;
orig = pCirVertices[b].v;
orig.y = 1000.0f;
if(IntersectTriangle( orig, dir,
pVertices[pIndices[m]].v, pVertices[pIndices[m+1]].v, pVertices[pIndices[m+2]].v,
&scale[0], &scale[1], &scale[2]))
{
cnt++;
pCirVertices[b].v.y = (orig + dir * scale[0]).y+0.1f;
}
}
}
}
}
m_ppTerVB[vbNum]->Unlock();
}
}
m_pTerIB->Unlock();
m_pCirVB->Unlock();
}
if(intersect && LBT)
{
float checkRadius = ( m_radiusSize * m_intervalRate - 1.5f ) * (m_radiusSize * m_intervalRate - 1.5f); //원의 반지름보다 조금 작은값의 제곱
float checkSELine = m_realVBSize * 8.0f * m_intervalRate / 2.0f; //실제 VB의 총 길이
//픽킹된 VB의 vertex의 y값을 증감시킨다.
for( WORD i = 0; i < m_virtualVBSize; i++ )
{
for( WORD k = 0; k < m_virtualVBSize; k++)
{
DWORD vbNum = sNum + ((m_vbSizeX) * i) + k - m_fixedVBPoint;
m_ppTerVB[vbNum]->Lock(0, 0, (void**)&pVertices, 0);
for( WORD a = 0; a < 9; a++)
{
for( WORD b = 0; b < 9; b++)
{
WORD count = 9*a+b;
D3DXVECTOR3 checkV = pVertices[count].v;
checkV.y = 0.0f;
float d = D3DXVec3LengthSq(&(checkV - m_pickPos));
float r = checkRadius;
if( d < r && checkV.x > -checkSELine && checkV.x < checkSELine && checkV.z > -checkSELine && checkV.z < checkSELine)
{
float increaseY = sinf(D3DXToRadian( 90.0f - (90.0f * d / r) ) )*(m_increaseRate);
pVertices[count].v.y += increaseY;
}
}
}
m_ppTerVB[vbNum]->Unlock();
}
}
}
//vertex 초기화
if( RBT )
{
DWORD cnt = 0;
for( WORD i = 0; i < m_vbSizeZ; i++)
{
for( WORD k = 0; k < m_vbSizeX; k++)
{
m_ppTerVB[cnt]->Lock(0, 0, (void**)&pVertices, 0);
DWORD cnt2 = 0;
for( WORD a = 0; a < 9; a++ )
{
for(WORD b = 0; b < 9; b++)
{
pVertices[cnt2++].v.y = 0.0f;
}
}
m_ppTerVB[cnt++]->Unlock();
}
}
m_pCirVB->Lock( 0, 0, (void**)&pCirVertices, 0 );
for( WORD i = 0; i < m_cirTic; i++)
{
pCirVertices[i].v.y = 0.0f;
}
m_pCirVB->Unlock();
}
}

 

 

일반 메모리를 사용하여 픽킹된곳의 실제 좌표값을 얻어내어

VB의 배열을 탐색한 후 해당 VB의 실제 번호를 알아내고

픽킹된 좌표와 탐색한 vertex의 차백터한 백터의 크기가 반지름의 제곱에 크기보다 작은

vertex들의 y값을 증가시킨다.

 

차후에 카메라 클래스를 구현하여 맵툴에 적용시킨후

다른 세부사항을 추가할 계획이다.