将顶点保存到纹理并传递给着色器
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 坐标中添加噪声值来移动粒子。这就是为什么我想将数据放入纹理中,以便能够读取下一次迭代的粒子坐标并添加新的位移。 是吗?这个点一开始并没有为我移动(现在它正在移动)。并且不动=您的着色器没有交互。这就是我解决的问题,我相信你现在走在正确的道路上。然而,如前所述,我无法自己编写代码。如果您觉得自己编写代码太难了,那么也许您应该暂时搁置它...那么我仍然很乐意提供帮助。以上是关于将顶点保存到纹理并传递给着色器的主要内容,如果未能解决你的问题,请参考以下文章