반응형


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

+ Recent posts