第一步:给模子添加光带
起首创建一个立方体,不举行任何缩放平移操纵,也不要set position。
底子代码如下:
在顶点着色器代码里varying vec3 vPosition;vPosition = position;得到threejs主动计算的顶点坐标插值(也就是这个模子上每个点的xy坐标),然后在片元着色器代码里同样varying vec3 vPosition;来获取xy坐标值。
先设置整体颜色gl_FragColor = vec4(0.0,1.0,1.0,1.0);
然后再通过if条件判定,符合条件的片元设置其他颜色,光带就形成了。
gl_Position = projectionMatrix*viewMatrix*modelMatrix*vec4( position, 1.0 );是固定写法,你可以试下去掉会发生什么。
- import * as THREE from 'three';
- const geometry = new THREE.BoxGeometry(30,60,30);
- const vertexShader = `
- varying vec3 vPosition;//表示顶点插值后位置数据,与片元数量相同,一一对应
- void main(){
- vPosition = position;// 顶点位置坐标插值计算
- // 投影矩阵 * 视图矩阵 * 模型矩阵 * 模型顶点坐标
- gl_Position = projectionMatrix*viewMatrix*modelMatrix*vec4( position, 1.0 );
- }
- `;
- const fragmentShader = `
- varying vec3 vPosition;
- void main(){
- // 设置整体颜色
- gl_FragColor = vec4(0.0,1.0,1.0,1.0);
- // 当vPosition.y的位置符合if条件时,设置其他颜色,就会形成光带
- if(vPosition.y > 20.0 && vPosition.y < 22.0 ){
- gl_FragColor = vec4(1.0,1.0,0.0,1.0);
- }
- }
- `;
- // 以下代码是使用着色器材料进行颜色设置
- export const material = new THREE.ShaderMaterial({
- //顶点着色器对象vertexShader
- vertexShader: vertexShader,
- // 片元着色器对象fragmentShader
- fragmentShader: fragmentShader
- });
- export const model = new THREE.Mesh(geometry, material);
复制代码 在y坐标20的地方,有一条宽度为2的光带,由于限制条件是20<y<22。
第二步:让光带动起来
想要让光带动起来,只必要限制条件也动起来,好比之前的20<y<22,要让这两个数字随时间发生变化。这时间必要在shader材质里利用uniforms界说一个对象变量startY,包含value属性。
- export const material = new THREE.ShaderMaterial({
- uniforms:{
- startY:{value:-30.0} //立方体位于原点,y的最小值是-30.0,而不是0.0
- },
- //顶点着色器对象vertexShader
- vertexShader: vertexShader,
- // 片元着色器对象fragmentShader
- fragmentShader: fragmentShader
- });
复制代码 在片元着色器里接收uniform里的变量,名字必须跟shader材质里界说的雷同,留意这里是uniform,shader材质里是uniforms,将vPosition.y的范围限定在startY和startY+2.0之间。
- const fragmentShader = `
- varying vec3 vPosition;
- uniform float startY;
- void main(){
- // 设置整体颜色,不然模型会设置为默认白色
- gl_FragColor = vec4(0.0,1.0,1.0,1.0);
- // 当vPosition.y的位置符合if条件时,设置其他颜色,就会形成光带
- if(vPosition.y > startY && vPosition.y < startY + 2.0 ){
- gl_FragColor = vec4(1.0,1.0,0.0,1.0);
- }
- }
- `;
复制代码 在渲染循环里让startY不断改变,片元着色器里的startY跟着变化,光带就动起来了。
特别留意,startY的起始值是-30.0,而不是0.0,startY的最大值是30.0,由于vPosition.y是浮点型数据,在对其举行计算的变量也必须是浮点型。
- // 渲染循环
- function render() {
- material.uniforms.startY.value += 0.5;
- // 当y超过模型高度后,y重置到模型底部
- if(material.uniforms.startY.value>30.0){
- material.uniforms.startY.value = -30.0;
- }
- renderer.render(scene, camera);
- requestAnimationFrame(render);
- }
复制代码
这时会发现光带移动到顶部的时间,会出现闪烁,我们把startY的值再缩小一点,克制这个题目。
之前是material.uniforms.startY.value>30.0 的时间,startY重置,改成material.uniforms.startY.value>25.0没这个现象了,详细上限是多少,跟模子高度和光带宽度有关,根据自己的实际项目来设置即可。
第三步:美化光带
光带的上半部门,从下往上,从光带颜色渐变到模子自己的颜色;下半部门,从上往下,从光带颜色渐变到模子自己的颜色。
- const fragmentShader = `
- varying vec3 vPosition;
- uniform float startY;
- const float bandWidth = 20.0;//光带宽度
- float halfBandWidth = bandWidth*0.5;//光带宽度的一半
- const vec3 bandColor = vec3(1.0,0.0,0.0);//光带的颜色
- const vec3 baseColor = vec3(0.0,1.0,1.0);//模型本身的颜色
- void main(){
- // 设置整体颜色,不然模型会设置为默认白色
- gl_FragColor = vec4(baseColor,1.0);
- // 光带上半部分
- if(vPosition.y > startY && vPosition.y < startY + halfBandWidth ){
- float percent = (vPosition.y-startY)/halfBandWidth;//范围0~1
- gl_FragColor.rgb = mix( bandColor, baseColor, percent);
- }
- // 光带下半部分
- if(vPosition.y <= startY && vPosition.y > startY - halfBandWidth ){
- float percent = (startY - vPosition.y)/halfBandWidth;//范围0~1
- gl_FragColor.rgb = mix( bandColor, baseColor, percent);
- }
- }
- `;
复制代码 为了更方便看渐变色效果,先把光带移动停下了,光带加宽,光带设置为红色。
留意:gl_FragColor是vec4类型,表示片元颜色的rgba,gl_FragColor.rgb表示当前片元颜色的rgb,不带a(透明度)。
mix是着色器语言GLSL ES的内置函数,可以直接利用,好比参数1和2分表示一个颜色值,通过参数3百分比per,就可以控制两个颜色color1、color2的混淆比例,参数3范围控制在0~1就行。
mix的参数1和2顺序,不用刻意记住,用代码测试下就行,不对就反过来。
mix的两个颜色参数,是vec3的,只包含rgb信息,以是只必要赋值给gl_FragColor.rgb即可,此时默认的透明度是1.0,如果确实必要设置a,可以写成gl_FragColor = vec4( mix( bandColor, baseColor, percent),0.8); 把vec3变成vec4.
要特别留意,光带颜色和模子颜色不要设置为一样,否则就会跟我一样,看不到光带,还以为是代码逻辑有题目,查抄了好几遍才发现。
第四步:增长光带
想要显示多条移动光带,startY不仅要在渲染循环量不断变化,还要在for循环变化,直接写startY += float(i);会报错uniform里的变量不能修改,我们得换个方法,界说另一个uniform变量time,在片元着色器里将time赋值给另一个普通的float变量startY,再在for循环了来改变startY。
- // 以下代码是使用着色器材料进行颜色设置
- export const material = new THREE.ShaderMaterial({
- uniforms:{
- time:{value:0.0} //立方体位于原点,y的最小值是-30.0,而不是0.0
- },
- //顶点着色器对象vertexShader
- vertexShader: vertexShader,
- // 片元着色器对象fragmentShader
- fragmentShader: fragmentShader
- });
复制代码- const fragmentShader = `
- varying vec3 vPosition;
- uniform float time;
-
- const float bandWidth = 4.0;//光带宽度
- const float bandSpacing = 4.0;//光带间隔
- float halfBandWidth = bandWidth*0.5;//光带宽度的一半
- const vec3 bandColor = vec3(1.0,1.0,0.0);//光带的颜色
- const vec3 baseColor = vec3(0.0,1.0,1.0);//模型本身的颜色
- void main(){
- // 设置整体颜色,不然模型会设置为默认白色
- gl_FragColor = vec4(baseColor,1.0);
- float startY = -30.0+time; //-30.0是模型y坐标的起始值
- //循环产生多条光带
- for(int i=0;i<10;i++){
- startY += float(i)+bandSpacing;
- // 光带上半部分
- if(vPosition.y > startY && vPosition.y < startY + halfBandWidth ){
- float percent = (vPosition.y-startY)/halfBandWidth;//范围0~1
- gl_FragColor.rgb = mix( bandColor, baseColor, percent);
- }
- // 光带下半部分
- if(vPosition.y <= startY && vPosition.y > startY - halfBandWidth ){
- float percent = (startY - vPosition.y)/halfBandWidth;//范围0~1
- gl_FragColor.rgb = mix( bandColor, baseColor, percent);
- }
- }
- }
- `;
复制代码- function render() {
- material.uniforms.time.value += 0.5;
- // 当y超过模型高度后,y重置到模型底部
- if(material.uniforms.time.value>15.0){
- material.uniforms.time.value = 0.0;
- }
- renderer.render(scene, camera);
- requestAnimationFrame(render);
- }
复制代码
运行后看效果,顶部又开始了闪烁,必要将vPosition.y的值必要限制一下。
在if条件里加上vPosition.y <30.0,留意,光带的上半部门和下半部门都要加这句话。
我的模子里是小于30,详细小于多少,以自己的项目来调解。
旋转后发现底部也有闪烁,继承做限制vPosition.y >-30.0。
模子底部没有光带,必要将startY的下限继承下移。把-30改成-40,总之要比模子自己y的最小值更小。当time=0的时间,startY等于-40,比模子的底部更低,详细值多少,以自己的项目来调解。
float startY = -40.0+time; //模子y坐标的起始值。
除了调解以上数据,还可以调解time重置的条件,好比time大于10和大于20,效果是差别的。
调解后的效果。
第五步:将光带换成彩色
创建光带颜色数组,在for循环里对数组长度循环取值即可。
换成彩色后,光带直接有一个很大的空隙,这是光带数组中有一个光带颜色跟模子自己的颜色一样,mix后就看不出来光带颜色了,这也是一个必要留意的地方,换个模子颜色后,间隔恢复正常了。
 
完整代码:
- import * as THREE from 'three';const geometry = new THREE.BoxGeometry(30,60,30);const vertexShader = ` varying vec3 vPosition;//表示顶点插值后位置数据,与片元数量雷同,逐一对应 void main(){ vPosition = position;// 顶点位置坐标插值计算 // 投影矩阵 * 视图矩阵 * 模子矩阵 * 模子顶点坐标 gl_Position = projectionMatrix*viewMatrix*modelMatrix*vec4( position, 1.0 ); }`;const fragmentShader = ` varying vec3 vPosition; uniform float time; const float bandWidth = 4.0;//光带宽度 const float bandSpacing = 4.0;//光带间隔 float halfBandWidth = bandWidth*0.5;//光带宽度的一半 //光带的颜色 const vec3 bandColor[7] = vec3[7]( vec3(1.0,0.0,0.0), vec3(1.0,0.5,0.0), vec3(1.0,1.0,0.0), vec3(0.0,1.0,0.0), vec3(0.0,1.0,1.0), vec3(0.0,0.0,1.0), vec3(1.0,0.0,1.0) ); const vec3 baseColor = vec3(1.0,1.0,1.0);//模子自己的颜色 void main(){ // 设置整体颜色,不然模子会设置为默认白色 gl_FragColor = vec4(baseColor,1.0); float startY = -40.0+time; //模子y坐标的起始值 float percent = 0.0; int colorIndex = 0; for(int i=0;i<10;i++){ startY += float(i)+bandSpacing; colorIndex = int(mod(float(i),float(bandColor.length()))); // 光带上半部门 if(vPosition.y > startY && vPosition.y < startY + halfBandWidth && vPosition.y <30.0 && vPosition.y >-30.0){ percent = (vPosition.y-startY)/halfBandWidth;//范围0~1 gl_FragColor.rgb = mix( bandColor[colorIndex], baseColor, percent); } // 光带下半部门 if(vPosition.y <= startY && vPosition.y > startY - halfBandWidth && vPosition.y <30.0 && vPosition.y >-30.0){ percent = (startY - vPosition.y)/halfBandWidth;//范围0~1 gl_FragColor.rgb = mix( bandColor[colorIndex], baseColor, percent); } } }`;// 以下代码是使用着色器材料进行颜色设置
- export const material = new THREE.ShaderMaterial({
- uniforms:{
- time:{value:0.0} //立方体位于原点,y的最小值是-30.0,而不是0.0
- },
- //顶点着色器对象vertexShader
- vertexShader: vertexShader,
- // 片元着色器对象fragmentShader
- fragmentShader: fragmentShader
- });export const model = new THREE.Mesh(geometry, material);
复制代码- // 渲染循环
- function render() {
- material.uniforms.time.value += 0.5;
- if(material.uniforms.time.value>10.0){
- material.uniforms.time.value = 0.0;
- }
- renderer.render(scene, camera);
- requestAnimationFrame(render);
- }
复制代码
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。 |