제 14 장 파티클 시스템
파티클 시스템 목 표 파티클에 부여할 수 있는 속성들에 대해 배우고 Direct3D 에서 파티클을 표현하는 방법을 확인 목 표 파티클에 부여할 수 있는 속성들에 대해 배우고 Direct3D 에서 파티클을 표현하는 방법을 확인 범용적 이용 가능한 속성과 메서드를 포함하는 유연한 파티클 시스템 기반 클래스 디자인 세 가지의 전형적인 파티클 시스템인 눈, 폭발, 입자총 구현 2010-1학기 컴퓨터게임(DirectX)
파티클과 포인트 스프라이트 파티클은 매우 작은 물체이며 일반적으로 하나의 포인트로 모델링됨 포인트 기본형: D3DPRIMITIVETYPE의 D3DPT_POINTLIST 포인트스프라이트: 포인트 기본형과는 달리 텍스처 적용이 가능하고 크기를 변경할 수 있고, 하나의 포인트로 표현할 수 있다. 구조체 포맷 파티클의 위치와 컬러를 표현 struct Particle { D3DXVECTOR3 _position; D3DCOLOR _color; static const DWORD FVF; }; const DWORD Particle::FVF = D3DFVF_XYZ | D3DFVF_DIFFUSE; 2010-1학기 컴퓨터게임(DirectX)
파티클 구조체는 간단히 파티클의 위치와 컬러만을 저장하지만, 애플리케이션의 필요에 따라 텍스처 좌표 세트를 저장할 수 있음. Particle 구조체에 하나의 부동 소수점 변수를 추가하면 파티클의 크기를 지정할 수 있다. D3DFVF_PSIZE 플래그를 FVF포맷에 추가해야 함 파티클이 각자의 크기를 관리하도록 하면 각각의 파티클의 크기를 직접 바꿀 수 있다. 대부분의 그래픽 카드에서는 파티클의 크기 제어를 지원하지 않으므로 이용을 피하는 것이 좋음 2010-1학기 컴퓨터게임(DirectX)
크기 멤버를 갖춘 버텍스 구조체 struct Particle { D3DXVECTOR3 _position; D3DCOLOR _color; Float _size; static const DWORD FVF; }; const DWORD Particle::FVF = D3DFVF_XYZ | D3DFVF_DIFFUSE | D3DFVF_PSIZE; D3DFVFCAPS_PSIZE가 지원되지 않더라도 버텍스 셰이더를 이용하면 파티클 단위의 크기 제어가 가능 2010-1학기 컴퓨터게임(DirectX)
포인트 스프라이트 렌더 상태 포인트 스프라이트의 동작들은 거의 대부분 렌더 상태에 의해 제어됨 포인트 스프라이트와 관련된 렌더 상태 D3DRS_POINTSPRITEENABLE - 부울값. 디폴트는 false True값은 현재 지정된 전체 텍스처를 포인트 스프라이트 텍스처 매핑에 사용할 것임을 의미 False 값은 포인트 스프라이트의 텍스처 좌표로 지정한 텍셀을 이용해 포인트 스프라이트의 텍스처를 입혀야 하도록 지정 _device->SetRenderState(D3DRS_POINTSPRITEENABLE, true); 2010-1학기 컴퓨터게임(DirectX)
D3DRS_POINTSCALEENABLE - 부울값 True : 포인트 크기를 뷰 스페이스 단위로 해석 지정 False : 포인트 크기를 스크린 스페이스 단위로 해석 지정 _device->SetRenderState(D3DRS_POINTSCALEENABLE, true); D3DRS_POINTSIZE - 포인트 스프라이트 크기 지정 _device->SetRenderState(D3DRS_POINTSIZE, d3d::FtoDw(2.5f)); 2010-1학기 컴퓨터게임(DirectX)
d3d::FtoDw함수는 d3dUtility.h/cpp에 추가한 것 float 을 DWORD로 형 변환한다. DWORD d3d::FtoDw(float f) { return *((DWORD*)&f); } D3DRS_POINTSIZE_MIN : 포인트 스프라이트의 지정할 수 있는 최소 크기 지정 _device->SetRenderState(D3DRS_POINTSIZE_MIN, d3d::FtoDw(0.2f)); 2010-1학기 컴퓨터게임(DirectX)
D3DRS_POINTSIZE_MAX : 포인트 스프라이트의 지정할 수 있는 최대 크기를 지정 _device->SetRenderState(D3DRS_POINTSIZE_MAX, d3d::FtoDw(5.0f)); D3DRS_POINTSCALE_A, D3DRS_POINTSCALE_B, D3DRS_POINTSCALE_C 이 세 개의 상수는 거리에 따라 포인트 스프라이트의 크기가 변하는 방법을 제어 거리란 카메라와 포인트 스프라이트 간의 거리이다. 2010-1학기 컴퓨터게임(DirectX)
FinalSize = ViewportHeight · Size · A, B, C : 순서대로 D3DRS_POINTSCALE_A, D3DRS_POINTSCALE_B, D3DRS_POINTSCALE_C 렌더 상태에 지정된 값 D : 뷰 스페이스 내의 포인트 스프라이트와 카메라 위치와의 거리 뷰 스페이스 내의 (x, y, z)에 포인트 스프라이트가 위치한다면 D = x2 + y2+z2 1 A+B(D)+C(D ) 2 2010-1학기 컴퓨터게임(DirectX)
다음 코드는 포인트 스프라이트가 작아지도록 포인트 스프라이트 거리 상수 값을 지정 _device->SetRenderState(D3DRS_POINTSCALE_A, d3d::FtoDw(0.0f)); _device->SetRenderState(D3DRS_POINTSCALE_B, d3d::FtoDw(0.0f)); _device->SetRenderState(D3DRS_POINTSCALE_C, d3d::FtoDw(1.0f)); 2010-1학기 컴퓨터게임(DirectX)
파티클과 파티클의 속성들 파티클은 위치와 컬러 이외의 상당히 많은 속성들로 이루어짐 예: 속도 등 파티클을 렌더링 하는데 필요한 데이터와 파티클 속성을 별도의 구조체 내에 보관 렌더링할 준비가 완료되면 Particle 구조체로 위치와 속성을 복사해 이용 파티클의 속성은 모델링하려는 파티클 시스템의 종류에 따라 달라진다. 2010-1학기 컴퓨터게임(DirectX)
다음의 구조체 예제는 몇 가지의 공통적인 파티클 속성을 포함 struct Attribute{ D3DXVECTOR3 _position; D3DXVECTOR3 _velocity; D3DXVECTOR3 _acceleration; D3DXVECTOR3 _lifeTime; D3DXVECTOR3 _age; D3DXVECTOR3 _color; D3DXVECTOR3 _colorFade; D3DXVECTOR3 _isAlive; }; 2010-1학기 컴퓨터게임(DirectX)
_position : 월드 스페이스 내의 파티클 위치 _velocity : 파티클의 속도, 초당 이동단위 _acceleration : 파티클의 가속, 초당 이동단위 _lifeTime : 파티클이 소멸될 때까지 유지되는 시간 _age : 파티클 현재 나이 _color : 파티클의 컬러 _colorFade : 파티클의 컬러가 시간의 흐름에 따라 퇴색하는 방법 _isAlive : 파티클이 생존한 경우 True, 소멸 False 2010-1학기 컴퓨터게임(DirectX)
파티클 시스템의 요소들 파티클 시스템 파티클들의 모임 파티클을 보여주고 관리하는 역할을 담당 파티클의 크기, 원천의 위치, 적용할 텍스처 등 시스템 내의 모든 파티클에 영향을 주는 전역 특성 관리 파티클 갱신, 디스플레이, 소멸, 생성 등을 관장 Psystem 클래스 모든 파티클 시스템이 공유하는 공통 특성을 Psystem기반 클래스로 추상화 다른 모든 전형적인 파티클 시스템의 부모로 이용 2010-1학기 컴퓨터게임(DirectX)
Psystem 클래스 class PSystem { public: PSystem(); virtual ~PSystem(); virtual bool init(IDirect3DDevice9* device, char* texFileName); virtual void reset(); virtual void resetParticle(Attribute* attribute) = 0; virtual void addParticle(); virtual void update(float timeDelta) = 0; 2010-1학기 컴퓨터게임(DirectX)
virtual void preRender(); virtual void render(); virtual void postRender(); bool isEmpty(); bool isDead(); protected: virtual void removeDeadParticles(); IDirect3DDevice9* _device; D3DXVECTOR3 _origin; d3d::BoundingBox _boundingBox; 2010-1학기 컴퓨터게임(DirectX)
IDirect3DTexture9* _tex; IDirect3DVertexBuffer9* _vb; float _emitRate; float _size; IDirect3DTexture9* _tex; IDirect3DVertexBuffer9* _vb; std::list<Attribute> _particles; int _maxParticles; DWORD _vbSize; // size of vb DWORD _vbOffset; // offset in vb to lock DWORD _vbBatchSize; // number of vertices to lock starting at _vbOffset }; 2010-1학기 컴퓨터게임(DirectX)
_origin : 시스템의 원천. 시스템 내에서 파티클이 시작되는 곳 데이터 멤버 _origin : 시스템의 원천. 시스템 내에서 파티클이 시작되는 곳 _boundingBox : 파티클이 이동할 수 있는 부피를 제한하는데 이용 _emitRate : 시스템에 새로운 파티클이 추가되는 비율. 초당 파티클 수 _size : 시스템 내 모든 파티클의 크기 _particles : 시스템 내 파티클 속성의 리스트. 파티클을 만들고 제거하고 갱신하는데 이용. 2010-1학기 컴퓨터게임(DirectX)
_maxParticles : 주어진 시간 동안 시스템이 가질 수 있는 최대 파티클의 수 _vbSize : 버텍스 버퍼가 보관할 수 있는 파티클의 수 _vbOffset, _vbBatchSize: 파티클시스템의 렌더링에 이용 메서드 Psystem / ~PSystem. : 디폴트 값을 초기화하는 생성자와 장치 인터페이스(버텍스버퍼, 텍스처) 해제 소멸자 Init : 이 메서드는 포인트 스프라이트를 저장하기 위한 버텍스를 만들고 텍스처를 만드는 등의 장치 의존적인 초기화 작업 처리 2010-1학기 컴퓨터게임(DirectX)
hr = device->CreateVertexBuffer( _vbSize * sizeof(Particle), D3DUSAGE_DYNAMIC | D3DUSAGE_POINTS | D3DUSAGE_WRITEONLY, Particle::FVF, D3DPOOL_DEFAULT, &_vb, 0); 동적 버텍스 버퍼를 이용. 매 프레임 마다 파티클을 갱신하며 이 때 버텍스 버퍼 메모리에 접근 버텍스 버퍼가 포인트 스프라이트를 보관할 것임을 지정하는 D3DUSAGE_POINTS 이용 2010-1학기 컴퓨터게임(DirectX)
동적 버텍스 버퍼는 관리 메모리 풀에 보관할 수 없으므로 일반적인 관리 메모리 풀 대신에 디폴트 메모리 풀을 이용 버텍스 크기가 _vbSize에 의해 미리 정의되며 시스템 내의 파티클 수와는 관련이 없음을 주의. _vbSize 가 시스템 내 파티클의 수와 같은 경우는 거의 없음. 동적 버텍스 버퍼는 관리 메모리 풀에 보관할 수 없으므로 일반적인 관리 메모리 풀 대신에 디폴트 메모리 풀을 이용 2010-1학기 컴퓨터게임(DirectX)
reset : 이 메서드는 시스템 내의 모든 파티클 속성을 리셋 void PSystem::reset(){ std::list<Attribute>::iterator i; for(i = _particles.begin(); i != _particles.end(); i++) { resetParticle( &(*i) ); } 2010-1학기 컴퓨터게임(DirectX)
resetParticle : 한 파티클의 속성을 리셋 addParticle : 시스템에 파티클을 추가 void PSystem::addParticle(){ Attribute attribute; resetParticle(&attribute); _particles.push_back(attribute); } update : 시스템 내의 모든 파티클들을 갱신 render : 시스템 내의 모든 파티클들을 렌더링 2010-1학기 컴퓨터게임(DirectX)
preRender : 렌더링에 앞서 지정해야 할 초기 렌더 상태를 지정 void PSystem::preRender() { _device->SetRenderState(D3DRS_LIGHTING, false); _device->SetRenderState(D3DRS_POINTSPRITEENABLE, true); _device->SetRenderState(D3DRS_POINTSCALEENABLE, true); _device->SetRenderState(D3DRS_POINTSIZE, d3d::FtoDw(_size)); _device->SetRenderState(D3DRS_POINTSIZE_MIN, d3d::FtoDw(0.0f)); _device->SetRenderState(D3DRS_POINTSCALE_A, d3d::FtoDw(0.0f)); _device->SetRenderState(D3DRS_POINTSCALE_B, d3d::FtoDw(0.0f)); _device->SetRenderState(D3DRS_POINTSCALE_C, d3d::FtoDw(1.0f)); 2010-1학기 컴퓨터게임(DirectX)
_device->SetTextureStageState(0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE); _device->SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_SELECTARG1); _device->SetRenderState(D3DRS_ALPHABLENDENABLE, true); _device->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_SRCALPHA); _device->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA); } 2010-1학기 컴퓨터게임(DirectX)
알파 블렌딩을 활성화 하여 텍스처의 알파 채널이 텍스처의 픽셀 투명도를 결정하도록 했음을 확인 눈덩이와 비슷한 둥근 파티클을 얻기 위해서는 흰색의 원형과 검은색의 알파 채널을 갖는 흰색 택스처를 이용하면 된다. 2010-1학기 컴퓨터게임(DirectX)
postRender : 특정 파티클 시스템이 지정했을 수 있는 렌더 상태를 복구하는데 이용 void PSystem::postRender(){ _device->SetRenderState(D3DRS_LIGHTING, true); _device->SetRenderState(D3DRS_POINTSPRITEENABLE, false); _device->SetRenderState(D3DRS_POINTSCALEENABLE, false); _device->SetRenderState(D3DRS_ALPHABLENDENABLE, false); } 2010-1학기 컴퓨터게임(DirectX)
isEmpty : 현재 시스템에 파티클이 없는 경우 True isDead : 시스템 내 파티클이 모두 죽은 경우 True 2010-1학기 컴퓨터게임(DirectX)
removeDeadParticles : _particle검색 후 죽은 파티클을 리스트에서 제거 void PSystem::removeDeadParticles(){ std::list<Attribute>::iterator i; i = _particles.begin(); while( i != _particles.end() ) { if( i->_isAlive == false ){ i = _particles.erase(i); } else { i++; // next in list 2010-1학기 컴퓨터게임(DirectX)
파티클 시스템의 드로잉 파티클 시스템은 동적이기 때문에 매 프레임마다 시스템의 파티클을 갱신해야 함 파티클 시스템의 렌더링 방식 예 (1) 최대 수의 파티클을 보관할 수 있는 버텍스 버퍼 생성 각 프레임에 다음과 같은 작업 수행 1. 모든 파티클을 갱신 2. 모든 살아있는 파티클들을 버텍스 버퍼로 복사 3. 버텍스 버퍼를 그린다. 효율적이지 못하다: 버텍스 버퍼가 시스템 내의 모든 파티클을 포함할 수 있는 크기를 가져야 하고 리스트에서 버텍스버퍼로 모든 파티클을 복사하는 동안 그래픽카드가 아무일로 하지 않음. 2010-1학기 컴퓨터게임(DirectX)
적당한 크기의 버텍스 버퍼를 만들고, 이를 세그먼트로 나눈다.(예 : 세그먼트 500 지정) 파티클 시스템의 렌더링 방식 예 (2) 적당한 크기의 버텍스 버퍼를 만들고, 이를 세그먼트로 나눈다.(예 : 세그먼트 500 지정) 현재 위치의 세그먼트를 표시하기 위한 전역 변수 i = 0 을 만든다. 각 프레임에 다음과 같은 작업을 수행한다. 세그먼트 0:500 파티클 용량 세그먼트 1:500 파티클 용량 세그먼트 2:500 파티클 용량 세그먼트 3:500 파티클 용량 버텍스 버퍼 : 2000 파티클 용량 2010-1학기 컴퓨터게임(DirectX)
D3DLOCK_NOOVER-WRITE 플래그로 세그먼트 i를 잠근다. 세그먼트 i로 500 파티클을 복사한다. 1. 모든 파티클을 갱신 D3DLOCK_NOOVER-WRITE 플래그로 세그먼트 i를 잠근다. 세그먼트 i로 500 파티클을 복사한다. 2. 만약 버텍스 버퍼가 가득 찼다면 버텍스 버퍼의 처음부터 시작한다. i = 0 D3DLOCK_DISCARD 플래그로 세그먼트 i 잠근다. 세그먼트 i 로 500 파티클을 복사. 3. 세그먼트 i를 렌더링 한다. 4. 다음 세그먼트로 : i++ 2010-1학기 컴퓨터게임(DirectX)
버텍스 버퍼의 일부가 렌더링 될 때 렌더링되지 않는 일부 버퍼를 잠글 수 있게하여 렌더링 지연을 막을 수 있다. 이 방식이 높은 효율을 가짐 필요한 버텍스 버퍼의 크기를 줄일 수 있으며 CPU와 그래픽 카드가 함께 작업할 수 있다. 버텍스 버퍼의 일부가 렌더링 될 때 렌더링되지 않는 일부 버퍼를 잠글 수 있게하여 렌더링 지연을 막을 수 있다. CPU와 그래픽카드가 함께 작업할 수 있다. 렌더링 구현을 위해 다음 데이터멤버 사용 _vbSize : 버텍스 버퍼가 한번에 보관할 수 있는 파티클의 수 _vbOffset : 버텍스 버퍼에서 복사를 시작할 파티클 내 다음 단계로의 오프셋. 바이트가 아닌 파티클 단위. _vbBatchSize : 하나의 단계에 정의된 파티클 수 2010-1학기 컴퓨터게임(DirectX)
렌더링 메서드의 코드 void PSystem::render() { if( !_particles.empty() ) { preRender(); _device->SetTexture(0, _tex); _device->SetFVF(Particle::FVF); _device->SetStreamSource(0, _vb, 0, sizeof(Particle)); if(_vbOffset >= _vbSize) _vbOffset = 0; Particle* v = 0; _vb->Lock( _vbOffset * sizeof( Particle ), _vbBatchSize * sizeof( Particle ), (void**)&v,_vbOffset ? D3DLOCK_NOOVERWRITE : D3DLOCK_DISCARD); 2010-1학기 컴퓨터게임(DirectX)
DWORD numParticlesInBatch = 0; std::list<Attribute>::iterator i; for(i = _particles.begin(); i != _particles.end(); i++) { if( i->_isAlive ) { v->_position = i->_position; v->_color = (D3DCOLOR)i->_color; v++; numParticlesInBatch++; //단체 카운터 증가 //현재 단계가 모두 채워졌는가 if(numParticlesInBatch == _vbBatchSize) // 단계가 그려지는 동안 다음 단계를 // 파티클로 채운다. _vb->Unlock(); 2010-1학기 컴퓨터게임(DirectX)
_device->DrawPrimitive( D3DPT_POINTLIST, _vbOffset, _vbBatchSize); if(_vbOffset >= _vbSize) _vbOffset = 0; _vb->Lock( _vbOffset * sizeof( Particle ), _vbBatchSize * sizeof( Particle ), (void**)&v, _vbOffset ? D3DLOCK_NOOVERWRITE : D3DLOCK_DISCARD); numParticlesInBatch = 0; } 2010-1학기 컴퓨터게임(DirectX)
if( numParticlesInBatch ) { _device->DrawPrimitive( _vb->Unlock(); if( numParticlesInBatch ) { _device->DrawPrimitive( D3DPT_POINTLIST, _vbOffset, numParticlesInBatch); } _vbOffset += _vbBatchSize; postRender(); 2010-1학기 컴퓨터게임(DirectX)
무작위성 시스템의 파티클에는 무작위성이 필요하다. 예 : 눈의 크기, 속도 등 무작위성을 지원하기 위해 d3dUtility.h/cpp 파일에 다음과 같은 두 개의 함수 추가. Float d3d::GetRandomFloat(); [lowBound, highBound] 범위의 임의의 float 리턴 GetRandomVector() 최소점 min, 최대점 max로 정의된 상자 내의 임의 벡터 출력 2010-1학기 컴퓨터게임(DirectX)
float d3d::GetRandomFloat(float lowBound, float highBound) { if( lowBound >= highBound ) // 잘못된 입력 return lowBound; // [0,1]범위의 임의의 float을 얻는다. float f = (rand() % 10000) * 0.0001f; // [lowBound, highBound] 범위의 float을 리턴 return (f * (highBound - lowBound)) + lowBound; } 2010-1학기 컴퓨터게임(DirectX)
void d3d::GetRandomVector( D3DXVECTOR3* out, D3DXVECTOR3* min, D3DXVECTOR3* max) { out->x = GetRandomFloat(min->x, max->x); out->y = GetRandomFloat(min->y, max->y); out->z = GetRandomFloat(min->z, max->z); } 2010-1학기 컴퓨터게임(DirectX)
전형적인 파티클 시스템 눈, 불꽃놀이, 입자 총을 구현하는 과정 눈 시스템: 내리는 눈송이를 모델링 불꽃놀이 시스템: 불꽃놀이와 비슷한 폭발 현상 모델링 입자총 시스템: 사용자 키 입력에 따라 카메라가 바라보는 방향으로 발사되는 입자 총탄 모델링 2010-1학기 컴퓨터게임(DirectX)
예제 : 눈 눈의 클래스 class Snow : public PSystem. { public : snow(d3d::boundingBox* boundingBox, int numParticles); void resetParticle(Attribute* attribute); void update(float timeDelta); }; 2010-1학기 컴퓨터게임(DirectX)
생성자는 경계 상자 구조체를 가리키는 포인터와 시스템 내 파티클의 수를 받는다. 경계상자는 눈송이가 떨어질 부피를 정의 Snow::Snow(d3d::BoundingBox* boundingBox, int numParticles){ _boundingBox = *boundingBox; _size = 0.25f; _vbSize = 2048; _vbOffset = 0; _vbBatchSize = 512; for(int i = 0; i < numParticles; i++) addParticle(); } 2010-1학기 컴퓨터게임(DirectX)
resetParticle은 경계 상자 내 임의의 x와 y좌표 위치에서 눈송이를 만들고, 눈송이에 속도를 부여하여 아래방향으로 약간 왼쪽으로 떨어지게 함 void Snow::resetParticle(Attribute* attribute){ attribute->_isAlive = true; // 눈송이 위치 지정을 위해 임의의 x, z 좌표를 얻는다. d3d::GetRandomVector( &attribute->_position, &_boundingBox._min, &_boundingBox._max); 2010-1학기 컴퓨터게임(DirectX)
// 높이(y-좌표)는 항상 경계 상자의 최상단이 된다. attribute->_position.y = _boundingBox._max.y; // 눈송이는 아래쪽으로 떨어지며 약간 왼쪽을 향한다. attribute->_velocity.x = d3d::GetRandomFloat(0.0f, 1.0f) * -3.0f; attribute->_velocity.y = d3d::GetRandomFloat(0.0f, 1.0f) * -10.0f; attribute->_velocity.z = 0.0f; attribute->_color = d3d::WHITE; } 2010-1학기 컴퓨터게임(DirectX)
파티클의 위치를 갱신하며 시스템의 경계 상자를 벗어났는지 확인 경계상자를 벗어나면 파티클을 초기화 update 메서드 파티클의 위치를 갱신하며 시스템의 경계 상자를 벗어났는지 확인 경계상자를 벗어나면 파티클을 초기화 void Snow::update(float timeDelta) { std::list<Attribute>::iterator i; for(i = _particles.begin(); i != _particles.end(); i++) i->_position += i->_velocity * timeDelta; if( _boundingBox.isPointInside( i->_position ) == false ) resetParticle( &(*i) ); } 2010-1학기 컴퓨터게임(DirectX)
파티클 시스템: 눈 2010-1학기 컴퓨터게임(DirectX)
불 꽃 놀 이 Firework 시스템의 클래스 class Firework : public PSystem { public: Firework(D3DXVECTOR3* origin, int numParticles); void resetParticle(Attribute* attribute); void update(float timeDelta); void preRender(); void postRender(); }; 2010-1학기 컴퓨터게임(DirectX)
생성자는 시스템 원천(origin)으로의 포인터와 시스템이 가진 파티클의 수를 받는다. 원천이란 불꽃이 폭발할 장소를 의미 resetParticle 메서드 시스템 원천의 파티클을 초기화 구체 내에서 임의의 속도를 만들고 시스템 내의 파티클들은 임의의 컬러를 부여받음 각 파티클들이 2초 동안 유지되도록 수명 지정 2010-1학기 컴퓨터게임(DirectX)
void Firework::resetParticle(Attribute* attribute){ attribute->_isAlive = true; attribute->_position = _origin; D3DXVECTOR3 min = D3DXVECTOR3(-1.0f, -1.0f, -1.0f); D3DXVECTOR3 max = D3DXVECTOR3( 1.0f, 1.0f, 1.0f); d3d::GetRandomVector( &attribute->_velocity, &min, &max); D3DXVec3Normalize( &attribute->_velocity); 2010-1학기 컴퓨터게임(DirectX)
attribute->_velocity *= 100.0f; attribute->_color = D3DXCOLOR( d3d::GetRandomFloat(0.0f, 1.0f), 1.0f); attribute->_age = 0.0f; attribute->_lifeTime = 2.0f; // lives for 2 seconds } 2010-1학기 컴퓨터게임(DirectX)
void Firework::update(float timeDelta){ 각 파티클의 위치를 갱신 수명을 초과한 파티클의 죽음을 처리. 죽은 파티클을 제거하지 않고 재활용 void Firework::update(float timeDelta){ std::list<Attribute>::iterator i; for(i = _particles.begin(); i != _particles.end(); i++) { // only update living particles if( i->_isAlive ) 2010-1학기 컴퓨터게임(DirectX)
i->_position += i->_velocity * timeDelta; i->_age += timeDelta; if(i->_age > i->_lifeTime) // kill i->_isAlive = false; } 2010-1학기 컴퓨터게임(DirectX)
Firework 렌더링에는 다른 블렌드 인수가 이용되며 깊이 버퍼로의 쓰기도 허용 안됨 블렌드 인수와 쓰기 변경을 위해 PSystem::preRender, Psystem::postRender 메서드 오버라이드 오버라이드 된 예 void Firework::preRender(){ PSystem::preRender(); _device->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_ONE); _device->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_ONE); 2010-1학기 컴퓨터게임(DirectX)
// z-버퍼 읽기는 가능하지만 쓰기는 허용하지 않음 _device->SetRenderState(D3DRS_ZWRITEENABLE, false); } void Firework::postRender() { PSystem::postRender(); _device->SetRenderState(D3DRS_ZWRITEENABLE, true); 두 메서드 모두 부모 버전의 메서드를 호출 => 재사용 2010-1학기 컴퓨터게임(DirectX)
파티클 시스템: 불꽃놀이 2010-1학기 컴퓨터게임(DirectX)
입 자 총 Particle Gun 클래스 class ParticleGun : public PSystem { public: ParticleGun(Camera* camera); void resetParticle(Attribute* attribute); void update(float timeDelta); private: Camera* _camera; }; 2010-1학기 컴퓨터게임(DirectX)
새로운 파티클을 만들 때마다 카메라의 위치와 방향에 대한 정보가 필요하기 때문 생성자는 카메라로의 포인터를 받는다. 새로운 파티클을 만들 때마다 카메라의 위치와 방향에 대한 정보가 필요하기 때문 resetParticle 메서드 파티클의 위치를 카메라의 현재 위치로 지정 파티클의 속도를 카메라가 바라보고 있는 방향의 100배로 지정 2010-1학기 컴퓨터게임(DirectX)
void ParticleGun::resetParticle(Attribute* attribute){ attribute->_isAlive = true; D3DXVECTOR3 cameraPos; _camera->getPosition(&cameraPos); D3DXVECTOR3 cameraDir; _camera->getLook(&cameraDir); attribute->_position = cameraPos; attribute->_position.y -= 1.0f; attribute->_velocity = cameraDir * 100.0f; attribute->_color = D3DXCOLOR(0.0f, 1.0f, 0.0f, 1.0f); attribute->_age = 0.0f; attribute->_lifeTime = 1.0f; // lives for 1 seconds } 2010-1학기 컴퓨터게임(DirectX)
void ParticleGun::update(float timeDelta){ 파티클의 위치를 갱신 수명이 다한 경우 죽은 것으로 처리 파티클 리스트를 검색하여 죽은 파티클 제거 void ParticleGun::update(float timeDelta){ std::list<Attribute>::iterator i; for(i = _particles.begin(); i != _particles.end(); i++) { i->_position += i->_velocity * timeDelta; i->_age += timeDelta; 2010-1학기 컴퓨터게임(DirectX)
if(i->_age > i->_lifeTime) // kill i->_isAlive = false; } removeDeadParticles(); 2010-1학기 컴퓨터게임(DirectX)
파티클 시스템: 입자총 2010-1학기 컴퓨터게임(DirectX)