上一篇说顶点着色器和片元着色器的皮毛,这篇郭先生说一说着色器变量,通过变量可以设置材质。先看看今天要做的如下图。在线案例请点击红绿灯。
捕获42.PNG
在这个案例之前,我们先复习一下着色器变量
嗯,现在我们知道了这些变量的用法,接下来我们使用它。
要制作这样一个红绿灯,我们考虑使用Geometry的merge方法
var shape = new THREE.Shape();
shape.moveTo(-10, 20);
shape.absarc(0, 20, 10, Math.PI, Math.PI * 2, true);
shape.lineTo(10, -20);
shape.absarc(0, -20, 10, 0, Math.PI, true );
shape.lineTo(-10, 20);
var extrudeSettings = {
steps: 2, //用于沿着挤出样条的深度细分的点的数量,默认值为1
depth: 5, //挤出的形状的深度,默认值为100
bevelEnabled: true, //对挤出的形状应用是否斜角,默认值为true
bevelThickness: 1, //设置原始形状上斜角的厚度。默认值为6
bevelSize: 1, //斜角与原始形状轮廓之间的延伸距离
bevelSegments: 10, //斜角的分段层数,默认值为3
curveSegments: 12, //曲线上点的数量,默认值是12
};
var frame = new THREE.ExtrudeGeometry(shape, extrudeSettings);
// var material = new THREE.MeshPhongMaterial({color: 0x222222, emissive: 0x222222});
var cylinGeom = new THREE.CylinderGeometry(6, 6, 6, 30, 20);
frame.merge(cylinGeom.clone(), new THREE.Matrix4().compose(new THREE.Vector3(0, 15, 3.1), new THREE.Quaternion().setFromAxisAngle(new THREE.Vector3(1,0,0), Math.PI/2), new THREE.Vector3(1,1,1)));
frame.merge(cylinGeom.clone(), new THREE.Matrix4().compose(new THREE.Vector3(0, 0, 3.1), new THREE.Quaternion().setFromAxisAngle(new THREE.Vector3(1,0,0), Math.PI/2), new THREE.Vector3(1,1,1)));
frame.merge(cylinGeom.clone(), new THREE.Matrix4().compose(new THREE.Vector3(0, -15, 3.1), new THREE.Quaternion().setFromAxisAngle(new THREE.Vector3(1,0,0), Math.PI/2), new THREE.Vector3(1,1,1)));
通过ExtrudeGeometry挤压出我们想要的几何体,然后添加三个圆柱体,形成我们想要的几何体。
现在使用uniform变量
uniforms = {
time: {
type: 'f', value: 0.0
}
}
这里我们在其中设置一个叫做time的变量,它的类型是一个float类型,默认值设置成0.0。然后我们在requestAnimationFrame的每一帧动画中调用uniforms.time.value += 0.01;让着色器动起来。
顶点着色器我们不做太多操作
varying vec3 vPosition;
uniform float time;
void main() {
vPosition = position;
gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );
}
这里我们定义一个三维向量vPosition,用来将顶点着色器里面的position属性传递到片元着色器中(three.js会默认传入一些属性,像uv,position,normal等)
varying vec3 vPosition;
uniform float time;
void main() {
float time = mod(time, 3.0);//time值对3取模,得到[0,3)范围内的值。
//由于我们制作红绿灯时用了小技巧,让其z分量比较大,所以可以根据z的值判断是否为红绿灯面。然后在根据y值,判断为哪个灯。
if(vPosition.z == 6.1 && vPosition.y > 8.0) {
if(time < 1.0) {//时间为[0,1)红灯
gl_FragColor=vec4(1.0, 0.0, 0.0, 1.0);
} else {
gl_FragColor=vec4(0.2, 0.0, 0.0, 1.0);
}
} else if(vPosition.z == 6.1 && vPosition.y > -8.0) {//时间为[1,2)黄灯
if(time >= 1.0 && time < 2.0) {
gl_FragColor=vec4(1.0, 0.7, 0.0, 1.0);
} else {
gl_FragColor=vec4(0.2, 0.1, 0.0, 1.0);
}
} else if(vPosition.z == 6.1) {//时间为[2,3)绿灯
if(time >= 2.0) {
gl_FragColor=vec4(0.0, 1.0, 0.0, 1.0);
} else {
gl_FragColor=vec4(0.0, 0.2, 0.0, 1.0);
}
} else {//其余部分为灰色
gl_FragColor=vec4(0.2, 0.2, 0.2, 1.0);
}
}
这里我们使用顶点着色器传过来的向量vPosition和uniform中的time值做一些判断,实现对每个点颜色进行控制(根据颜色插值从而实现颜色面的控制),里面使用了一些方法,例如mod,请参见上一篇文章。
虽然这个小案例很简单,但是我相信大家肯定有了很好的想法,这几篇都是比较基础的,后面还有很多好看的案例,喜欢就点个赞吧!
转载请注明地址:郭先生的博客