ThreeJS中的灯光


参考:https://threejs.org/open in new window

//遍历场景中的所有对象,然后判断当前对象是否是光源对象
function toggleLights( visible ) {
	scene.traverse( function ( object ) {
		if ( object.isLight ) {
			object.visible = visible;
		}
	} );
	render();
}

    const shaderMaterial = new THREE.ShaderMaterial({
        // 定义顶点着色器,用于处理顶点属性
        vertexShader: `
            precision lowp float;
            // 传递顶点位置信息到片元着色器
            varying vec4 vPosition;
            // 传递变换后的顶点位置信息到片元着色器
            varying vec4 gPosition;
            void main(){
                // 将顶点坐标从模型空间变换到世界空间
                vec4 modelPosition = modelMatrix * vec4( position, 1.0 );
                // 将变换后的顶点坐标从世界空间变换到相机空间
                // 并传递给 varying vPosition
                vPosition = modelPosition;
                // 将顶点坐标从模型空间变换到世界空间
                // 并传递给 varying gPosition
                gPosition = vec4( position, 1.0 );
                // 将顶点坐标从模型空间变换到相机空间和投影空间
                gl_Position =  projectionMatrix * viewMatrix * modelPosition;
            }
        `,
        // 定义片元着色器,用于处理像素颜色
        fragmentShader:`
            precision lowp float;
            // 接收来自顶点着色器的变量
            varying vec4 vPosition;
            varying vec4 gPosition;

            void main(){
                // 定义红色和黄色的颜色值
                vec4 redColor = vec4(1,0,0,1);
                vec4 yellowColor = vec4(1,1,0.5,1);
                // 计算需要混合的颜色值,并传递给 gl_FragColor
                vec4 mixColor = mix(yellowColor,redColor,gPosition.y/3.0);

                if(gl_FrontFacing){
                    // 对于正面的面,计算并设置像素颜色
                    gl_FragColor = vec4(mixColor.xyz-(vPosition.y-20.0)/80.0-0.1,1);
                }else{
                    // 对于背面的面,直接设置像素颜色
                    gl_FragColor = vec4(mixColor.xyz,1);
                }
            }  
        `,
        // 传递给着色器的变量,这里为空对象
        uniforms:{},
        // 设置物体的两面都需要渲染
        side:THREE.DoubleSide
    })

    const gltfLoader = new GLTFLoader()
    let LightBox = null 

    gltfLoader.load("/assets/model/flyLight.glb",(gltf) => {
        LightBox = gltf.scene.children[1]

        LightBox.material = shaderMaterial;
        
        for (let i = 0; i < 150; i++) {
          let flyLight = gltf.scene.clone(true);
          let x = (Math.random() - 0.5) * 300;
          let z = (Math.random() - 0.5) * 300;
          let y = Math.random() * 60 + 25;
          flyLight.position.set(x, y, z);
          gsap.to(flyLight.rotation, {
            y: 2 * Math.PI,
            duration: 10 + Math.random() * 30,
            repeat: -1,
          });
          gsap.to(flyLight.position, {
            x: "+=" + Math.random() * 5,
            y: "+=" + Math.random() * 20,
            yoyo: true,
            duration: 5 + Math.random() * 10,
            repeat: -1,
          });
          scene.add(flyLight);
        }

    })

function createLight(color) {

  // 定义光源强度为2
  const intensity = 2;

  // 创建一个点光源
  const light = new THREE.PointLight(color, intensity, 20);

  // 开启阴影
  light.castShadow = true;

  // 减少双面对象自身阴影
  light.shadow.bias = -0.005;

  // 创建一个球体作为光源的可视化表示
  let geometry = new THREE.SphereGeometry(0.3, 12, 6);
  let material = new THREE.MeshBasicMaterial({
    color: color
  });

  // 根据光源强度调整颜色
  material.color.multiplyScalar(intensity);

  let sphere = new THREE.Mesh(geometry, material);

  // 将球体添加到光源上
  light.add(sphere);

  // 生成纹理
  const texture = new THREE.CanvasTexture(generateTexture());

  // 设置纹理过滤器和重复方式
  texture.magFilter = THREE.NearestFilter;
  texture.wrapT = THREE.RepeatWrapping;
  texture.wrapS = THREE.RepeatWrapping;
  texture.repeat.set(1, 4.5);

  // 创建一个球体作为光源的光晕效果
  geometry = new THREE.SphereGeometry(2, 32, 8);
  material = new THREE.MeshPhongMaterial({
    side: THREE.DoubleSide, // 双面显示
    alphaMap: texture, // 设置透明度贴图
    alphaTest: 0.5 // 设置透明度阈值
  });

  sphere = new THREE.Mesh(geometry, material);

  // 开启球体阴影和接收阴影
  sphere.castShadow = true;
  sphere.receiveShadow = true;

  // 将球体添加到光源上
  light.add(sphere);

  // 返回创建的光源
  return light;

}
/**
 * 生成一个 2x2 的纯白色 canvas 纹理
 */
function generateTexture() {
  // 创建一个 canvas 元素,并设置它的宽高为 2
  const canvas = document.createElement( 'canvas' );
  canvas.width = 2;
  canvas.height = 2;

  // 获取 canvas 的绘制上下文,并将其填充为白色
  const context = canvas.getContext( '2d' );
  context.fillStyle = 'white';
  context.fillRect( 0, 1, 2, 1 );

  // 返回生成的纹理
  return canvas;
}
评论
  • 按正序
  • 按倒序
  • 按热度
Powered by Waline v2.13.0