http://www.cyworld.com/romejune/5142517
//////////////////////////////////////////////////////////////////////////////////////////////////
//
// File: pSystem.h
//
// Author: Frank Luna (C) All Rights
Reserved
//
// System: AMD Athlon 1800+ XP, 512 DDR, Geforce 3, Windows
XP, MSVC++ 7.0
//
// Desc: Represents a geneal particle
system.
//
//////////////////////////////////////////////////////////////////////////////////////////////////
#ifndef __pSystemH__
#define __pSystemH__
#include "d3dUtility.h"
#include "camera.h"
#include <list>
namespace psys
{
////파티클의 위치와 컬러를 표현하는 데의 구조체
포맷.
struct Particle
{
D3DXVECTOR3
_position;
D3DCOLOR _color;
static const DWORD
FVF;
};
struct
Attribute
{
Attribute()
{
_lifeTime = 0.0f;
_age
= 0.0f;
_isAlive = true;
}
// 파티클과 파티클의 속성들.
// 파티클을 렌더링하는데 필요한 데이터와 파티클 속성을 별도의 구조체 내에 보관하게 되는데,
// 파티클을
만들고 파괴하고 갱신할 때는 바로 이러한 속성을 이용해 작업하는 것이며,
// 이를 렌더링할 준비가 완료되면 Particle 구조체로
위치와 속성을 복사해 이용.
D3DXVECTOR3 _position; // 월드 스페이스 내의 파티클
위치.
D3DXVECTOR3 _velocity; // 파티클의 속도, 보통은
초당 이동 단위로 기록.
D3DXVECTOR3 _acceleration; // 파티클의
가속. 보통은 초당 이동 단위로 기록.
float _lifeTime; // 파티클이 소멸할 때까지 유지되는 시간.
// 예, 레이저 빔 파티클은 특정한 시간동안만 유지.
float
_age; // 파티클의 현재 나이
D3DXCOLOR
_color; // 파티클의 컬러
D3DXCOLOR
_colorFade; // 파티클의 컬러가 시간의 흐름에 따라 퇴색하는
방법
bool _isAlive; // 파티클이 생존한 경우 true,
소멸한 경우 false
};
// 파티클 시스템의 요소들.
// 파티클 시스템은 파티클들의 모임이며 파티클을
보여주고 관리하는 역할을 담당한다.
// 파티클의 크기나 파티클 원천의 위치, 파티클에 적용할 텍스처 등
// 시스템 내의 모든
파티클에 영향을 주는 전역 특성들을 관리.
// 기능적 관점에서 보면
// 파티클 갱신과 디스플레이, 소멸, 생성 등을 관장하는
역할.
class PSystem
{
public:
// 디폴트 값을 초기화하는
생성자와
// 장치 인터페이스 (버텍스 버퍼, 텍스처)를 해제하는
디스트럭터
PSystem();
virtual ~PSystem();
// init - 포인트 스프라이트를 저장하기 위한 버텍스 버퍼를 만들고
// 텍스처를
만드는 등의 Direct3D의 장치 의존적인 초기화 작업을 처리.
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;
// 렌더링에 앞서 지정해야 할 초기 렌더 상태를 지정.
// 이 메서드는 시스템에 따라
달라질 수 있으므로 가상 함수로 선언.
virtual void preRender();
// 시스템 내의 모든 파티클들을 렌더링
virtual void
render();
// 특정 파티클 시스템이 지정했을 수 있는 렌더 상태를 복구하는 데 이용.
// 이
메서드는 시스템에 따라 달라질 수 있으므로 가상 메서드로 선언.
virtual void postRender();
// 현재 시스템에 파티클이 없는 경우 true 리턴.
bool
isEmpty();
// 시스템 내의 파티클이 모두 죽은 경우 true 리턴.
bool
isDead();
protected:
// 속성 리스트 _particle을 검색하여 죽은 파티클을 리스트에서
제거.
virtual void removeDeadParticles();
protected:
IDirect3DDevice9*
_device;
D3DXVECTOR3 _origin; // 시스템의 원천,
시스템 내에서 파티클이 시작되는 곳.
d3d::BoundingBox _boundingBox; // 파티클이 이동할 수 있는 부피를 제한하는 데 이용.
// 예, 산 정상을 둘러싼 지역에만 눈이 오는 시스템.
// 원하는 영역을 경계상자로 정의하면 이 영역을
벗어난 파티클들을 곧바로 소멸.
float _emitRate; // 시스템에 새로운 파티클이 추가되는 비율. 보통은 초당 파티클 수로
기록.
float _size; // 시스템
내 모든 파티클의 크기
IDirect3DTexture9*
_tex;
IDirect3DVertexBuffer9* _vb;
std::list<Attribute>
_particles; // 시스템 내 파티클 속성의 리스트.
// 우리는 파티클을 만들고 제거하고 갱신하는 데 이 리스트를 이용.
// 파티클을 그릴
준비가 완료되면
// 리스트 노드의 일부를 버텍스 버퍼로 복사하고
// 파티클 드로잉 과정을 거친다.
// 이어
다음 단계의 데이터를 복사하고 다시 파티클을 그리며,
// 모든 파티클을 그릴 때까지 이 과정을 반복.
int _maxParticles; // 주어진 시간 동안
시스템이 가질 수 있는 최대 파티클의 수.
// 예, 파티클이 파괴되는 속도보다 만들어지는 속도가 빠르다면
// 엄청나게
많은 수의 파티클이 동시에 존재할 수 있다.
// 이 멤버는 이와 같은 상황을 막는다.
DWORD _vbSize; // 버텍스 버퍼가 보관할 수 있는 파티클의 수.
// 이 값은 실제 파티클 시스템 내의 파티클 수와는 독립적.
DWORD _vbOffset; // 파티클 시스템의 렌더링에 이용.
DWORD _vbBatchSize; // 파티클 시스템의 렌더링에 이용.
};
// 눈
class Snow : public
PSystem
{
public:
// 생성자
// 경계 상자 구조체를
가리키는 포인터와 시스템 내 파티클의 수
// 경계 상자는 눈송이가 떨어질 부피를 정의하며,
// 만약 눈송이가 이 범위
밖으로 벗어 나면 즉시 소멸하고 다시 만들어짐.
// 항상 같은 수의 파티클을
유지.
Snow(d3d::BoundingBox* boundingBox, int numParticles);
void
resetParticle(Attribute* attribute);
void update(float
timeDelta);
};
// 불꽃놀이
class Firework : public
PSystem
{
public:
Firework(D3DXVECTOR3* origin, int
numParticles);
void resetParticle(Attribute* attribute);
void
update(float timeDelta);
void preRender();
void
postRender();
};
// 입자총
class ParticleGun : public
PSystem
{
public:
ParticleGun(Camera* camera);
void
resetParticle(Attribute* attribute);
void update(float
timeDelta);
private:
Camera* _camera;
};
}
#endif // __pSystemH__
//////////////////////////////////////////////////////////////////////////////////////////////////
//
// File: pSystem.cpp
//
// Author: Frank Luna (C) All Rights
Reserved
//
// System: AMD Athlon 1800+ XP, 512 DDR, Geforce 3, Windows
XP, MSVC++ 7.0
//
// Desc: Represents a geneal particle
system.
//
//////////////////////////////////////////////////////////////////////////////////////////////////
#include <cstdlib>
#include "pSystem.h"
using namespace psys;
const DWORD Particle::FVF = D3DFVF_XYZ | D3DFVF_DIFFUSE;
// 초기화하는
생성자
PSystem::PSystem()
{
_device = 0;
_vb = 0; //버텍스 버퍼
_tex = 0; //텍스처
}
// 인터페이스 해제하는
디스트럭터
PSystem::~PSystem()
{
d3d::Release<IDirect3DVertexBuffer9*>(_vb);
d3d::Release<IDirect3DTexture9*>(_tex);
}
// init - 포인트 스프라이트를 저장하기 위한 버텍스 버퍼를 만들고
// 텍스처를 만드는
등의 Direct3D의 장치 의존적인 초기화 작업을 처리.
bool PSystem::init(IDirect3DDevice9*
device, char* texFileName)
{
// 우리는 동적 버텍스 버퍼를 이용할
것임.
// 매 프레임 마다 파티클을 갱신해야 하며 이는 곧 버텍스 버퍼의 메모리에 접근해야 함을 의미.
// 정적 버텍스
버퍼로의 접근 속도는 상당히 느리다는 데 주의.
// 동적 버텍스 버퍼를 이용하는 것은 바로 이
때문.
_device = device;
HRESULT hr = 0;
hr = device->CreateVertexBuffer(
// 버텍스 버퍼 크기가
_viSize에 의해 미리 정의되며
// 시스템 내의 파티클 수와는 관련이 없음을 주의.
_vbSize *
sizeof(Particle),
// 버텍스 버퍼가 포인트 스프라이트를 보관할 것임을 지정하는
D3DUSAGE_POINTS를 이용.
D3DUSAGE_DYNAMIC | D3DUSAGE_POINTS |
D3DUSAGE_WRITEONLY,
Particle::FVF,
// 동적 버텍스 버퍼는
관리 메모리 풀에 보관할 수 없으므로 디폴트 메모리 풀을 이용.
D3DPOOL_DEFAULT,
&_vb,
0);
if(FAILED(hr))
{
::MessageBox(0,
"CreateVertexBuffer() - FAILED", "PSystem", 0);
return false;
}
hr =
D3DXCreateTextureFromFile(
device,
texFileName,
&_tex);
if(FAILED(hr))
{
::MessageBox(0, "D3DXCreateTextureFromFile() -
FAILED", "PSystem", 0);
return false;
}
return true;
}
// 시스템 내의 모든 파티클 속성을 리셋.
void
PSystem::reset()
{
std::list<Attribute>::iterator i;
for(i =
_particles.begin(); i != _particles.end(); i++)
{
// 한 파티클의 속성을 리셋.
// 파티클의 속성이 리셋되는 방식은 파티클 시스템에 따라
달라짐.
// 따라서 하위 클래스에서 메서드를 구현하도록 추상 메서드로 선언.
resetParticle(
&(*i) );
}
}
// 시스템에 파티클을 추가.
// 이 메서드는 리스트에 추가 하기전에 파티클을 초기화 하는데
resetPaticle 메서드를 이용.
void PSystem::addParticle()
{
Attribute
attribute;
resetParticle(&attribute);
_particles.push_back(attribute);
}
// 포인트 스프라이트 렌더 상태.
void
PSystem::preRender()
{
_device->SetRenderState(D3DRS_LIGHTING,
false);
// 현재 지정된 전체 텍스처를 포인트 스프라이트의 텍스처 매핑에 이용할것임을
의미.
_device->SetRenderState(D3DRS_POINTSPRITEENABLE, true);
// 포인트 크기를 뷰 스페이스 단위로 해석하도록 지정.
// 뷰 스페이스 단위는 간단히
카메라 공간 내의 3D 포인트를 나타내며,
// 포인트 스프라이트의 크기는 카메라와의 거리에 따라 적절하게 조정됨.
// 즉,
카메라와 멀리 떨어진 파티클은 가까운 파티클에 비해작게
나타남.
_device->SetRenderState(D3DRS_POINTSCALEENABLE, true);
// 포인트 스프라이트의 크기를 지정.
// 이 값은 D3DRS_POINTSCALEENABLE
상태 값에 따라서 뷰 스페이스 내의 크기나
// 스크린 스페이스 내의 크기로 해석.
// FtoDw 함수는 float을
DWORD로 형 변환한다.
// 이 함수가 필요한 것은 일반적인 IDirect3DDevice9::SetRenderState
호출이
// float이 아닌 DWORD를 필요로 하기
때문.
_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));
// 텍스처의 알파를
이용.
_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);
}
// 특정 파티클 시스템이 지정했을 수 있는 렌더 상태를 복구하는 데 이용.
// 이 메서드는
시스템에 따라 달라질 수 있으므로 가상 메서드로 선언.
void
PSystem::postRender()
{
_device->SetRenderState(D3DRS_LIGHTING,
true);
_device->SetRenderState(D3DRS_POINTSPRITEENABLE,
false);
_device->SetRenderState(D3DRS_POINTSCALEENABLE,
false);
_device->SetRenderState(D3DRS_ALPHABLENDENABLE, false);
}
// 렌더링 메서드
void
PSystem::render()
{
//
// Remarks: The render method works by
filling a section of the vertex buffer with data,
// then we
render that section. While that section is rendering we lock a
new
// section and begin to fill that section. Once that sections
filled we render it.
// This process continues until all the
particles have been drawn. The benifit
// of this method is that
we keep the video card and the CPU busy.
if( !_particles.empty() )
{
//렌더 상태를
지정.
preRender();
_device->SetTexture(0,
_tex);
_device->SetFVF(Particle::FVF);
_device->SetStreamSource(0,
_vb, 0, sizeof(Particle));
// render batches one by one
//
// 버텍스 버퍼를 벗어날 경우 처음부터 시작한다.
// _vbOffset - 버텍스 버퍼에서 복사를 시작할 파티클 내 다음 단계로의 오프셋(바이트가 아닌 파티클
단위)
// 예, 단계 1이 0부터 499까지 항목이라면 단계 2로의 오프셋은 500이
된다.
if(_vbOffset >= _vbSize)
_vbOffset = 0;
Particle* v = 0;
// _vbBatchSize - 하나의 단계에 정의된 파티클의
수.
_vb->Lock(
_vbOffset * sizeof( Particle
),
_vbBatchSize * sizeof( Particle
),
(void**)&v,
_vbOffset ? D3DLOCK_NOOVERWRITE :
D3DLOCK_DISCARD);
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++; //
next element;
numParticlesInBatch++; //단계 카운터를 증가시킨다.
// 현재 단계가 모두 채워져
있는가?
if(numParticlesInBatch == _vbBatchSize)
{
//
// 버텍스 버퍼로 복사된 마지막 단계의 파티클들을
그린다.
//
_vb->Unlock();
_device->DrawPrimitive(
D3DPT_POINTLIST,
_vbOffset,
_vbBatchSize);
//
// 단계가 그려지는 동안 다음 단계를 파티클로
채운다.
//
// 다음 단계의 처음 오프셋으로 이동한다.
_vbOffset +=
_vbBatchSize;
// 버텍스 버퍼의 경계를 넘는메모리로 오프셋을 설정하지 않는다.
// 경계를
넘을 경우 처음부터 시작.
if(_vbOffset >= _vbSize)
_vbOffset =
0;
_vb->Lock(
_vbOffset * sizeof( Particle
),
_vbBatchSize * sizeof( Particle
),
(void**)&v,
_vbOffset ? D3DLOCK_NOOVERWRITE :
D3DLOCK_DISCARD);
numParticlesInBatch = 0; // 다음 단계를 위한
리셋
}
}
}
_vb->Unlock();
// (numParticlesInBatch == _vbBatchSize) 조건이
//
만족되지 못하여 마지막 단계가 렌더링되지 않는 경우가 발생할 수 있다.
// 일부만 채워진 단계는 바로 이곳에서 렌더링
된다.
if( numParticlesInBatch
)
{
_device->DrawPrimitive(
D3DPT_POINTLIST,
_vbOffset,
numParticlesInBatch);
}
// 다음 블록
_vbOffset += _vbBatchSize;
//
// reset render states
//
postRender();
}
}
// 현재 시스템에 파티클이 없는 경우 true 리턴.
bool
PSystem::isEmpty()
{
return _particles.empty();
}
// 시스템 내의 파티클이 모두 죽은 경우 true 리턴.
// 모든 파티클이 죽은 상태와
시스템이 빈 상태를 혼동하지 않도록.
// 빈 상태는 시스템 내에 파티클이 없는 상태를 의미
// 죽은 상태는 파티클이 존재하지만
죽은 것으로 표시된 상태를 의미.
bool
PSystem::isDead()
{
std::list<Attribute>::iterator i;
for(i =
_particles.begin(); i != _particles.end(); i++)
{
// is there at least
one living particle? If yes,
// the system is not dead.
if(
i->_isAlive )
return false;
}
// no living particles found, the
system must be dead.
return true;
}
// 속성 리스트 _particle을 검색하여 죽은 파티클을 리스트에서
제거.
void
PSystem::removeDeadParticles()
{
std::list<Attribute>::iterator
i;
i = _particles.begin();
while( i != _particles.end() )
{
if( i->_isAlive == false
)
{
// erase는 다음 반복자를 리턴하므로
// 우리가 반복자를
증가시킬 필요가 없다.
i = _particles.erase(i);
}
else
{
i++; // next in list
}
}
}
//*****************************************************************************
//
Snow System
//***************
// 생성자
// 경계 상자 구조체를 가리키는 포인터와 시스템 내 파티클의 수
//
경계 상자는 눈송이가 떨어질 부피를 정의하며,
// 만약 눈송이가 이 범위 밖으로 벗어 나면 즉시 소멸하고 다시
만들어짐.
// 항상 같은 수의 파티클을 유지.
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();
}
// 한 파티클의 속성을 리셋.
// 파티클의 속성이 리셋되는 방식은 파티클 시스템에 따라
달라짐.
// 따라서 하위 클래스에서 메서드를 구현하도록 추상 메서드로 선
// 경계 상자 내 임의의 x와 z좌표 위치에서 눈송이를 만들고
// y좌표를 경계 상자의
최상단과 같도록 지정.
// 이어 눈송이에 속도를 부여하여 아래 방향으로 그리고 약간 왼쪽으로 떨어지도록 한다.
// 눈송이는
흰색으로 표현.
void Snow::resetParticle(Attribute*
attribute)
{
attribute->_isAlive = true;
// GetRandomVector - 최소점 min과 최대점 max로 정의된 상자 내의 임의 벡터를
출력.
// 눈송이의 위치 지정을 위해 임의의 x, z 좌표를
얻는다.
d3d::GetRandomVector(
&attribute->_position,
&_boundingBox._min,
&_boundingBox._max);
// 높이 (y좌표) 는 항상 경계 상자의
최상단.
attribute->_position.y = _boundingBox._max.y;
// GetRandowFloat - [ lowBound, highBound ] 범위에 있는 임의의
float을 리턴.
// 눈송이는 아래쪽으로 떨어지며 약간 왼쪽을
향한다.
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;
}
// 시스템 내의 모든 파티클들을 갱신.
// 메서드의 구현은 특정 파티클 시스템에 따라
달라지므로
// 하위 클래스에서 메서드를 구현하도록 추상 메서드로 선언.
// 파티클의 위치를 갱신하며
// 시스템의 경계 상자를 벗어났는지 확인.
// 만약
경계 상자를 벗어났다면 해당 파티클을 초기화.
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)
);
}
}
}
//*****************************************************************************
//
Explosion System
//********************
// 불꽃놀이 생성자
// 시스템 원천(불꽃이 폭발할 장소) 으로의 포인터, 시스템이 가진
파티클의 수.
Firework::Firework(D3DXVECTOR3* origin, int
numParticles)
{
_origin = *origin;
_size =
0.9f;
_vbSize = 2048;
_vbOffset = 0;
_vbBatchSize =
512;
for(int i = 0; i < numParticles; i++)
addParticle();
}
// 시스템 원천의 파티클을 초기화하고 구체 내에서 임의의 속도를 만들며,
// 시스템 내의
파티클들은 임의의 컬러를 부여.
// 각 파티클들이 2초 동안 유지하도록 수명을 지정.
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,
&attribute->_velocity);
attribute->_velocity *= 100.0f;
attribute->_color = D3DXCOLOR(
d3d::GetRandomFloat(0.0f,
1.0f),
d3d::GetRandomFloat(0.0f, 1.0f),
d3d::GetRandomFloat(0.0f,
1.0f),
1.0f);
attribute->_age = 0.0f;
attribute->_lifeTime = 2.0f; // 2초 동안의 수명을 가진다.
}
// 각 파티클의 위치를 갱신하고 수명을 초과한파티클의 죽음을 처리.
// 이 시스템은 죽은
파티클을 제거하지 않는다.
// 이것은 새로운 불꽃을 만들 때 기존의 죽은 Firework 시스템을 재활용할 수 있기 때문.
//
즉, 파티클을 만들고 제거하는 번거로운 과정을 최소화.
void Firework::update(float
timeDelta)
{
std::list<Attribute>::iterator i;
for(i = _particles.begin(); i != _particles.end(); i++)
{
// 생존한 파티클만 갱신.
if( i->_isAlive
)
{
i->_position += i->_velocity * timeDelta;
i->_age += timeDelta;
if(i->_age > i->_lifeTime) //
죽인다.
i->_isAlive = false;
}
}
}
// 렌더링에 앞서 지정해야 할 초기 렌더 상태를 지정.
// 이 메서드는 시스템에 따라 달라질
수 있으므로 가상 함수로 선언.
// 다른 블렌드 인수가 이용.
// 깊이 버퍼로의 쓰기도 허용되지 않음.
// 디폴트
블렌드 인수와 쓰기 여부를 변경하고자 한다면
// pSystem::preRender와 pSystem::postRender 메서드를
오버라이드하면 됨.
void
Firework::preRender()
{
PSystem::preRender(); // 부모
버전의 메서드를 호출.
_device->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_ONE);
_device->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_ONE);
// z 버퍼 읽기는 가능 하지만 쓰기는 허용하지
않는다.
_device->SetRenderState(D3DRS_ZWRITEENABLE, false);
}
void Firework::postRender()
{
PSystem::postRender();
_device->SetRenderState(D3DRS_ZWRITEENABLE, true);
}
//*****************************************************************************
//
Laser System
//****************
// 입자총 생성자
// 카메라로의 포인터를 받는다.
// 새로운 파티클을 만들 때마다 카메라의 위치와 방향에 대한
정보가 필요.
ParticleGun::ParticleGun(Camera*
camera)
{
_camera = camera;
_size =
0.8f;
_vbSize = 2048;
_vbOffset = 0;
_vbBatchSize = 512;
}
// 파티클의 위치를 카메라의 현재 위치로 지정하고
// 파티클의 속도를 카메라가 보고 있는
방향의 100배로 지정.
// 이 같은 방법으로 현재 바라보고 있는 방향으로 "총알"을 발사할 수 있다.
// 파티클의 컬러는
녹색으로 지정.
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; // 수명은 1초
}
// 파티클의 위치를 갱신하고
// 수명이 다한 경우 죽은 것으로 처리한다.
// 파티클
리스트를 검색하여 죽은 파티클을 제거.
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;
if(i->_age > i->_lifeTime) // kill
i->_isAlive =
false;
}
removeDeadParticles();
}
'그래픽스(Graphics) > DirectX9~12' 카테고리의 다른 글
Direct 에서 파티클 SetRenderState 설정 설명 (0) | 2013.01.31 |
---|---|
용책, 해골책 (0) | 2013.01.31 |
파티클 간단한 렌더링 (0) | 2013.01.31 |
CommitChanges (0) | 2013.01.27 |
Effect::CommitChanges() (0) | 2013.01.25 |