Threejs渐变光柱效果

请添加图片描述

一、实现原理

通过shader,将物体的透明度由下往上,从1到0渐变即可(只需要两圈顶点,底下一圈alpha设为1,上面一圈alpha设为0)

二、实现步骤

1、创建geometry

这个几何体类似于圆柱,只是没有上下两个底面

			/*let bottomPos = [];
			let topPos = [];
			let angleOffset = Math.PI*2/segment;
			for(var i=0;i<segment;i++){
                let x = Math.cos(angleOffset * i)*radius;
                let z = Math.sin(angleOffset * i)*radius;
                bottomPos.push(new Vector3(x,0,z));
                topPos.push(new Vector3(x,height,z));
            }
            bottomPos = bottomPos.concat(topPos);
    
            let face = []
            for(var i=0;i<segment;i++){
                if(i != segment - 1){
                    face.push(new Face3(i+segment+1,i,i+segment));
                    face.push(new Face3(i,i+segment+1,i+1));
                }
                else{
                    face.push(new Face3(segment,i,i+segment));
                    face.push(new Face3(i,segment,0));
                }
            }
    
            let geo = new Geometry();
            geo.vertices = bottomPos;
            geo.faces = face;*/
    //更新为BufferGeometry
    let bottomPos = []
    let topPos = []
    let angleOffset = (Math.PI * 2) / segment
    for (var i = 0; i < segment; i++) {
      let x = Math.cos(angleOffset * i) * radius
      let z = Math.sin(angleOffset * i) * radius
      bottomPos.push(x, 0, z)
      topPos.push(x, height, z)
    }
    bottomPos = bottomPos.concat(topPos)

    let face = []
    for (var i = 0; i < segment; i++) {
      if (i != segment - 1) {
        face.push(i + segment + 1, i, i + segment)
        face.push(i, i + segment + 1, i + 1)
      } else {
        face.push(segment, i, i + segment)
        face.push(i, segment, 0)
      }
    }

    let geo = new BufferGeometry()
    geo.setAttribute('position', new BufferAttribute(new Float32Array(bottomPos), 3))
    geo.setIndex(new BufferAttribute(new Uint16Array(face), 1))
   

请添加图片描述

2、创建shader材质

            let c = new Color(color);
            let mat = new ShaderMaterial({
                uniforms: {
                    targetColor:{value:new Vector3(c.r,c.g,c.b)},
                    height: { value: height},
                },
                side: DoubleSide,
                transparent:true,
                //depthTest:false,
                depthWrite:false,
                vertexShader: [
                    "varying vec3 modelPos;",
                    "void main() {",
                    "   modelPos = position;",
                    "	gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );",
                    "}"
                ].join("\n"),
                fragmentShader: [
                    "uniform vec3 targetColor;",
                    "uniform float height;",
                    "varying vec3 modelPos;",
    
                    "void main() {",
                    "   gl_FragColor = vec4(targetColor.xyz,(1.0 - modelPos.y/height)*(1.0 - modelPos.y/height));",
                    "}"
                ].join("\n")
            });

需要注意的是使用双面渲染、打开透明、关闭深度写入以及alpha的获取(这里使用二次方程,比线性函数过度更自然)

三、完整代码

/**
     * 生成并返回柱状渐变光环
     * @param {*} radius 半径
     * @param {*} height 高度
     * @param {*} color 颜色
     * @returns 
     */
    getAureole(radius,height,color){
        let geo,mat;
        let segment = 64;
        //geo
        {
            /*let bottomPos = [];
            let topPos = [];
            let angleOffset = Math.PI*2/segment;
            for(var i=0;i<segment;i++){
                let x = Math.cos(angleOffset * i)*radius;
                let z = Math.sin(angleOffset * i)*radius;
                bottomPos.push(new Vector3(x,0,z));
                topPos.push(new Vector3(x,height,z));
            }
            bottomPos = bottomPos.concat(topPos);
    
            let face = []
            for(var i=0;i<segment;i++){
                if(i != segment - 1){
                    face.push(new Face3(i+segment+1,i,i+segment));
                    face.push(new Face3(i,i+segment+1,i+1));
                }
                else{
                    face.push(new Face3(segment,i,i+segment));
                    face.push(new Face3(i,segment,0));
                }
            }
    
            geo = new Geometry();
            geo.vertices = bottomPos;
            geo.faces = face;*/
            //更新为BufferGeometry
            let bottomPos = []
    		let topPos = []
    		let angleOffset = (Math.PI * 2) / segment
    		for (var i = 0; i < segment; i++) {
      			let x = Math.cos(angleOffset * i) * radius
      			let z = Math.sin(angleOffset * i) * radius
      			bottomPos.push(x, 0, z)
      			topPos.push(x, height, z)
    		}
    		bottomPos = bottomPos.concat(topPos)

    		let face = []
    		for (var i = 0; i < segment; i++) {
      			if (i != segment - 1) {
        			face.push(i + segment + 1, i, i + segment)
        			face.push(i, i + segment + 1, i + 1)
      			} else {
        			face.push(segment, i, i + segment)
        			face.push(i, segment, 0)
      			}
    		}

    		let geo = new BufferGeometry()
    		geo.setAttribute('position', new BufferAttribute(new Float32Array(bottomPos), 3))
    		geo.setIndex(new BufferAttribute(new Uint16Array(face), 1))
        }
        //mat
        {
            let c = new Color(color);
            mat = new ShaderMaterial({
                uniforms: {
                    targetColor:{value:new Vector3(c.r,c.g,c.b)},
                    height: { value: height},
                },
                side: DoubleSide,
                transparent:true,
                //depthTest:false,
                depthWrite:false,
                vertexShader: [
                    "varying vec3 modelPos;",
                    "void main() {",
                    "   modelPos = position;",
                    "	gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );",
                    "}"
                ].join("\n"),
                fragmentShader: [
                    "uniform vec3 targetColor;",
                    "uniform float height;",
                    "varying vec3 modelPos;",
    
                    "void main() {",
                    "   gl_FragColor = vec4(targetColor.xyz,(1.0 - modelPos.y/height)*(1.0 - modelPos.y/height));",
                    "}"
                ].join("\n")
            });
        }

        let mesh = new Mesh(geo,mat);
        mesh.renderOrder = 9999
        return mesh;
    }
  • 9
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值