※ 무기의 잔상효과를 구현하기위해서는 실시간으로 무기가 움직이는 월드상에
폴리곤을 만들어주고 텍스쳐 uv또한 실시간으로 할당해
주어야한다.
또한, 낮은 프레임에서도 부드러운 형태로 폴리곤을 만드려면
셈플링하는 무기의
위치에 대하여 보간처리를 해야한다.
여기서는 동적으로 폴리곤을 생성하고 사용될 텍스쳐의
uv를 결정해주는 방법을 살펴보도록 한다.
스플라인 보간처리부분은 직접 해보세요.
※ 무기에 필요한 정보
☞ 무기의 잔상효과가 적용될 시작지점과 끝점에 더미를 추가하도록한다.
☞ 더미이름은 *point1,*point2라고 칭한다.
※ 구현 순서
1. 더미이름으로 각 더미노드 포인터를 찾아
저장해놓는다.
2. 매 프레임마다 더미노드의 변경된 좌표에 대하여 폴리곤을
생성한다.
3. 정해진
출력시간을 초과하면 해당 정보를 리스트에서 제거한다.
4.
일정 비율로 시간이 지남에따라 폴리곤 크기를 줄여준다.
5.
생성된 폴리곤에 대하여 텍스쳐 uv를 할당한다.
struct
AIPoint
{
float
m_fStartTime; // 폴리곤을 생성할 때 현재 시간을 저장한다.
NiPoint3 m_kPoint[2]; // 생성될때 더미노드 월드좌표를 저장한다.
};
typedef std::vector<AIPoint>
VAIPOINT;
typedef
VAIPOINT::iterator
VAIPOINT_ITER;
VAIPOINT m_vAIPointList; // 더미노드 리스트
NiTriShapePtr m_spAIGeometry; // 동적으로 만들어진 지오메트리
NiAVObject* m_pkPointNode[2]; // 잔상이 적용될 노드포인터
float m_fLifeTime; // 폴리곤이 출력되는 시간
※ 매
프레임마다 더미의 월드좌표와 시간정보를 리스트에 추가한다.
실제 제작시에는 변화가있을때만 추가해야할 것이다. 또는 특정 애니메이션에서만 추가되도록 작성해야한다.
AIPoint r_kAIPoint;
r_kAIPoint.m_fStartTime = p_fTime;
r_kAIPoint.m_kPoint[0] =
m_pkPointNode[0]->GetWorldTranslate();
r_kAIPoint.m_kPoint[1] =
m_pkPointNode[1]->GetWorldTranslate();
m_vAIPointList.push_back( r_kAIPoint
);
※
매프레임마다 *point2더미 위치를 *point1
더미위치방향으로 줄어들게 한다.
또한 출력시간이
지났다면 해당 AIPoint
객체를
리스트에서 제거하도록 한다.
if( m_vAIPointList.empty() )
return;
VAIPOINT_ITER r_iter;
for( r_iter = m_vAIPointList.begin(); r_iter != m_vAIPointList.end();
)
{
float r_fElapsedTime = p_fTime -
r_iter->m_fStartTime;
if( r_fElapsedTime > m_fLifeTime )
{
r_iter = m_vAIPointList.erase( r_iter
);
}
else
{
NiPoint3 r_kDirVec =
( r_iter->m_kPoint[0] - r_iter->m_kPoint[1]
);
float r_fLength =
r_kDirVec.Length();
if ( r_fLength > 0.0f
)
{
NiPoint3::UnitizeVector( r_kDirVec
);
float fAmount = r_fLength / ( m_fLifeTime * 10.0f
);
r_kDirVec *=
fAmount;
r_iter->m_kPoint[1] +=
r_kDirVec;
}
++r_iter;
}
}
※ 주어진 리스트를 이용하여
동적으로 폴리곤과 uv좌표정보를 갱신한다.
unsigned short r_usAIPointCount =
m_vAIPointList.size();
// 최소한 3개이상이어야 정상적인 메쉬를 만들 수
있다
if (
r_usAIPointCount <= 2 )
return;
unsigned short r_usVertices
= r_usAIPointCount * 2;
unsigned short r_usTriangles = ( r_usAIPointCount - 1 ) *
2;
unsigned short* r_pusTriList =
NULL;
NiPoint3* r_pkVerts = NiNew NiPoint3[ r_usVertices
];
NiPoint2* r_pkTexture = NiNew NiPoint2[ r_usVertices
];
if ( r_usTriangles )
{
r_pusTriList = (unsigned short*)NiMalloc(
sizeof(unsigned short) * ( 3 * r_usTriangles )
);
}
for( int r_i = 0; r_i < r_usAIPointCount; ++r_i
)
{
int r_nNum = r_i * 2;
r_pkVerts[r_nNum] =
m_vAIPointList[r_i].m_kPoint[0];
r_pkVerts[r_nNum + 1] =
m_vAIPointList[r_i].m_kPoint[1];
if( 0 == r_i )
{
r_pkTexture[0] = NiPoint2( 0.0f, 0.0f
);
r_pkTexture[1] = NiPoint2( 1.0f, 0.0f
);
}
else
{
float r_uv = (float)( r_i ) / (float)( r_usAIPointCount - 1
);
r_pkTexture[r_nNum] =
NiPoint2( 0.0f, r_uv );
r_pkTexture[r_nNum + 1] = NiPoint2( 1.0f, r_uv
);
int r_nIndex = ( r_i - 1 ) *
6;
int r_nFactor = ( r_i - 1 ) * 2;
r_pusTriList[r_nIndex + 0] = 0 +
r_nFactor;
r_pusTriList[r_nIndex + 1] = 1 +
r_nFactor;
r_pusTriList[r_nIndex + 2] = 2 +
r_nFactor;
r_pusTriList[r_nIndex + 3] = 2 +
r_nFactor;
r_pusTriList[r_nIndex + 4] = 1 +
r_nFactor;
r_pusTriList[r_nIndex + 5] = 3 +
r_nFactor;
}
}
NiGeometryData* r_pkGeomData =
m_spAIGeometry->GetModelData();
NiTriShapeData* r_pkTriShape =
(NiTriShapeData*)r_pkGeomData;
r_pkGeomData->Replace(
r_usVertices,
r_pkVerts,
0,
// Normal
0,
// Color
r_pkTexture,
1,
// TextureSets
NiGeometryData::NBT_METHOD_NONE );
// Normal Binormal Tangent
Method
r_pkTriShape->Replace( r_usTriangles, r_pusTriList
);
r_pkGeomData->MarkAsChanged (
NiGeometryData::VERTEX_MASK |
NiGeometryData::TEXTURE_MASK |
NiTriBasedGeomData::TRIANGLE_INDEX_MASK
|
NiTriBasedGeomData::TRIANGLE_COUNT_MASK
);
// Perform initial update.
m_spAIGeometry->Update(0.0f);
m_spAIGeometry->UpdateProperties();
m_spAIGeometry->UpdateEffects();
m_spAIGeometry->UpdateNodeBound();
-> URL : http://clodymade.tistory.com/entry/무기잔상효과