블로그 이미지
Every unexpected event is a path to learning for you.

카테고리

분류 전체보기 (2731)
Unity3D (814)
Programming (474)
Server (33)
Unreal (4)
Gamebryo (56)
Effect (10)
Lecture (15)
Shader (8)
Learn (6)
Shoveling (3)
Bug Report (2)
3DS Max (8)
Tip & Tech (228)
협업 (57)
3DS Max (3)
Game (12)
Utility (136)
Etc (96)
Link (32)
Portfolio (19)
Subject (90)
iOS,OSX (51)
Android (14)
Linux (5)
잉여 프로젝트 (2)
게임이야기 (3)
Memories (20)
Interest (38)
Thinking (38)
한글 (30)
PaperCraft (5)
Animation (408)
Wallpaper (2)
재테크 (18)
Exercise (3)
나만의 맛집 (3)
냥이 (10)
육아 (16)
Total
Today
Yesterday
03-28 00:02

스텐실 버퍼

stencil buffer는 특수한 효과를 위한 off-screen buffer로, back buffer 및 depth buffer와 동일한 해상도를 가진다. 따라서, stencil buffer 내의 (i, j)번째 픽셀은 back/depth buffer의 (i, j)번째 픽셀과 대응된다.

이름이 의미하는 것 처럼 stencil buffer는 back buffer의 일정 부분이 렌더링되는 것을 막는 효과를 위해 사용된다. 예를 들어, 거울에 특정 물체를 반사하도록 할려고 한다면, 거울에 반사되는 부분에 대해서만 드로잉을 수행하면 된다. 이 때 거울에 비치지 않는 부분은 렌더링되는 것을 막을 수 있는 있도록 하는 것이 바로 stencil buffer다.

 

다음과 같은 곳에 활용할 수 있다.

- 거울에 비치는 물체를 그릴때

- Shadow volume 을 이용한 그림자 렌더링

- 기타 다양한 마스킹( FPS 저격 줌인? )

 

기초 지식

렌더링 테스트의 순서 : 스텐실 테스트 -> Z-Test

 

 

In 게임브리오(StencilShadow.cpp)

 

NiStencilPropertyPtr spStencil = NiNew NiStencilProperty;
spStencil->SetStencilOn(true);

// 스텐실 테스트는 항상 통과하도록함
spStencil->SetStencilFunction(NiStencilProperty::TEST_ALWAYS);

// 스텐실 테스트에 실패해서 아무것도 그려지지 않게 생겼을 경우...
spStencil->SetStencilFailAction(NiStencilProperty::ACTION_KEEP);

// 스텐실 테스트와 Z-Test 모두 통과 했을 경우...
spStencil->SetStencilPassAction(NiStencilProperty::ACTION_INCREMENT);

// 스텐실 테스트는 통과했으나, Z-Test에서 통과하지 못했을 경우...
spStencil->SetStencilPassZFailAction(NiStencilProperty::ACTION_KEEP);

// 양면을 모두 그리도록..
spStencil->SetDrawMode(NiStencilProperty::DRAW_BOTH);
spShaft->AttachProperty(spStencil);

 

위에서 보면.. Stencil을 통과했다라는 말이.. Stencil + Z-Test 통과라는 것을 알 수 있다.

 

볼륨쉐도우

 

자세한 방법은 네이버씨에게 물어보거나, 아니면 책을 보면 쉽게 이해할 수 있다.

 

볼륨 쉐도우는

 

단순하고 정적인 Blocker가

 

복잡한 형태의 혹은 애니매이션 되는 대상에게 그림자를 드리울 때, 사용하면 가장 좋다!

 

왜? 볼륨쉐도우니까... 공부합시다!

[출처]
 Stencil buffer 사용하기|작성자 프라이드

반응형

'Gamebryo > Lecture' 카테고리의 다른 글

Mesh 만들기  (0) 2011.11.08
Mesh의 생성 ( Particle, 검궤적 등 )  (0) 2011.11.08
게임브리오 2D Line관련  (0) 2011.10.30
FrameRenderSystem에서.. 커스텀알파소터프로세스..  (0) 2011.09.18
무기잔상효과  (0) 2011.02.08
Posted by blueasa
, |

Mesh 만들기

Gamebryo/Lecture / 2011. 11. 8. 15:09

MeshData 제작

 

StencilShadow와 Eturnum 샘플을 보면 Mesh를 프로그램에서 만들어 내는 방법을 배울 수 있다.

 

( Eturnum의 Swoosh.cpp, StencilShadow의 StencilShadow.cpp )

 

아무래도 StencilShadow의 코드가 보기에 더 익숙하고 쉽게 보인다.

 

하지만, Eturnum 의 Mesh는 매 프레임 바뀌는 Mesh에 더 빠른 코드인것 같다.

 

자세한 내용은 두 개의 샘플을 열어보자.

 

Bound 설정

 

Gamebryo는 Camera culling을 기본적으로 행하고 있기때문에

 

Mesh를 만들면 반드시 WorldBound를 업데이트 시켜줘야 한다.

 

두 가지 함수를 통해서 할 수 있는데..

 

1 번 방식 ( Eturnum의 Swoosh.cpp )

----------------------------------------

NiBound kBound;
kBound.SetCenter(0.0f, 0.0f, 0.0f);
kBound.SetRadius(10000.0f);
m_pkMesh->SetModelBound(kBound);

 

2 번 방식 ( StencilShadow의 StencilShadow.cpp )

----------------------------------------

spSideWall->RecomputeBounds();

 

2 번 방식이 더 정확하고 편해보인다. 다만 계산이 조금 들어간다는게 단점이다. ( 요즘 CPU가 얼마나 빠른데... )

 

노말 설정

 

이 외에도 DirectX의 CalcNormal과 같은 Normal을 계산해주는 함수도 있다. ( StencilShadow의 StencilShadow.cpp )

 

NiMeshUtilities::CalculateNormals( spSideWall,
NiCommonSemantics::POSITION(), 0, NiCommonSemantics::NORMAL(), 0,
NiDataStream::ACCESS_CPU_READ | NiDataStream::ACCESS_GPU_READ |
NiDataStream::ACCESS_CPU_WRITE_STATIC );

[출처]
 Mesh 만들기|작성자 프라이드

반응형

'Gamebryo > Lecture' 카테고리의 다른 글

Stencil buffer 사용하기  (0) 2011.11.08
Mesh의 생성 ( Particle, 검궤적 등 )  (0) 2011.11.08
게임브리오 2D Line관련  (0) 2011.10.30
FrameRenderSystem에서.. 커스텀알파소터프로세스..  (0) 2011.09.18
무기잔상효과  (0) 2011.02.08
Posted by blueasa
, |

매 프레임마다 메쉬를 업데이트 해야하는 경우가 있을 경우...

 

void Update()

{

spMesh = NiNew NiMesh();

}

라는 식으로 코딩을 해서는 안된다.

 

NiNew 가 많이 느리고, 새롭게 만든 Mesh에 새로운 DataStream을 생성 해야하므로, 속도가 많이 느려지게 된다.

 

그것을 피하는 방법은 다음과 같다.

 

1. 최초 한번만 불리는 부분에서 Mesh를 생성

2. DataStream을 적당한 사이즈로 준비한다. 100개의 폴리곤 정도라면, Vertex = 3 * Poly, Index = 3 * Poly 정도로 만들면 충분함.

   ( 사용할 PrimitiveType 별로, 적당히 넣어주면 될 듯 )

3. 매 프레임 DataStream 을 Lock하여 데이터를 넣어주고,

4. DataStream의 SetRegion함수를 이용하여, 사용할 양을 지정해준다.

   ex >  kPositionLock.GetDataStream()->SetRegion( NiDataStream::Region(0,(NiUInt32)vecVertices.size()*iCount), 0 );

 

샘플에도 있는 코드지만, 의외로 아무 생각없이 만드는 경우가 있어서 ^_^;;

[출처]
 Mesh의 생성 ( Particle, 검궤적 등 )|작성자 프라이드

반응형

'Gamebryo > Lecture' 카테고리의 다른 글

Stencil buffer 사용하기  (0) 2011.11.08
Mesh 만들기  (0) 2011.11.08
게임브리오 2D Line관련  (0) 2011.10.30
FrameRenderSystem에서.. 커스텀알파소터프로세스..  (0) 2011.09.18
무기잔상효과  (0) 2011.02.08
Posted by blueasa
, |

출처 : http://cafe.naver.com/dxgameprogramming/1752


NiLine 클래스는 2.6부터 사라져서 저도 라인 만들 때 NiMesh를 써서 만들었습니다. path에서 waypoint들 나올테니 나온 좌표들 가지고 벡터에 넣어서 그리시면 될겁니다.

 

TestMakeLine(const NiPoint3 & kStartPos, const NiPoint3 & kEndPos)

{

NiMesh * pkWaypointLine = NiNew NiMesh; 
 pkWaypointLine->SetPrimitiveType(NiPrimitiveType::PRIMITIVE_LINES);

 NiUInt8 uiAccessMask = NiDataStream::ACCESS_CPU_READ | 
  NiDataStream::ACCESS_CPU_WRITE_MUTABLE | NiDataStream::ACCESS_GPU_READ;

 NiDataStreamRef* pkPositionRef = pkWaypointLine->AddStream(
  NiCommonSemantics::POSITION(), 0, NiDataStreamElement::F_FLOAT32_3, 
  4, uiAccessMask, NiDataStream::USAGE_VERTEX);
 NIASSERT(pkPositionRef);

 NiDataStreamRef* pkIndexRef = pkWaypointLine->AddStream(
  NiCommonSemantics::INDEX(), 0, NiDataStreamElement::F_UINT16_1, 
  4, uiAccessMask, NiDataStream::USAGE_VERTEX_INDEX);
 NIASSERT(pkIndexRef);

 NiDataStream * pkPositionStream = pkPositionRef->GetDataStream();
 NiDataStream * pkIndexStream = pkIndexRef->GetDataStream();

 pkPositionStream->GetRegion(0).SetRange(0);
 pkIndexStream->GetRegion(0).SetRange(0);

 NiDataStreamElementLock kPositionsLock = NiDataStreamElementLock(
  pkWaypointLine, NiCommonSemantics::POSITION(), 0,
  NiDataStreamElement::F_FLOAT32_3);
 NIASSERT(kPositionsLock.IsLocked());

 NiDataStreamElementLock kIndicesLock = NiDataStreamElementLock(
  pkWaypointLine, NiCommonSemantics::INDEX(), 0,
  NiDataStreamElement::F_UINT16_1);
 NIASSERT(kIndicesLock.IsLocked());

 NiTStridedRandomAccessIterator<NiPoint3> kPositionsIter = 
  kPositionsLock.begin<NiPoint3>();

 NiTStridedRandomAccessIterator<NiUInt16> kIndicesIter = 
  kIndicesLock.begin<NiUInt16>();

 kPositionsIter[0] = kStartPos;
 kIndicesIter[0] = 0;

 kPositionsIter[1] = kEndPos;
 kIndicesIter[1] = 1;

 pkPositionStream->GetRegion(0).SetRange(2);
 pkIndexStream->GetRegion(0).SetRange(2);

 NiVertexColorProperty* pkVC = NiNew NiVertexColorProperty;
 pkVC->SetSourceMode(NiVertexColorProperty::SOURCE_IGNORE);
 pkVC->SetLightingMode(NiVertexColorProperty::LIGHTING_E);
 pkWaypointLine->AttachProperty(pkVC);

 NiMaterialProperty* pkMat = NiNew NiMaterialProperty;
 pkMat->SetEmittance(NiColor(0.0f, 0.0f, 1.0f));
 pkMat->SetAlpha(1.0f);
 pkWaypointLine->AttachProperty(pkMat);

 pkWaypointLine->RecomputeBounds();
 pkWaypointLine->UpdateProperties(); 
 pkWaypointLine->Update(0);

 g_vWaypointLine.push_back(pkWaypointLine);

}

 

저는 2.6에서 위와 같은 방법으로 검출된 path 연결해서 쓰고 있습니다.

반응형

'Gamebryo > Lecture' 카테고리의 다른 글

Mesh 만들기  (0) 2011.11.08
Mesh의 생성 ( Particle, 검궤적 등 )  (0) 2011.11.08
FrameRenderSystem에서.. 커스텀알파소터프로세스..  (0) 2011.09.18
무기잔상효과  (0) 2011.02.08
캐릭터 기울기 연산  (0) 2011.02.08
Posted by blueasa
, |

겜브리오의 Frame Render Sytstem 에서는 랜더클릭별로 알파프로세스를 지정해 줄 수 있다.

구조를 설명하자면.. 각 Mesh들은 랜더클릭의 랜더링 함수가 호출될때 클릭별로 설정된 CullingProcess에 의하여 보여지는 영역들에 대한 메쉬들의 집합을 구한다. 이 RenderObject들의 리스트(NiVisibleArray)를 가지고 랜더링을 하게되는데 이것은 SceneGraph상의 순서(생성순, 노드어태치순)으로 일괄적으로 랜더링되며 AssetViewer나 NiApplication에서는 NiAlphaSortProcessor를 사용한다. 이것을 연결하지 않을시 디폴트로된 기본 솔트프로세스가 연결되어지는데 이건 그냥 순서대로 그리는것이다.

NiAlphaSortProcessor를 보면 NiBackToFrontSortProcessor를 상속하게 되는데 위에 불투명한랜더링객체(알파가 없는, NiSortedAdjustNOde가 적용된)를 우선적으로 그리고, 알파가 있는 랜더링 객체를 기본적으로 Mesh의 피봇중심(BoundCenter)과 카메라와의 거리(ZBuffer)을 이용하여 뒤에서부터 앞으로 정렬하여 나온 NiVisibleArray의 내용을 그린다.

하지만 위와같은 랜더링시 문제점도 있어서

1) 알파텍스쳐가 쓰인 큰오브젝트(폭포, 스카이박스)의 경우 폭포의 피봇중심과 그 폭포앞의 오브젝트들(폭포앞물튐파티클등)이 서로 카메라의 위치에 따라 혹은 폭포와 스카이박스피봇와의 거리차등..의 문제로 인해서 앞뒤판정이 실제와 차이나게 생길수있고

2) 알파를 적용한 빌보드와 파티클이 같이 나오는 경우 파티클이 뒤에서 빌보드를 통과한다거나 앞에서 뒤로 빌보드를 통과 하거나 혹은 빌보드와 근접시.. 카메라의 위치에 따라 잘못판단되는 경우가 생길수있다.
예) 두장의 알파빌보드를 근접하여 놓았을경우 카메라 방향에 따라 앞뒤면이 잘못 나올수있다.

3) NiSortAdjustNode를 썼을 경우에도 불투명 오브젝트로 처리하게 되니 만약 NiSortAdJustNode 뒤에 불투명한 오브젝트가 있고 그것이 나중에 랜더링 된다면 이 NiSortAdjustNode를 쓴 알파오브젝트에는 실제로 뒤에 오브젝트가 나오지 않게 될 것이다.
예) NiSortAdjustNode를 쓴 폭포뒤에 불투명한 동굴이 있다고 쳤을때 실제로 어태치된 순서가 동굴이
나중에 어태치 되어있다면 동굴은 폭포수에 그려지지 않을 것이다.

위와 같은 문제를 해결하기 위해선 디자이너들이 알파에 대한 정렬 프로세스를 확실히 이해 한 상태에서 작업을 해야 한다는것이다.

파티클이나 빌보드의 경우 겹쳐저도 상관없는 경우 ZTest만 하고 ZWrite는 하지 않게 하여 (Zmode10), 테스트를 하여 투명우산 앞에 그릴지 뒤에 그릴지를 판단하고 그려질땐 Zbuffer를 쓰지 않아 같은 파티클의 경우 섞이게 만들고. 넓은 반투명 빌보드의 겹침현상은 기본적으로 두개의 오브젝트의 피봇중심이 가까워서 일어나는 현상임으로 이런경우는 실제피봇중심만 거리를 두게끔 처리함으로서 해결할수 있을 것이다. 이렇게 되어도 카메라의 거리에 따라 문제가 생길수 있는 부분은 존재하는데 확실히 랜더링 순서를 알고있는 메쉬집합체의 경우 깊이를 쓰는 부분에서 순서대로 깊이를 판단해서 NiVisibleArray에 넣어 주어 랜더링 하는 방법이 있는데

나의 경우에는 디자이너와 협의하여 순서를 확실히 아는 오브젝의 경우 Aset_이라는 이름으로 판단하였다.

아래는 사용중인 CustomAlphaSortProcessor 의 핵심 부분이다.


void NiCustomAlphaSortProcessor::PreRenderProcessList(const NiVisibleArray* pkInput, NiVisibleArray& kOutput, void* pvExtraData)
{
if (!pkInput) return;

NiRenderer* pkRenderer = NiRenderer::GetRenderer();
NIASSERT(pkRenderer);

NiPoint3 kWorldLoc, kWorldDir, kWorldUp, kWorldRight;
NiFrustum kFrustum;
NiRect<float> kViewport;
pkRenderer->GetCameraData(kWorldLoc, kWorldDir, kWorldUp, kWorldRight,
kFrustum, kViewport);

const unsigned int uiInputCount = pkInput->GetCount();

if (m_uiAllocatedDepths < uiInputCount)
{
NiFree(m_pfDepths);
m_pfDepths = NiAlloc(float, uiInputCount);
m_uiAllocatedDepths = uiInputCount;
}


NiSortedObjectList kItems0;

unsigned int uiDepthIndex = 0;

bool bSet = false;
float f;
for (unsigned int ui = 0; ui < uiInputCount; ui++)
{
NiRenderObject& kMesh = pkInput->GetAt(ui);

// NiSortAdjustNode인 경우
if( !kMesh.GetSortObject() ) // NiSortAdjustNode는 알파로 처리하되.. 알파보다는 먼저 랜더링 되게 변경.
{
kItems0.AddTail(&kMesh);
}
else if (IsTransparent( kMesh ) )
{
NiNode * pkParent = kMesh.GetParent();
NiFixedString name = kMesh.GetName();
if( name.Contains("Aset_") || ( pkParent && pkParent->GetName().Contains("Aset_") ) )
{
kOutput.Add(kMesh);

if( bSet == false )
{
f = ComputeDepth(kMesh, kWorldDir);
m_pfDepths[uiDepthIndex++] = f;
}
else
{
f = f-0.1f;
m_pfDepths[uiDepthIndex++] = f;
}

bSet = true;
}
else
{
bSet = false;
kOutput.Add(kMesh);
m_pfDepths[uiDepthIndex++] = ComputeDepth(kMesh, kWorldDir);
}


}
else
{
// 불투명한 오브젝트는 바로그린다. (NoSort 포함);
NiAVObject* pkAVObj = &kMesh;
if (NiIsKindOf(NiRenderObject, pkAVObj))
{
// FOutputLOG( (char *)(const char *) kMesh.GetName() );
kMesh.RenderImmediate(pkRenderer);
}

}

}

// NiSortAdjustNode는 불투명랜더링이 끝나면 이것도 바로 랜더링
while (kItems0.GetSize())
{
NiRenderObject* pkGeom = kItems0.RemoveHead();
pkGeom->RenderImmediate(pkRenderer);
}

//

SortObjectsByDepth(kOutput, 0, kOutput.GetCount() - 1);

/* // 로그를 남겨보자..
FOutputLOG("====알파만 걸러서 순서가 어뜨케 되나..=====================");
for(int i = 0; i<kOutput.GetCount(); i++)
{
NiRenderObject& kMesh = kOutput.GetAt(i);
FOutputLOG((char*)(const char*)kMesh.GetName());
}
*/


}

반응형

'Gamebryo > Lecture' 카테고리의 다른 글

Mesh의 생성 ( Particle, 검궤적 등 )  (0) 2011.11.08
게임브리오 2D Line관련  (0) 2011.10.30
무기잔상효과  (0) 2011.02.08
캐릭터 기울기 연산  (0) 2011.02.08
Gamebryo 셋팅  (1) 2011.01.06
Posted by blueasa
, |

무기잔상효과

Gamebryo/Lecture / 2011. 2. 8. 17:05

무기의 잔상효과를 구현하기위해서는 실시간으로 무기가 움직이는 월드상에

폴리곤을 만들어주고 텍스쳐 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/무기잔상효과

반응형

'Gamebryo > Lecture' 카테고리의 다른 글

게임브리오 2D Line관련  (0) 2011.10.30
FrameRenderSystem에서.. 커스텀알파소터프로세스..  (0) 2011.09.18
캐릭터 기울기 연산  (0) 2011.02.08
Gamebryo 셋팅  (1) 2011.01.06
게임브리오 강좌(?) 링크  (3) 2010.04.14
Posted by blueasa
, |
필요한 경우는 아래와 같다.
1. 2족 캐릭터가 지형의 경사면에서 죽는 애니메이션.
2. 4족 이상 동물의 지형 경사면 이동.


일단 캐릭터가 서있는 지형에대한 노멀벡터를 알아야한다.
자신의 위치에서 바닥으로 피킹을 해서 얻으면 된다.
캐릭터의 크기가 바닥 그리드에 비해 크다면 캐릭터의 크기에 맞게 삼각형 형태의
3정점에서 피킹을하여 얻어지는 평면의 노멀값을 계산하여 사용하도록 하자.

1. 현재 캐릭터 위치에서 지형으로 피킹을 한다.
2. 피킹으로 얻어진 노멀 벡터와 Z축 벡터를 이용하여 회전행렬을 구한다.
3. 캐릭터의 회전값에 적용한다.


ex)
// 원래 벡터 srcVec, 변환후 벡터 destVec, 회전축 벡터 axisVec
// axisVec = srcVec x destVec                                               // 회전축 벡터
// angle = acos( srcVec * destVec / |srcVec| |destVec| )       // 회전각


// m_spCharRootNode 캐릭터 루트 노드
// m_kPickNormal 현재 위치에대한 노멀 벡터
NiMatrix3 r_kRot;
NiPoint3 r_kAxis = m_kPickNormal.Cross( NiPoint3(0.0f, 0.0f, 1.0f) );
float r_fDot = m_kPickNormal.Dot( NiPoint3(0.0f, 0.0f, 1.0f) );
float r_fRadian = NiACos( r_fDot );
r_kRot.MakeRotation( r_fRadian, r_kAxis );
m_spCharRootNode->SetRotate( r_kRot );


주의사항 : 루트노드를 카메라 회전및 기타 다른용도에
사용되고 있다면 위 코드는 정상적으로 구현되지 않을 수 있습니다.
이럴 경우 노멀벡터값을 루트노드회전행렬과 곱한값을 사용하면 해결 될 수 있습니다.
 
반응형

'Gamebryo > Lecture' 카테고리의 다른 글

FrameRenderSystem에서.. 커스텀알파소터프로세스..  (0) 2011.09.18
무기잔상효과  (0) 2011.02.08
Gamebryo 셋팅  (1) 2011.01.06
게임브리오 강좌(?) 링크  (3) 2010.04.14
Gamebryo 2.5  (0) 2010.04.12
Posted by blueasa
, |

Gamebryo 셋팅

Gamebryo/Lecture / 2011. 1. 6. 20:45

*게임브리오 설치 전에 VS 2005를 사용시 반드시 서비스팩1를 설치 

(매니패스트 관련 에러가 난다면 버그로 인해 재배포가 안되어서 에러가 나는 것이므로 꼭 패치해야 한다.)

- 추가 라이브러리

NiMesh.lib NiApplication.lib NiSystem.lib NiMain.lib NiInput.lib NiFloodgate.lib NiDx9Renderer.lib NiAnimation.lib

 

*시작

1. Win32API Project로 생성 3DProject로 설정 (빈프로젝트 생성)

2. 클래스 추가->c++클래스 추가 -> base class에 NiApplication등록-> classname은 CGameApplication

3. #include "NiApplication.h" 추가 // 게임브리오 프레임워크

4. 프로젝트 속성 -> 문자집합을 '유니코드' 설정되어 있는것을-> '설정안함'으로 설정

 

 

5. 프로젝트 속성 -> C/C++ -> 64비트 이식성 문제점 검색 -> '아니오' 설정

 

 

6. C/C++ -> 추가포함 디렉터리 -> 자신이 설치한 include폴더로 지정

7. C/C++ -> 전처리기 -> 전처리기 정의 ->WIN32;_DEBUG;_WINDOWS;NIDEBUG;STRICT 추가 

8. 링커 -> 추가라이브러리 디렉터리 -> 자신이 설치한 debuglib폴더로 지정

9. 링커 -> 입력 -> 추가 종속성 -> 위의 추가라이브러리 설정

   NiMesh.lib (메쉬), NiApplication.lib(프레임워크), NiSystem.lib(게임브리오 전반적 시스템), NiFloodgate.lib(Util),

   NiMain.lib(Base), NiInput.lib(input), NiDx9Render.lib(D3D9)

 

10. 도움말 확인

 

 

 이것을 생성한 class에 추가

11. 게임브리오 라이센스를 선언해 주어야 한다.

 #include <NiLicense.h>
NiEmbedGamebryoLicenseCode;

12. 생성한 NiApplication NiApplication::Create()에

     return NiNew CGameApplication; 으로 추가

     NiApplication* NiApplication::Create()
    {
    /*
     new -> NiNew
     delete -> NiDelete
    */
     return NiNew CGameApplication; 
     }

13. 생성한 클래스의 생성자에게 : NiApplication 생성자 추가후

    CGameApplication::CGameApplication(void)
    : NiApplication("Game ver 0.1", DEF_SCREEN_WIDTH, DEF_SCREEN_HEIGHT)

 

* 잠시! 헤더에 대한 설명

NiApplication.h

: public NiMemObject 가 하고 있다. -> 게임브리오가 질접적으로 메모리를 관리하기 위해 사용되고 있는 것

NiRefObject.h

: 참조를 관리해주는 것으로 이것을 상속받고 있는건 참조에 따라 자동삭제를 하기 위해서임(게임브리오에서 쓰는 스마트포인터 같은..)

NiMeshScreenElements.h

: 2D관련해서 작성할 때 추가

NiMesh.h

: 3D관련

 

*슈핑모드 만들기

1. 구성관리자 -> 새로만들기

 

2. 새 솔루션 구성

 

3. 전행처리기

 

4. lib폴더를 shipping으로 추가

 

5. 헤더는 기본헤더로

 

=> shipping모드는 debug 모드보다 더 가볍다.

 

* 직접 초기화 하기(Dx Device Create)

 

 

직접 초기화 하기 위해 CreateRender() 함수를 상속받아와서 아래 코드를 작성한다.

bool CGameApplication:::CreateRenderer()
{
 unsigned int uiWidth = m_pkAppWindow->GetWidth();
 unsigned int uiHeight = m_pkAppWindow->GetHeight();

 m_spRenderer = NiDX9Renderer::Create(uiWidth, uiHeight,
  NiDX9Renderer::USE_NOFLAGS, GetWindowReference(), 
  GetRenderWindowReference());

 if (m_spRenderer == NULL)
 {
  NiMessageBox("Unable to create a renderer!", "Renderer Failure!");
  QuitApplication();
  return false;
 }
 return true;
}

단, #include <NiDX9Render.h>를 추가해야 한다.

이렇게 하면 앞에서 한 예제와 다르게 다이어로그가 뜨면서 어떤 형식으로 실행할 것인지 물어보지 않는다.

왜냐하면 직접 DX로 한다고 선언했기 때문에..

- 다이어로그 뜰때

 

* 중요한 m_spRendere!

DX 디바이스 가져오기

//--직접적으로DirectX를제어하고싶을때

             NiRenderer* renderer = m_spRenderer;

             NiDX9Renderer* pDX9Renderer  = ((NiDX9Renderer*)renderer);

             LPDIRECT3DDEVICE9 pp =pDX9Renderer->GetD3DDevice();

 

-> 스마트 포인터 때문에 NiRenderer* 포인터로 한번 받아온다.


출처 : http://blog.naver.com/fantaldh/40067964992

[출처] Gamebryo 셋팅|작성자 대봉이

반응형

'Gamebryo > Lecture' 카테고리의 다른 글

무기잔상효과  (0) 2011.02.08
캐릭터 기울기 연산  (0) 2011.02.08
게임브리오 강좌(?) 링크  (3) 2010.04.14
Gamebryo 2.5  (0) 2010.04.12
[링크] 게임브리오 강좌  (0) 2010.04.10
Posted by blueasa
, |
반응형

'Gamebryo > Lecture' 카테고리의 다른 글

캐릭터 기울기 연산  (0) 2011.02.08
Gamebryo 셋팅  (1) 2011.01.06
Gamebryo 2.5  (0) 2010.04.12
[링크] 게임브리오 강좌  (0) 2010.04.10
게임브리오 초기 설정(vs2005)  (0) 2010.04.07
Posted by blueasa
, |

Gamebryo 2.5

Gamebryo/Lecture / 2010. 4. 12. 14:17
반응형

'Gamebryo > Lecture' 카테고리의 다른 글

Gamebryo 셋팅  (1) 2011.01.06
게임브리오 강좌(?) 링크  (3) 2010.04.14
[링크] 게임브리오 강좌  (0) 2010.04.10
게임브리오 초기 설정(vs2005)  (0) 2010.04.07
Gamebryo  (0) 2010.04.07
Posted by blueasa
, |