var attributes = {
displacement: {
type: 'f', // 浮点数
value: [] // 空数组
}
};
var vShader = $('#vertexshader');
var fShader = $('#fragmentshader');
// 创建一个包含attribute属性的着色器材质
var shaderMaterial =
new THREE.MeshShaderMaterial({
attributes: attributes,
vertexShader: vShader.text(),
fragmentShader: fShader.text()
});
// 向displacement中填充随机数
var verts = sphere.geometry.vertices;
var values = attributes.displacement.value;
for(var v = 0; v < verts.length; v++) {
values.push(Math.random() * 30);
}
这样,就可以看到一个变形的球体了。最Cool的是:所有这些变形都是在GPU中完成的。
4.动起来
要使这东西动起来,应该怎么做?好吧,应该做这两件事情。
一个uniform变量amplitude,在每一帧控制displacement实际造成了多少位移。我们可以使用正弦或余弦函数来在每一帧中生成它,因为这两个函数的取值范围从-1到1。
一个帧循环。
我们需要将这个uniform变量加入到着色器材质中,同时也需要加入到顶点着色器中。先来看顶点着色器:
复制代码 代码如下:
uniform float amplitude;
attribute float displacement;
varying vec3 vNormal;
void main() {
vNormal = normal;
// 将displacement乘以amplitude,当我们在每一帧中平滑改变amplitude时,画面就动起来了
vec3 newPosition =
position +
normal *
vec3(displacement *
amplitude);
gl_Position = projectionMatrix *
modelViewMatrix *
vec4(newPosition, 1.0);
}
然后更新着色器材质:
复制代码 代码如下:
var uniforms = {
amplitude: {
type: 'f', // a float
value: 0
}
};
var vShader = $('#vertexshader');
var fShader = $('#fragmentshader');
// 创建最终的着色器材质
var shaderMaterial =
new THREE.MeshShaderMaterial({
uniforms: uniforms,
attributes: attributes,
vertexShader: vShader.text(),
fragmentShader: fShader.text()
});
我们的着色器也已经就绪了。但我们好像又倒退了一步,屏幕中又只剩下光滑的球了。别担心,这是因为amplitude值设置为0,因为我们将amplitude乘上了displacement,所以现在看不到任何变化。我们还没设置循环呢,所以amplitude只可能是0.
在我们的JavaScript中,需要将渲染过程打包成一个函数,然后用requestAnimationFrame去调用该函数。在这个函数里,我们更新uniform(译者注:即amplitude)的值。
复制代码 代码如下:
var frame = 0;
function update() {
// amplitude来自于frame的正弦值
uniforms.amplitude.value =
Math.sin(frame);
// 更新全局变量frame
frame += 0.1;
renderer.render(scene, camera);
// 指定下一次屏幕刷新时,调用update
requestAnimFrame(update);
}
requestAnimFrame(update);
5.小结
就是它了!你看到球体正在奇怪地脉动着。关于着色器,还有太多的内容没有讲到呢,但是我希望这篇教程能够对你有一些帮助。现在,当你看到一些其他的着色器时,我希望你能够理解它们,而且你应该有信心去创建自己的着色器了!
和往常一样,我将这一课的源码打包了
您可能感兴趣的文章: