[MetalKit]41-Working-with-Particles-in-Metal-part3粒子系统3

本系列文章是对 metalkit.org 上面MetalKit内容的全面翻译和学习.c++

MetalKit系统文章目录git


上次咱们关注的是如何操纵GPU上的Model I/O对象的顶点.本文咱们用另外一种方式来经过计算线程来建立粒子.咱们能够重用上次的playground,从修改metal视图代理类的Particle结构体开始,只须要包含两个GPU更新用的成员就好了-positionvelocity:github

struct Particle {
    var position: float2
    var velocity: float2
}
复制代码

咱们还能够删除timer变量, 及translate(by:)update() 方法了.改得最多的是initializeBuffers() 方法:swift

func initializeBuffers() {
    for _ in 0 ..< particleCount {
        let particle = Particle(
        		position: float2(Float(arc4random() %  UInt32(side)), 
        				Float(arc4random() % UInt32(side))), 
        		velocity: float2((Float(arc4random() %  10) - 5) / 10, 
        				(Float(arc4random() %  10) - 5) / 10))
        particles.append(particle)
    }
    let size = particles.count * MemoryLayout<Particle>.size
    particleBuffer = device.makeBuffer(bytes: &particles, length: size, options: [])
}
复制代码

注意:咱们在整个窗口范围内生成随机位置,并生成[-5,5]范围内的速度值.将其除以10以让速度慢下来.数组

最重要的部分则是在配置指令编码器时.设置threads per group数量为2D网格,一边为thread execution width,另外一边为maximum total threads per threadgroup,这两个值是GPU的硬件特征值,且在执行期间不会改变.设置threads per grid为一维数组,size由粒子数量决定:app

let w = pipelineState.threadExecutionWidth
let h = pipelineState.maxTotalThreadsPerThreadgroup / w
let threadsPerGroup = MTLSizeMake(w, h, 1)
let threadsPerGrid = MTLSizeMake(particleCount, 1, 1)
commandEncoder.dispatchThreads(threadsPerGrid, threadsPerThreadgroup: threadsPerGroup)
复制代码

注意:在新的Metal 2中,dispatchThreads(:) 能够不指定线程组数而直接工做.与使用旧的dispatchThreadgroups(:) 方法相比,新方法计算组数,并当网格尺寸不是组尺寸的倍数时提供nonuniform thread groups,并确保没有未使用的线程.dom

回到内核着色器中,首先匹配CPU中的粒子结构体,而后在内核中更新位置和速度:ide

Particle particle = particles[id];
float2 position = particle.position;
float2 velocity = particle.velocity;
int width = output.get_width();
int height = output.get_height();
if (position.x < 0 || position.x > width) { velocity.x *= -1; }
if (position.y < 0 || position.y > height) { velocity.y *= -1; }
position += velocity;
particle.position = position;
particle.velocity = velocity;
particles[id] = particle;
uint2 pos = uint2(position.x, position.y);
output.write(half4(1.), pos);
output.write(half4(1.), pos + uint2( 1, 0));
output.write(half4(1.), pos + uint2( 0, 1));
output.write(half4(1.), pos - uint2( 1, 0));
output.write(half4(1.), pos - uint2( 0, 1));
复制代码

注意:咱们作了边界检测,当遇到边界时将速度取反,使粒子不会离开屏幕.还有一个小技巧,经过渲染出相邻的四个粒子来让整个粒子看起来更大点.post

你能够设置particleCount1000000,但这样会花费好几秒来渲染所有粒子.我只用了10000个粒子,这样它们在屏幕上不会显得太挤.运行一下app,你会看到粒子随机来回移动: 学习

particles3.gif

至此,粒子渲染系统结束,感谢FlexMonkey分享对计算概念的看法,源代码source code已发布在Github上.

下次见!

相关文章
相关标签/搜索