将顶点保存到纹理并传递给着色器

Posted

技术标签:

【中文标题】将顶点保存到纹理并传递给着色器【英文标题】:Save vertices to texture and pass to shader 【发布时间】:2014-06-25 23:59:21 【问题描述】:

终于有时间玩着色器了,但有一刻卡住了。我想将顶点传递给着色器并在其上制作一些 gpgpu。

Gpgpu 工作正常,我猜是因为我看到几个像素和一个在中心的像素被推到一边,因为我输入代码只是为了测试。

现在我想传递球体顶点。这是我正在采取的步骤。请指出错误:-)

编辑:添加小提琴 - click here

1) 创建几何图形,并将其传递给数据数组。

geometry = new THREE.SphereGeometry( 0.2, 15, 15 );
console.log(geometry.vertices.length);
var a = new Float32Array(geometry.vertices.length * 4);
for(var k=0; k<geometry.vertices.length; k++) 
                a[ k*4 + 0 ] = geometry.vertices[k].x;
                a[ k*4 + 1 ] = geometry.vertices[k].y;
                a[ k*4 + 2 ] = geometry.vertices[k].z;
                a[ k*4 + 3 ] = 1;   

2) 保存在数据纹理中

posTexture[2] = new THREE.DataTexture(a, 16, 16, THREE.RGBAFormat, THREE.FloatType);

3) 设置“设置场景”(它应该将数据纹理传递给它一次) setUniforms = posTexture:类型:“t”,值:posTexture [2] ;

var setMaterial = new THREE.ShaderMaterial(
    uniforms: setUniforms,
    vertexShader:   document.getElementById('setVert').textContent,
    fragmentShader: document.getElementById('setFrag').textContent,
    wireframe: true
);

var setPlane = new THREE.Mesh(new THREE.PlaneGeometry(16,16), setMaterial);
setScene.add(setPlane);

4) 设置着色器。

<script type="x-shader/x-vertex" id="setVert">

    // switch on high precision floats
    #ifdef GL_ES
    precision highp float;
    #endif
    varying vec2 vUv;
    uniform sampler2D posTexture;

    void main()
        vUv = uv;
        gl_Position = projectionMatrix * modelViewMatrix * vec4(position,1.0);
    

</script>
<script type="x-shader/x-fragment" id="setFrag">

    #ifdef GL_ES
    precision highp float;
    #endif
    uniform sampler2D posTexture;
    varying vec2 vUv;

    void main()
        vec3 color = texture2D( posTexture, vUv ).xyz;

        gl_FragColor = vec4(col, 1.0);
    
</script>

5) 动画它!!! start 设置 SetShader 以保存数据并将 WebGLRenderTarget 输出到下一个着色器:一个负责计算并返回带有坐标的纹理,下一个用于显示

function animate() 

    requestAnimationFrame(animate);
    renderer.setViewport(0,0,16, 16);
    if(buffer == 0) 
        buffer = 1;
        a = 0;
        b = 1;
     else 
        buffer = 0;
        a = 1;
        b = 0;
    

    if(start) 
        renderer.render(setScene, processCamera, posTexture[a]);
        start = false;
    

    posUniforms.posTexture.value = posTexture[a];
    renderer.render(posScene, processCamera, posTexture[b])
    dispUniforms.posTexture.value = posTexture[b];
    renderer.setViewport(0,0,dispSize.x, dispSize.y);
    renderer.render(scene, camera);


【问题讨论】:

一方面,您的片段着色器甚至不应该编译(col 未定义)。另外,一个RGBA纹理是Unsigned归一化的;您通常不希望将顶点位置直接吐到这种纹理中,因为您将丢失任何 0.5 并在将位置写入gl_FragColor 之前添加 0.5 以输出到纹理。 那么这个位置是怎么保存的呢? chromeexperiments.com/detail/one-million-particles/?f= 【参考方案1】:

我不得不稍微润色一下着色器代码,我觉得有点乱^^http://jsfiddle.net/ec5zU/1/

嗯,您正在尝试将球体顶点向下推到 gpu。您想要这样做的事实表明您可能不太了解 gpgpu 的概念。它可以在 GPU 上计算东西(算法、数学)。这是一个在不执行/显示 3D 相关内容的情况下使用 GPU 的概念。

将球体顶点传递给纹理,然后用该纹理做一些事情对我来说毫无意义——但也许我只是不太明白你想要做什么。那么您能否详细说明您使用 gpgpu 方法的最终目标?

在演示中使用纹理的原因如下:您可以轻松地将数据从 CPU(javascript)移动到 GPU(例如使用制服、属性),但反过来就更难了。一种可能性是为您的 GPU 设置一个单独的渲染目标,这样您将在渲染周期完成后将其保存为纹理。然后你有点“存储你的数据”。

将 cmets 包括在这个答案中我想说的是:我建议学习更多关于着色器和 three.js 的知识,因为大多数时候事情可以做得更容易和更好。如果那个演示案例很重要,那么尝试实现我和 Andon M. Coleman 给你的修复,想想你的球体逻辑以及你想如何实现它,因为你现在做的方式也不行很有道理……

如果您确定没有比每帧在纹理上创建和重新分配位置更好的方法,那就这样吧:) 我又玩了一个小时,添加了 cmets,更改了一些东西,修复了最糟糕的部分,然后现在你看到一个红点在屏幕上移动:http://jsfiddle.net/ec5zU/2/ 我不会再投入任何时间了,因为我认为 *** 并不是要对你的项目进行编码^^ 我希望我能提供一些帮助,并且你有一个再次开始,因为现在有些东西实际上正在“工作和移动”。祝你好运,玩得开心!

(*** 告诉我要包含一些代码。所以底部有一些经过优化的着色器代码。)

   <script type="x-shader/x-fragment" id="fragmentshader">

        precision highp float;

        varying vec2 vUv;
        uniform sampler2D posTexture;

        void main()
        
            vec3 color = texture2D(posTexture, vUv).rgb;
            color.x += 0.01;
            gl_FragColor = vec4(color, 1.0);

        

    </script>

【讨论】:

我想用一些函数扭曲和动画球体,所以我认为 gpgpu 将是完美的?否则你怎么能得到以前的职位?我试图像这里chromeexperiments.com/detail/one-million-particles/?f= 那样做,但显然我失败了...... 那么你想要做的就是在屏幕上显示一堆像素..?你不需要gpgpu,忘了它。有几种方法可以解决这个问题,最明显和最灵活的(也是最简单的,因为它由 THREE.js 预编码)是 THREE.ParticleSystem。然后,您将创建一个自定义顶点和片段着色器(每个只有 1 个),其中包含一些逻辑。如果您不知道片段/顶点着色器是什么或如何创建一个,我建议您阅读一些教程,例如 aerotwist.com/tutorials/an-introduction-to-shaders-part-1。 因此,从 THREE.js 的角度来看,您要做的就是创建一个带有“位置”属性的 BufferGeometry(有很多示例),并可能用 10 万个位置填充它。首先尝试使用“ParticleSystemMaterial”,当它运行良好时,您可以像上面的教程一样创建自定义着色器,并使用该着色器代替 THREE.ParticleSystemMaterial。在这些着色器中,您可以拥有自己的逻辑:在顶点着色器中,您定义现在的位置,在片段着色器中定义它的外观。 我想计算着色器内部的噪声,而不是将其作为属性传递。我需要之前的位置,因为它会从给定的 xyz 坐标中添加噪声值来移动粒子。这就是为什么我想将数据放入纹理中,以便能够读取下一次迭代的粒子坐标并添加新的位移。 是吗?这个点一开始并没有为我移动(现在它正在移动)。并且不动=您的着色器没有交互。这就是我解决的问题,我相信你现在走在正确的道路上。然而,如前所述,我无法自己编写代码。如果您觉得自己编写代码太难了,那么也许您应该暂时搁置它...那么我仍然很乐意提供帮助。

以上是关于将顶点保存到纹理并传递给着色器的主要内容,如果未能解决你的问题,请参考以下文章

顶点纹理获取(在顶点着色器中读取纹理)

传递给片段着色器的纹理坐标全部为 0

将无符号整数输入属性传递给顶点着色器

通过顶点属性指针将颜色坐标传递到顶点着色器

OpenGL:为啥我不能将单个浮点数从顶点着色器传递到片段着色器?

将属性传递给 OpenGL 顶点着色器的行为很奇怪