10[粒子系统的实现]
第十集 粒子系统的实现
第六集中的二维纹理技术有着天生的缺陷, 1. 纹理走样; 2. 表现单一. 特别是在表达不规则物体如流水, 行云时, 这些缺陷被放大了.
于是有了三维纹理技术, 三维纹理中的纹理空间和物体空间都是三维的. 如显示大理石雕象, 在物体空间是雕象模型, 在纹理空间是大理石的三维纹理, 把雕象模型放进纹理空间的特定地方, 雕象模型表面和纹理空间的交点就是雕象模型要显示的纹理.
那么怎样构造三维纹理? 常用的方式为,
(1). 离散采样. 高分辨率的纹理很耗内存.
(2). 数学解析. --- 过程纹理技术.
在过程纹理中, 有一种能模拟大量不同类型不规则物体的算法 – 粒子系统.
其实, 粒子系统这个名称非常的专业化, 实际我们可以用Windows编程中的画像素来理解,
a. 粒子 --- POINT;
保存要画的像素的坐标.
b. 粒子系统 --- many POINTs;
很多像素要画, 于是要管理好画的过程, 如用个循环, 从POINT array中读取数据, 再画相应的像素.
10.1 粒子系统的实现
在一个封闭的空间中, 成千上万的微小的, 随机不规则运动的粒子组成一个不断变化的不规则物体 – 这些粒子构成了一个封闭的系统, 定义为粒子系统.
粒子系统 == 显示N多随机点的算法, 这是我们要理解的.
在感慨天空中行云的壮阔时, 很少有人会直接指出 -- 那只是一堆水蒸气; 不过现在我们是要创造虚拟世界中的云彩, 所以要从云的基本构成物质开始分析, 现实中云的基本元素 -- 水蒸气, 虚拟世界中的云的基本元素 -- 粒子.
10.1.1 粒子
粒子实际是粒子系统的数据存储单位, 一般粒子包含的数据类型有,
a. 位置; 虽然粒子随时在运动, 但按一定时间片来观察, 粒子还是有位置的.
b. 速度; 既然有位置的变化, 当然有速度存在, 速度的方向性是随时变化的.
c. 生命; 终究, 还是要面对的, 无非是长短的差别.
d. 颜色; 物体的五颜六色是由粒子的颜色决定的.
class CParticle
{
public :
CParticle() { Init();}
~CParticle() { }
VOID Init();
public :
D3DVECTOR m_vPos;
FLOAT m_fVel[3];
FLOAT m_fLife;
D3DXCOLOR m_clr;
};
使用类的形式来封装粒子包含的数据只是个人代码风格问题,
VOID CParticle::Init()
{
m_vPos.x = randf(-16.0, 16.0);;
m_vPos.y = randf(-16.0, 16.0);;
m_vPos.z = 0.0;
m_fVel[0] = 0.0;
m_fVel[1] = 0.0;
m_fVel[2] = 0.0;
m_fLife = randf(8.0, 16.0);
m_clr.a = 1.0;
m_clr.r = randf(0.0, 1.0);
m_clr.g = randf(0.0, 1.0);
m_clr.b = randf(0.0, 1.0);
}
单个粒子是无法形成我们要模拟的不规则物体的, 粒子只是粒子系统中存储数据的单位.
10.1.2 基本粒子系统
粒子系统的作用是管理系统内所有数据(粒子)的初始化, 更新, 删除(不是真的删除), 显示.
class CPSystem
{
public :
CPSystem(LPDIRECT3DVERTEXBUFFER9 pD3DVBuffer);
~CPSystem();
HRESULT Init();
VOID Render();
private :
LPDIRECT3DDEVICE9 m_pD3DDev;
LPDIRECT3DVERTEXBUFFER9 m_pD3DVBuffer;
CParticle m_aP[PARTICLE_COUNT];
};
CPSystem::CPSystem(LPDIRECT3DVERTEXBUFFER9 pD3DVBuffer)
: m_pD3DVBuffer(pD3DVBuffer)
{
}
CPSystem::~CPSystem()
{
SAFERELEASE( m_pD3DDev );
}
HRESULT CPSystem::Init()
{
for (INT i = 0; i < PARTICLE_COUNT; i++)
{
m_aP[i].Init();
}
return m_pD3DVBuffer->GetDevice(&m_pD3DDev);
}
从上面这个类中, 我们明显看出它的作用就是初始化有PARTICLE_COUNT个成员的数组, 然后在渲染的时候根据这个数组的各成员的数据显示很多的点.
粒子系统的渲染过程
过程纹理是实时计算的, 粒子系统一帧画面的形成步骤,
(1). 生命周期内的粒子根据粒子的属性对粒子进行变换, 超出生命周期的粒子”删除”.
(2). 如系统内粒子数量低于某标准值, 初始化新粒子, 加入系统.
(3). 绘制所有在生命周期内的粒子组成的图形.
VOID CPSystem::Render()
{
INT nRand = 0;
UINT nSize = PARTICLE_COUNT * sizeof(MYVERTEX);
FLOAT fRand = 0.0;
FLOAT fVel = 0.0;
MYVERTEX* pV = NULL;
if(FAILED(m_pD3DVBuffer->Lock(0, nSize, (LPVOID*)(&pV), D3DLOCK_DISCARD)))
{
return;
}
// 将上次更新的数据copy到vertex buffer让Direct3D显示
for (INT i = 0; i < PARTICLE_COUNT; i += 4)
{
pV->v = m_aP[i].m_vPos;
pV->colour = DWORD(m_aP[i].m_clr);
pV++;
pV->v = m_aP[i+1].m_vPos;
pV->colour = DWORD(m_aP[i+1].m_clr);
pV++;
pV->v = m_aP[i+2].m_vPos;
pV->colour = DWORD(m_aP[i+2].m_clr);
pV++;
pV->v = m_aP[i+3].m_vPos;
pV->colour = DWORD(m_aP[i+3].m_clr);
pV++;
}
m_pD3DVBuffer->Unlock();
m_pD3DDev->SetStreamSource(0, m_pD3DVBuffer, 0, sizeof(MYVERTEX));
m_pD3DDev->SetFVF(D3DFVF_MYVERTEX);
m_pD3DDev->DrawPrimitive(D3DPT_POINTLIST, 0, PARTICLE_COUNT);
// 更新数据, 当上次中的生命数据< 0, 表示要将数据删除, 实际重新初始化了这个数据
for (INT i = 0; i < PARTICLE_COUNT; i++)
{
if (m_aP[i].m_fLife > 0.0)
{
nRand = randn(3);
fRand = randf(0.0f, 0.6f);
fVel = FLOAT(0.3f - fRand);
m_aP[i].m_fVel[nRand] += fVel;
m_aP[i].m_vPos.x += m_aP[i].m_fVel[0];
m_aP[i].m_vPos.y += m_aP[i].m_fVel[1];
m_aP[i].m_vPos.z += m_aP[i].m_fVel[2];
m_aP[i].m_fLife -= fRand;
}
else
{
m_aP[i].Init();
}
}
}
10.1.3 DirectX Graphics中的Point Sprite
上面的代码只能显示五颜六色的点, 没有大小区别, DirectX Graphics中存在控制标志, 使得显示的点可以根据离视点的远近自动调整最佳的显示大小, 这时的点有个好听的名字 -- Point Sprite.
这些标志统一由IDirect3DDevice9中的函数SetRenderState来控制,
(1). D3DRS_POINTSPRITEENABLE
(2). D3DRS_POINTSCALEENABLE
(3). D3DRS_POINTSIZE
(4). D3DRS_POINTSIZE_MIN
(5). D3DRS_POINTSIZE_MAX
(6). D3DRS_POINTSCALE_A
(7). D3DRS_POINTSCALE_B
(8). D3DRS_POINTSCALE_C
各个参数的作用DirectX9c SDK有详细的描述.
在调用DrawPrimitive画点之前, 我们打开这些标志, 告诉DirectX Graphics要画的点是Point Sprite, 当完成绘制以后, 一般关闭标志, 防止对另外的渲染过程有影响
// open point sprite flags
EnterPSprite();
m_pD3DDev->DrawPrimitive(D3DPT_POINTLIST, 0, PARTICLE_COUNT);
ExitPSprite(); // close flags
VOID CPSystem:: EnterPSprite()
{
m_pD3DDev->SetRenderState(D3DRS_POINTSPRITEENABLE, TRUE);
m_pD3DDev->SetRenderState(D3DRS_POINTSCALEENABLE, TRUE);
m_pD3DDev->SetRenderState(D3DRS_POINTSIZE, FTOD(2.0f));
m_pD3DDev->SetRenderState(D3DRS_POINTSIZE_MIN, FTOD(1.0f));
m_pD3DDev->SetRenderState(D3DRS_POINTSCALE_A, FTOD(0.0f));
m_pD3DDev->SetRenderState(D3DRS_POINTSCALE_B, FTOD(0.0f));
m_pD3DDev->SetRenderState(D3DRS_POINTSCALE_C, FTOD(1.0f));
}
VOID CPSystem:: ExitPSprite()
{
// 只要关闭这两个就可以了, 其他的会自动失效
m_pD3DDev->SetRenderState(D3DRS_POINTSPRITEENABLE, FALSE);
m_pD3DDev->SetRenderState(D3DRS_POINTSCALEENABLE, FALSE);
}
再看看显示的结果, 好看多了, 但同时也发现放大的点是正方形的, 没有”粒子”的感觉. 一般”粒子”总认为是圆形的 --- 习惯性思维.
要将正方形变成圆形的, 就需要给粒子加上纹理, 粒子正方形就会有纹理显示,这里用到了Alpha混合, Alpha混合要到以后再解释, 这里我们让它先客串一下.
m_pD3DDev->SetTexture(0, m_pTexture); // 设置纹理
m_pD3DDev->SetStreamSource(0, m_pD3DVBuffer, 0, sizeof(MYVERTEX));
m_pD3DDev->SetFVF(D3DFVF_MYVERTEX);
EnterPSprite();
m_pD3DDev->DrawPrimitive(D3DPT_POINTLIST, 0, PARTICLE_COUNT);
ExitPSprite();
VOID CPSystem::EnterPSprite()
{
// alpha通道参数设置
m_pD3DDev->SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE);
m_pD3DDev->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_ONE);
m_pD3DDev->SetRenderState(D3DRS_POINTSPRITEENABLE, TRUE);
m_pD3DDev->SetRenderState(D3DRS_POINTSCALEENABLE, TRUE);
m_pD3DDev->SetRenderState(D3DRS_POINTSIZE, FTOD(2.0f));
m_pD3DDev->SetRenderState(D3DRS_POINTSIZE_MIN, FTOD(1.0f));
m_pD3DDev->SetRenderState(D3DRS_POINTSCALE_A, FTOD(0.0f));
m_pD3DDev->SetRenderState(D3DRS_POINTSCALE_B, FTOD(0.0f));
m_pD3DDev->SetRenderState(D3DRS_POINTSCALE_C, FTOD(1.0f));
}
VOID CPSystem::ExitPSprite()
{
// 关闭alpha通道
m_pD3DDev->SetRenderState(D3DRS_ALPHABLENDENABLE, FALSE);
m_pD3DDev->SetRenderState(D3DRS_POINTSPRITEENABLE, FALSE);
m_pD3DDev->SetRenderState(D3DRS_POINTSCALEENABLE, FALSE);
}
10.2 粒子系统的例子
10.2.1 例子说明
这是一个不模仿物体的粒子系统的例子, 由这个例子变化到模拟不规则物体的粒子系统只是各粒子的初始化值不同, 更新时的数据加减…不同而已, 这些网上的资源很多, 试着改数据模拟一下.
第十集 小结
粒子系统是根据粒子中的数据显示随机点的过程, 结合DirectX Graphics中的Point Sprite标志, 可以模拟很多现实中的不规则物体.
10[粒子系统的实现]相关推荐
- WPF结构、图形支持与DirectX学习
Windows 呈现基础(Windows Presentation Foundation,WPF)是一个用于Windows平台的全新的图形显示系统.WPF是针对.NET而设计的,它受现代显示技术,如H ...
- 计算机仿真与MATLAB-32学时 考试复习
第1章 系统仿真的基本概念 1.三个基本要素: 系统.模型.计算机 2.三项基本活动: 模型建立.仿真模型建立(二次建模).仿真试验 3.建模方法: 白盒子系统 用已知的基本定律,经过分析和演绎推导 ...
- H3CNE最新版官网考试模拟题库
以下工作于OSI 参考模型数据链路层的设备是__A____.(选择一项或多项) A. 广域网交换机 B. 路由器 C. 中继器 D. 集线器 A 数据链路层传输的是帧,交换机是基于帧转发的:B 路由器 ...
- cocos2d-x CCParticleSystem粒子系统
粒子系统主要分为如下两种模式: 1.重力式粒子系统(CCParticleSystemPoint ): 这种粒子存在重力,好像地球的万有引力一样,所有的粒子都会收到重力的约束,当 ...
- 【IOS-COCOS2D游戏开发之十】添加粒子系统特效并解决粒子特效与LAYER之间的坐标问题;...
本站文章均为 李华明Himi 原创,转载务必在明显处注明: 转载自[黑米GameDev街区] 原文链接: http://www.himigame.com/iphone-cocos2d/472.html ...
- 用JavaScript玩转游戏物理(一)运动学模拟与粒子系统
系列简介 也许,三百年前的艾萨克·牛顿爵士(Sir Issac Newton, 1643-1727)并没幻想过,物理学广泛地应用在今天许多游戏.动画中.为什么在这些应用中要使用物理学?笔者认为,自我们 ...
- java 粒子系统_Java粒子系统(烟火篇)
用好粒子系统,自己也可以自制一场烟火! 比如说这样的,这就是一个慢慢优化的过程. 下面就上代码大家仔细体会一下吧 import javax.swing.JFrame; import javax.swi ...
- Unity3D粒子系统碰撞器抑制、反弹
关于碰撞检测的主要配置我们看图中的Collision: 第一项:因为是一个,所以这里我选择的是World 第二项(Dampen):抑制(0~1),选这个为1时(完全抑制),碰撞之后,阻止了粒子,可以使 ...
- 虚幻引擎学习之路:粒子系统篇(二)
在此,特别感谢Unreal中国团队对于本篇文章中Unreal引擎相关内容的审核,并在UWA团队学习其引擎的道路上提供的大力支持. 一.Module 功能 1.1 Required Required M ...
最新文章
- grafana监控linux,Grafana –美观、强大的可视化监控指标展示工具 | Linux大学
- iOS进阶之底层原理-锁、synchronized
- 谷歌AI错杀Chrome插件,全职奶爸程序员“睡后收入”被迫终结
- 袁绍困局与张朝阳的雄心——类微博的狐友能让搜狐重回主战场吗
- 用java写了一个汉诺塔
- Android Listview设置每条信息的间距
- activity+window+view简单说明
- C#两种创建快捷方式的方法
- Android聊天软件开发(基于网易云IM即时通讯)——发送图片消息(五)
- 错误: 找不到或无法加载主类 org.sang.BlogserverApplication
- 前大灯是近光灯还是远光灯_大灯是近光灯还是远光灯
- FPGA作为从机与STM32进行SPI协议通信
- 排课系统matlab,matlab数学建模排课
- 组装计算机的游戏,如何组装游戏电脑
- 【实验】Oracle 10g RAC生产数据库RMAN方式恢复到异地单机数据库全程记录
- 前端开发薪资之各地区对比(图文分析)(share)
- Linux九阴真经之九阴白骨爪残卷10(MySQL架构、缓存及索引)
- 查看jvm内存状态的方式 -NMT证明jvm内存多样性
- android动态调试七种武器,安卓动态调试七种武器之长生剑 - Smali Instrumentation
- 改进Yolov5 | 用 GSConv+Slim Neck 一步步把 Yolov5 提升到极致!!!