Javascript 从着色器读取数据

Javascript 从着色器读取数据,javascript,canvas,three.js,shader,Javascript,Canvas,Three.js,Shader,我正在努力学习如何利用gpu的潜力来处理threejs和webgl之类的东西,所以我只是在分析代码以获得一些模式、方法以及如何完成事情,我需要一些代码解释 我发现了这个例子:,这似乎是最简单的一个,涉及到在着色器中进行的计算,并将其吐出 因此,根据我的发现: -粒子的速度和位置数据保存在传递给着色器的纹理中,以便在那里执行计算,并将其返回以进行更新 粒子在平面上随机创建,不超过纹理大小 对于(变量i=0;i

我正在努力学习如何利用gpu的潜力来处理threejs和webgl之类的东西,所以我只是在分析代码以获得一些模式、方法以及如何完成事情,我需要一些代码解释

我发现了这个例子:,这似乎是最简单的一个,涉及到在着色器中进行的计算,并将其吐出

因此,根据我的发现: -粒子的速度和位置数据保存在传递给着色器的纹理中,以便在那里执行计算,并将其返回以进行更新

  • 粒子在平面上随机创建,不超过纹理大小

    对于(变量i=0;i<1000000;i++){

    数学地板(i/texSize)/texSize,0) ; }

  • 我看不到任何粒子位置更新?如何从着色器中检索和更新每个粒子的数据

    挑选 仅通过鼠标位置来计算粒子移动的方向

  • 为什么有两个缓冲区?和8(4对片段和向量)着色器?仅仅计算速度和位置是不够的吗

  • 着色器如何更新纹理?我只是看到从中阅读而不是写作

提前感谢您的解释

他们到底是怎么做到的: 在这篇文章中,我将解释如何通过WebGL/Three.js几乎完全在gpu上计算这些结果——因为我使用的是Intel i7 4770k的集成图形,所以看起来可能有点马虎:


导言: 将所有内容保持在gpu内的简单方法:每个粒子的状态将由一个纹理像素颜色值表示。一百万个粒子将产生1024x1024像素的纹理,一个用于保持当前位置,另一个用于保持这些粒子的速度

没有人禁止将纹理的RGB颜色值用于0…255的完全不同的数据。基本上,每个纹理像素都有32位(R+G+B+alpha),用于存储在GPU内存中的任何内容。(如果每个粒子/对象需要存储更多数据,甚至可以使用多个纹理像素)

他们基本上是按顺序使用多个着色器。从源代码中,可以识别其处理管道的以下步骤:

  • 随机化粒子(在这个答案中被忽略)('randShader')
  • 根据每个粒子到鼠标位置的距离确定其速度('velShader')
  • 根据速度,相应地移动每个粒子('posShader')
  • 显示屏幕('dispShader')**

  • 步骤2:确定每粒子的速度: 他们在一百万点上调用一个绘制过程,其输出将保存为纹理。在顶点着色器中,每个片段获得两个名为“vUv”
    的附加变量,它们基本上确定了该过程中使用的纹理内的x和y像素位置

    下一步是它的片段着色器,因为只有该着色器可以输出(作为RGB值输入帧缓冲区,之后会转换为纹理缓冲区-所有这些都只发生在gpu内存中)。您可以在
    id=“velFrag”
    fragment着色器中看到,它获取一个名为
    uniform vec3 targetPos的输入变量。这些一致性是通过CPU的每一帧廉价设置的,因为它们在所有实例之间共享,并且不涉及大型内存传输。(包含鼠标坐标,可能在-1.00f到+1.00f的范围内-它们也可能每隔几帧更新一次鼠标坐标,以降低cpu使用率)

    这是怎么回事?该着色器计算粒子到鼠标坐标的距离,并根据该距离改变粒子速度-该速度还包含有关粒子飞行方向的信息。注意:此速度步也会使粒子获得动量,并根据灰度值保持飞行/超调鼠标位置


    步骤3:更新每个粒子的位置: 到目前为止,每个粒子都有一个速度和一个先前的位置。这两个值将被处理到一个新的位置,再次作为一个纹理输出——这次是到positionTexture。在渲染整个帧(进入默认帧缓冲区)并标记为新纹理之前,旧的positionTexture保持不变,并且可以轻松读取:

    id=“posFrag”
    fragment着色器中,它们从两种纹理(posTexture和velTexture)读取数据,并将这些数据处理到一个新位置。它们将x和y位置坐标输出到该纹理的颜色中(作为红色和绿色值)


    步骤4:黄金时段(=输出) 为了输出结果,他们可能再次获取一百万个点/顶点,并将positionTexture作为输入。然后,“顶点着色器”(vertex shader)通过读取位置x、y处纹理的RGB值(作为顶点属性传递)来设置每个点的位置

    //来自
    vec3 mvPosition=texture2D(posTex,vec2(x,y)).rgb;
    gl_PointSize=1.0;
    gl_位置=projectionMatrix*modelViewMatrix*vec4(mvPosition,1.0);
    
    在“显示片段着色器”(display fragment shader)中,它们只需要设置一种颜色(请注意低alpha,使其允许20个粒子叠加以完全照亮一个像素)

    //来自
    gl_FragColor=vec4(vec3(0.5,1.0,0.1,0.05);
    



    我希望这清楚地说明了这个小演示的工作原理:-)不过,我不是那个演示的作者。刚刚注意到这个答案实际上变成了一个超级重复的详细答案——通过粗关键词来获得短版本。

    您链接的示例不适用于我。请参见以下three.js示例:。谷歌“GPGPU”。谷歌“GPGPU乒乓球”。理想情况下,数据不会像您假设的那样“为更新”传回CPU——所有计算都在GPU上执行。@WestLangley如果数据没有传回CPU,则会存储在纹理数据中,并在下一次迭代中读取
    particles.vertices.push(new THREE.Vector3((i % texSize)/texSize,
    
    // From <script type="x-shader/x-vertex" id="dispVert">
    vec3 mvPosition = texture2D(posTex, vec2(x, y)).rgb;
    gl_PointSize = 1.0;
    gl_Position = projectionMatrix * modelViewMatrix * vec4(mvPosition,1.0);
    
    // From <script type="x-shader/x-fragment" id="dispFrag">
    gl_FragColor = vec4(vec3(0.5, 1.0, 0.1), 0.05);