基于ThreeJS如何让太阳光影发生变化?

太阳光影变化

    • 示例描述与操作指南
    • 示例效果展示 [^1]:
    • 实现步骤

示例描述与操作指南

太阳光影变化示例,是利用 Threejs 开源接口模拟在不同地区、不同时间的太阳光照下阴影的形成。当前示例用于展示在不同经纬度、不同时间下、建筑受到不同光照强度而生成的不同阴影效果。用户将完整代码下载下来后,替换用户模型 id 和用户个人账户 devcode,即可展示自有模型。

示例效果展示 1:

基于ThreeJS如何让太阳光影发生变化?_第1张图片

实现步骤

第一步 模拟太阳光

//添加DirectionalLight,用来模拟太阳光
    const addDirectionalLight = () => {
      vizbim.renderer.shadowMap.enabled = true;   // 将渲染器阴影渲染的属性打开
      // 添加一个水平角度转轴
      const pivotPoint2 = window.pivotPoint2 = new THREE.Object3D();
      vizbim.root.add(pivotPoint2);
    
      // 添加一个时间转轴 竖直转轴
      const pivotPoint = window.pivotPoint = new THREE.Object3D();
      pivotPoint2.add(pivotPoint);
    
      const pointColor = "#ffffff"; // 将点光源的颜色设置成白色
      directionalLight = new THREE.DirectionalLight(pointColor); // 平行光
      directionalLight.castShadow = true; // 将平行光产生阴影的属性打开
    
      //设置地面不产生阴影
      vizbim.components["BuildingAI_lightingEffect_0MCQCRssH0svCvV4FN424A"].receiveShadow = true;
      vizbim.components["BuildingAI_lightingEffect_0MCQCRssH0svCvV4FN424A"].castShadow = false;
    
      // 设置平行光源的产生阴影的范围参数
      directionalLight.shadow.camera.near = 0;
      directionalLight.shadow.camera.far = 50000;
      directionalLight.shadow.camera.left = -20000;
      directionalLight.shadow.camera.right = 20000;
      directionalLight.shadow.camera.top = 20000;
      directionalLight.shadow.camera.bottom = -20000;
      directionalLight.distance = 1110;
      directionalLight.intensity = 0.1;
      directionalLight.shadow.mapSize.height = 2560;
      directionalLight.shadow.mapSize.width = 2560;
    
      let sphereLight = new THREE.SphereGeometry(5, 32, 32);  // 创建一个球形mesh,用来存放点光源
      let sphereLightMaterial = new THREE.MeshBasicMaterial({color: 0xac6c25});
      let sphereLightMesh = window.sphereLightMesh = new THREE.Mesh(sphereLight, sphereLightMaterial);
      sphereLightMesh.castShadow = false;   //将这个球形mesh的产生阴影和接收阴影参数打开
      sphereLightMesh.receiveShadow = false; //将这个球形mesh的产生阴影和接收阴影参数打开
      sphereLightMesh.position.set(-25000, 0, 0); //  设置此球形mesh的位置
    
      pivotPoint.add(sphereLightMesh);  // 将球形mesh添加到点光源里
      pivotPoint.add(directionalLight); // 将平行光源添加到点光源里
      directionalLight.position.copy(sphereLightMesh.position);
    
      // 创建屏幕炫光,模拟太阳
      addFlensflare();
    }

第二步 添加屏幕炫光

/**
     * @description:  添加一个屏幕炫光到场景,因为屏幕炫光不是实际的光源,只是一个效果,因此一般配合其他光源使用。
     *                一般用此屏幕炫光来模拟太阳光源,因此配合一个平行光源使用。
     *                一般使平行光产生阴影效果分为以下几步:
     *                1. 将渲染器的阴影设置打开,即 renderer.shadowMap.enabled = true;
     *                2. 将此光源的产生阴影的属性打开,即 spotLdirectionalLightight.castShadow = true;
     *                3. 调整此光源的光源阴影范围,一般要使产生阴影的物体的位置大于阴影相机的最小值,小于最大值;
     *                4. 将需要产生阴影的物体的产生阴影的属性打开,即obj.castShadow = true;
     *                5. 将要接收阴影的属性打开,即obj.receiveShadow = true;
    
     */
    const addFlensflare = () => {
    
      vizbim.renderer.gammaInput = true;
      vizbim.renderer.gammaOutput = true;
    
      // lensflares
      let textureLoader = new THREE.TextureLoader();
    
      let textureFlare0 = textureLoader.load('lensflare/lensflare0.png');
      let textureFlare3 = textureLoader.load('lensflare/lensflare3.png');
    
      addLight(0.55, 0.9, 0.5, -25000, 0, 0);
      addLight(0.995, 0.9, 0.5, -25000, 0, 0);
    
      function addLight(h, s, l, x, y, z) {
    
        let light = new THREE.PointLight(0xffffff, 1.5, 200, 10);
        light.color.setHSL(h, s, l);
        light.position.set(x, y, z);
        pivotPoint.add(light);
    
        let lensflare = new THREE.Lensflare();
        lensflare.addElement(new THREE.LensflareElement(textureFlare0, 300, 0, light.color, THREE.AdditiveBlending));
        lensflare.addElement(new THREE.LensflareElement(textureFlare3, 60, 0.1, light.color, THREE.AdditiveBlending));
        lensflare.addElement(new THREE.LensflareElement(textureFlare3, 70, 0.12, light.color, THREE.AdditiveBlending));
        lensflare.addElement(new THREE.LensflareElement(textureFlare3, 120, 0.3, light.color, THREE.AdditiveBlending));
        lensflare.addElement(new THREE.LensflareElement(textureFlare3, 60, 0.4, light.color, THREE.AdditiveBlending));
        lensflare.position.set(x, y, z);
        light.add(lensflare);
        pivotPoint.add(light);
    
      }
    }

计算太阳高度和方位角

/**
     * @description:  根据地点纬度,时间来算出太阳高度角和方位角
     * @params:
     * @params:
     * @return:
     * @example:
    
     */
    const updateShaowBySunDegree = (realSunhour) => {
      const sunHourangle = computeSunHourangle(realSunhour);  // 太阳时角
      const sunDeclination = computeSunDeclination(shadowDays);  // 太阳赤纬
      const solarAltitude = computeSolarAltitude(shadowPosition.lat, sunDeclination, sunHourangle, realSunhour);  // 太阳高度角,弧度制
      const solarAzimuth = computeSolarAzimuth(shadowPosition.lat, sunDeclination, solarAltitude, realSunhour); // 太阳方位角,弧度制
      vizbim.lights.children[0].intensity = solarAltitude * 6 / Math.PI;
      // 如果太阳高度角为负数则关闭阴影效果
      if (solarAltitude < 0) {
        directionalLight.castShadow = false;  // 平行光
        pivotPoint.children[2].children[0].material.visible = false;  // 屏幕炫光
        pivotPoint.children[3].children[0].material.visible = false;
        vizbim.lights.children[0].intensity = 0
      } else {
        directionalLight.castShadow = true;
        pivotPoint.children[2].children[0].material.visible = true;
        pivotPoint.children[3].children[0].material.visible = true;
      }
      pivotPoint.rotation.y = solarAltitude;  // 太阳高度角
      pivotPoint2.rotation.z = -solarAzimuth + Math.PI / 2;   // 太阳方位角 弧度
      vizbim.renderer.shadowMap.needsUpdate = true;
      vizbim.renderer.render(vizbim.scene, vizbim.camera);
    }

下载完整代码


  1. 模拟太阳光影在不同地理位置、日期、时间下的变化,展示建筑物接收太阳光线与产生阴影的真实效果。
    在省市选择框选择省市名称,点击更新地点(默认为北京市);在日期选择框选择日期(默认为当天时间);通过滑动时间轴来确定时间并模拟太阳光影的变化。 ↩︎

你可能感兴趣的:(#,核心示例)