这篇相当于是对前三篇的总结,基本效果如下:

我认为比较完善的GPU粒子系统应该如下,粒子初始化可以放在CPU里,但是相关数据运算首先要放在GPU里,并且运算后的数据也应该放在显存里,而不是内存里。故用第三篇实现GPU粒子系统不满足,因为他数据是存放在纹理中,要放入VBO里,必需先读取经过内存,然后存放入显存里,这里虽然运算是放入GPU了,但是数据要经过显存-内存-显存的过程,产生不必要的消耗,并且,因为数据是存放在纹理的像素里,故限定在片断着色器中,这二个限制导致第三篇里的内容不能用来实现GPU粒子系统,而是用来实现一些需要结合CPU与GPU结合处理的运算。

在这里,我们采用OpenGL 里的Transform Feedback,和第三篇采用FBO结合浮点纹理不同,Transform Feedback简单来说,传入一个VBO,经过GPU运算后,放入另一个VBO中,注意二点,操作都是针对VBO,也就是针对显存,故不需要经过CPU与内存,还有一点就是在Transform Feedback里,一个缓存不能同时作为输入和输出。

首先来看一下简单的例子介绍Transform Feedback的基本应用,首先指出一点,GLSL3.0与GLSL4.0的Transform Feedback写法有些区别,手上分别有支持3.0与4.0的显示,但是为了更好的兼容性,选择3.0的写法,相应代码和着色器代码如下:

1 tf_v = """2 #version 330

3 in floatinValue;4 out floatoutValue;5 out floatout2;6 voidmain() {7 outValue = inValue+3.0;8 out2 = 1.0;9 }"""

简单变换反馈的着色器

1 this.tfProgram =glCreateProgram()2 this.tfProgram =ShaderProgram(this.tfProgram)3 tfvshader =shaders.compileShader(tf_v,GL_VERTEX_SHADER)4 glAttachShader(this.tfProgram,tfvshader)5 LP_LP_c_char =POINTER(POINTER(c_char))6 ptrs = (c_char_p * 2)('outValue', 'out2')7 printptrs,len(ptrs)8 c_array =cast(ptrs, LP_LP_c_char)9 glTransformFeedbackVaryings(this.tfProgram, len(ptrs), c_array, GL_INTERLEAVED_ATTRIBS)10 glLinkProgram(this.tfProgram)11 this.tfProgram.invalue = glGetAttribLocation(this.tfProgram,"inValue")

着色器基本参数设置

1 classtransformFeedback(common):2 def __init__(this,pro):3 data = [1.0, 2.0, 3.0, 4.0, 5.0]4 data1 = [1.0] * 5

5 this.vbo = vbo.VBO(ny.array(data,'f'))6 this.tbo = vbo.VBO(ny.array(data1,'f'))7 glUseProgram(pro)8 pi =pro.invalue9 #this.vbo = glGenBuffers(1)

10 #glBindBuffer(GL_ARRAY_BUFFER, this.vbo)

11 #output data

12 this.tbo = glGenBuffers(1)13 glBindBuffer(GL_ARRAY_BUFFER, this.tbo)14 glBufferData(GL_ARRAY_BUFFER, 40, None, GL_STATIC_DRAW)15 #input data

16 this.vbo.bind()17 glEnableVertexAttribArray(pi)18 #in pyopengl,the glVertexAttribPointer last two params must not be 0,0

19 glVertexAttribPointer(pi,1,GL_FLOAT,False,4*1,this.vbo)20 glEnable(GL_RASTERIZER_DISCARD)21 glBindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0, this.tbo)22 glBeginTransformFeedback(GL_POINTS)23 glDrawArrays(GL_POINTS, 0, 5)24 glEndTransformFeedback()25 glDisable(GL_RASTERIZER_DISCARD)26 glDisableVertexAttribArray(pi)27 glFlush()28

29 glBindBuffer(GL_ARRAY_BUFFER, this.tbo)30 buffer = (ctypes.c_float * 10)()31 #get buffer pointer

32 point =ctypes.cast(buffer, ctypes.POINTER(ctypes.c_float))33 glGetBufferSubData(GL_ARRAY_BUFFER, 0, 10 * 4,point)34 #convert pointer to array

35 array = ny.ctypeslib.as_array(point,(10,))36 print "tf",array37

38 bf =glMapBuffer(GL_TRANSFORM_FEEDBACK_BUFFER,GL_READ_WRITE)39 pointv =ctypes.cast(bf, ctypes.POINTER(ctypes.c_float))40 arrayv = ny.ctypeslib.as_array(pointv,(5,))41 print "tfv",arrayv42 glUnmapBuffer(GL_ARRAY_BUFFER)

Transform Feedback基本流程

着色器里代码很简单,传入一个float数据,返回二个float数据,上面我们传入一个数组,[1.0, 2.0, 3.0, 4.0, 5.0],经过着色器里简单运算,分别返回这个数据加3值,与一个固定值1.0.然后在transformFeedback我们为了验证正确与否,需要读取VBO里的数据。在这里,pyopengl可以使用glGetBufferSubData与glMapBuffer来得到VBO里的数据,需要注意的是,python与c之间的一些指针,数据的转换,引入ctype,声明ctype类型的数组,然后转换成对应的指针,填充这个数组后,然后转换把指针转化成numpy里的数组.得到的数据如下:

可以看到,传出的数据是4,1,5,1,6,1,7,1,8,1,对比传入的是1.0, 2.0, 3.0, 4.0, 5.0。验证正确。

下面我们以上面的例子来实现我们的粒子系统,这里先入相关Python代码。

1 classparticleSystem(object):2 def __init__(this,len=1):3 this.length =len4 this.cparticles = [0.0] * 7 *len5 this.nparticles = [0.0] * 7 *len6 this.index =07 this.center = 0.0,0.0

8 this.currenttime = 0.0

9 this.height = 2.0

10 this.init1()11 this.createVAO()12 definit1(this):13 #pos(x,y,z),vel(x,y,z),time

14 for i inrange(this.length):15 ind = i * 7

16 px,py,pz,tt = ind,ind + 1,ind + 2,ind + 6

17 vx,vy,vz = ind + 3,ind + 4,ind + 5

18 this.cparticles[px] = 0.0

19 this.cparticles[py] = 3.0

20 this.cparticles[pz] = random.uniform(0,5)21 this.cparticles[vx] =random.random()22 this.cparticles[vy] = 0.0

23 this.cparticles[vz] = 0.0

24 this.cparticles[tt] = random.uniform(1.0,40.0)#random.uniform(0, 3 * this.height)

25 defcreateVAO(this):26 this.currvbo = vbo.VBO(ny.array(this.cparticles,'f'))27 this.nextvbo = vbo.VBO(ny.array(this.nparticles,'f'))28 defrender(this,program):29 ind = this.index % 2

30 span = time.time() - this.currenttime if this.currenttime != 0.0 else 0.0

31 invbo,outvbo = (this.currvbo,this.nextvbo) if ind == 0 else(this.nextvbo,this.currvbo)32 #gpu compute.

33 printspan34 glUseProgram(program)35 glUniform1f(program.span, span)36 glUniform1f(program.live, 40)37 this.update(invbo,outvbo)38 glUseProgram(0)39 #draw particle.

40 glColor(0.5,0.8,0.9)41 glPointSize(3.0)42 outvbo.bind()43 glVertexPointer(3,GL_FLOAT,28,outvbo)44 glDrawArrays(GL_POINTS, 0, this.length)45 outvbo.unbind()46 this.index = this.index + 1

47 this.currenttime =time.time()48 defupdate(this,fvbo,svbo):49 #fvbo->shader(GPU)->svbo,should svbo and fvbo both bind.

50 svbo.bind()51 fvbo.bind()52 glEnableVertexAttribArray(0)53 glEnableVertexAttribArray(1)54 glEnableVertexAttribArray(2)55 glVertexAttribPointer(0,3,GL_FLOAT,False,4 * 7,fvbo)56 glVertexAttribPointer(1,3,GL_FLOAT,False,4 * 7,fvbo + 12)57 glVertexAttribPointer(2,1,GL_FLOAT,False,4 * 7,fvbo + 24)58 glEnable(GL_RASTERIZER_DISCARD)59 glBindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER,0,svbo)60 glBeginTransformFeedback(GL_POINTS)61 glDrawArrays(GL_POINTS, 0, this.length)62 glEndTransformFeedback()63 glDisable(GL_RASTERIZER_DISCARD)64 glDisableVertexAttribArray(0)65 glDisableVertexAttribArray(1)66 glDisableVertexAttribArray(2)67 fvbo.unbind()68 #query gpu data is chage?

69 #svbo.bind()

70 #bf = glMapBuffer(GL_ARRAY_BUFFER,GL_READ_WRITE)

71 #pointv = ctypes.cast(bf, ctypes.POINTER(ctypes.c_float))

72 #arrayv = ny.ctypeslib.as_array(pointv,(70,))

73 #print "tfv",arrayv

74 #glUnmapBuffer(GL_ARRAY_BUFFER)

粒子系统乒乓

结合前面的例子和上文中的乒乓来看,粒子在这里我们每个定义七个数据,前三个用来表示他的位置,后三个用来表示他的速度,最后一个用来表示他在显存里的存活时间。在update就是把数据从一个缓存经过GPU运算放入另一个缓存的过程,例如第一桢,我们传入fvbo,然后数据输出到svbo.在第二桢里,数据就从svbo经过GPU传入到fvbo,第三,第四分别如第一,第二。这样就能实现如第三篇中的乒乓技术。然后在显示render里,我们就用当前输出的缓存里的数据简单的输出显示,本文只是介绍用法,实现如雪花,雨滴,瀑布等特效需要对相关初始化粒子,着色器代码,添加纹理做更改,但是基本处理还是如上。

下面是着色器代码,实现粒子与球的碰撞,也有与地面的交互。代码如下:

1 particle_v = """2 #version 330

3 invec3 pos;4 invec3 vel;5 in floattime;6 uniform floatspan;7 uniform vec2 planeSacle;8 uniform sampler2D plane;9 uniform vec3 sphere;10 uniform floatlive;11 outvec3 outpos;12 outvec3 outvel;13 out floatouttime;14 voidmain() {15 outpos = pos + vel*span;16 vec2 uv = vec2(pos.xz/planeSacle + vec2(0.5,0.5));17 uv.y = 1.0 -uv.y;18 float hight =texture2D(plane, uv).r;19 vec3 tvel =vel;20 //sphere collision

21 float radius =sphere.y;22 vec3 sphereh = sphere + vec3(0.0,hight,0.0);23 if(distance(outpos,sphereh) <=radius)24 {25 tvel = reflect(vel,normalize(outpos-sphereh))/2.0;26 }27 tvel = tvel + vec3(0.0,-0.5,0.0)*span;28

29 //ground collision

30 if(hight >outpos.y)31 {32 outpos.y =hight;33 tvel = vec3(max(vel.x-span*1.1,0.0),0.0,max(vel.z - span*1.1,0.0));34 }35 //update particle live

36 outtime = time +span;37 if(outtime>=live)38 {39 outpos = vec3(0.0,3.0,hight*5.0);40 outtime = 0.0;41 tvel = vec3(hight,0.0,0.0);42 }43 outvel =tvel;44 }"""

粒子系统着色器代码

整个过程比较简单,也只考虑一些基本的碰撞,比如球的速度也应该影响碰撞后粒子的方向,但是这里只考虑粒子碰撞球后反射的方向,与地面的碰撞后,不会反弹,会慢慢停止向前移动。

最后一些相关着色器的参数设置代码。

1 this.particleProgram =glCreateProgram()2 this.particleProgram =ShaderProgram(this.particleProgram)3 particleshader =shaders.compileShader(particle_v,GL_VERTEX_SHADER)4 glAttachShader(this.particleProgram,particleshader)5 LP_LP_c_char =POINTER(POINTER(c_char))6 ptrs = (c_char_p * 3)('outpos', 'outvel','outtime')7 c_array =cast(ptrs, LP_LP_c_char)8 glTransformFeedbackVaryings(this.particleProgram, len(ptrs), c_array, GL_INTERLEAVED_ATTRIBS)9 glLinkProgram(this.particleProgram)10 this.particleProgram.pos = glGetAttribLocation(this.particleProgram,"pos")11 this.particleProgram.vel = glGetAttribLocation(this.particleProgram,"vel")12 this.particleProgram.time = glGetAttribLocation(this.particleProgram,"time")13 this.particleProgram.span = glGetUniformLocation(this.particleProgram,"span")14 this.particleProgram.live = glGetUniformLocation(this.particleProgram,"live")15 this.particleProgram.plane = glGetUniformLocation(this.particleProgram,"plane")16 this.particleProgram.planeSacle = glGetUniformLocation(this.particleProgram,"planeSacle")17 this.particleProgram.sphere = glGetUniformLocation(this.particleProgram,"sphere")

粒子系统参数设置

在本文中,试着用了5千W个粒子,发现初始化很慢,花了十几秒,但是桢数和5000个粒子基本没有差别,从这里可以看出,GPU并行处理的强大之处。

完整代码:PythonGPU粒子系统.zip 操作方式EDSF前后左右移动,WR分别向上与向下,鼠标右键加移动鼠标控制方向,V切换第一人称与第三人称。UP与DOWN切换前面操作的移动幅度。

python粒子特效_初试PyOpenGL四 (Python+OpenGL)GPU粒子系统与基本碰撞相关推荐

  1. python 粒子动画_初试PyOpenGL四 (Python+OpenGL)GPU粒子系统与基本碰撞

    我认为比较完善的GPU粒子系统应该如下,粒子初始化可以放在CPU里,但是相关数据运算首先要放在GPU里,并且运算后的数据也应该放在显存里,而不是内存里.故用第三篇实现GPU粒子系统不满足,因为他数据是 ...

  2. python opengl书籍_初试PyOpenGL一 (Python+OpenGL)

    很早就一直想学Python,看到一些书都有介绍,不管是做为游戏的脚本语言,还是做为开发项目的主要语言都有提及(最主要的CUDA都开始支持Python,CUDA后面一定要学),做为先熟悉一下Python ...

  3. python opengl 截图_初试PyOpenGL二 (Python+OpenGL)基本地形生成与高度检测

    在上文中,讲述了PyOpenGL的基本配置,以及网格,球形的生成,以及基本的漫游.现在利用上一篇的内容,来利用高程图实现一个基本的地形,并且,利用上文中的第三人称漫游,以小球为视角,来在地形上前后左右 ...

  4. python编程基础_月隐学python第2课

    python编程基础_月隐学python第2课 学习目标 掌握变量的输入和输出 掌握数据类型的基本概念 掌握算数运算 1.变量的输入和输出 1.1 变量输入 使用input输入 input用于输入数据 ...

  5. 查看Python的版本_查看当前安装Python的版本

    一.查看Python的版本_查看当前安装Python的版本 具体方法: 首先按[win+r]组合键打开运行: 然后输入cmd,点击[确定]: 最后执行[python --version]命令即可. 特 ...

  6. python opencv手册_教你用Python实现5毛钱特效(给你的视频来点料)

    一.前言 请务必看到最后.Python牛已经不是一天两天的事了,但是我开始也没想到,Python能这么牛.前段时间接触了一个批量抠图的模型库,而后在一些视频中找到灵感,觉得应该可以通过抠图的方式,给视 ...

  7. python并行运算库_最佳并行绘图Python库简介:“ HiPlot”

    python并行运算库 HiPlot is Facebook's Python library to support visualization of high-dimensional data ta ...

  8. python了解一下_想要精通python?19个语法了解一下!

    原标题:想要精通python?19个语法了解一下! Python简单易学,但又博大精深.许多人号称精通Python,却不会写Pythonic的代码,对很多常用包的使用也并不熟悉.学海无涯,我们先来了解 ...

  9. net能和python结合吗_如何不用安装python就能在.NET里调用Python库

    前言 Pythonnet这个屌爆的项目的出现,使得我们可以用一种新的方式,让C#可以和Python之间进行互操作.但是它的设置和部署可能有点问题,真的是这样吗? 本文我会介绍Python.Includ ...

  10. 我的世界python写游戏_快来试试Python写的游戏《我的世界》

    <我的世界 Minecraft>大家应该都听说过,但你有没有想过自己用Python写一个这样的游戏呢?太难.太复杂了?也许吧,但是不试一试你怎么知道能不能成呢? 国外有位叫fogleman ...

最新文章

  1. HDR sensor 原理介绍
  2. Apache关掉Etag和Last-Modified的方法
  3. Hadoop streaming 排序、分桶参数设置
  4. win2012 R2的ntp时间同步设置解析
  5. python难度如何_入门Python学习难吗怎样规划学习路线
  6. Dynpro程序抬头信息要求多值输入的解决方法
  7. 日常生活 -- 感悟
  8. [翻译练习] 对视图控制器压入导航栈进行测试
  9. 【数据库系统】SQL修改的注意事项
  10. java十进制转十六进制
  11. 解决属性名和字段名不一致的问题(Mybatis)
  12. AS/400开发经验点滴(六)如何制作下拉菜单
  13. 微调StyleGAN2模型
  14. 力扣(647.516)补9.15
  15. web大二实训作业:校园运动会网站设计——运动会图片轮播图片遮罩特效(4页)体育 HTML+CSS+JavaScript HTML5期末大作业...
  16. VUE2 组件间传值
  17. php 答题 一页一题,微信小程序答题,怎么设计页面渲染,答完一题,跳到下一题...
  18. 《机器学习》周志华课后习题答案——第五章(1-7已完结)
  19. Jmeter安装配置详细教程
  20. 小扎、马斯克宣战ChatGPT!Meta和推特组建顶级AI团队,硅谷硝烟四起

热门文章

  1. VirtualBox-5.2.44的安装
  2. java liveness_存活探针(liveness probe)
  3. 怎么用dos系统进入服务器,进入纯DOS系统的步骤分享
  4. 【数据结构】平行四边形数量
  5. java中,参数后面跟三个点(...)的含义
  6. QQ快速登录协议分析以及风险反思
  7. 什么是ARM开发板及其硬件特性介绍
  8. 深入浅出CChart 每日一课——快乐高四第二十课 七月流火,总复习之CChart多种编程模式
  9. 靶机渗透练习21-Noob
  10. 服务器托管费用怎么计算?