太阳光影变化示例,是利用 Threejs 开源接口模拟在不同地区、不同时间的太阳光照下阴影的形成。当前示例用于展示在不同经纬度、不同时间下、建筑受到不同光照强度而生成的不同阴影效果。用户将完整代码下载下来后,替换用户模型 id 和用户个人账户 devcode,即可展示自有模型。
第一步 模拟太阳光
//添加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);
}
下载完整代码
模拟太阳光影在不同地理位置、日期、时间下的变化,展示建筑物接收太阳光线与产生阴影的真实效果。
在省市选择框选择省市名称,点击更新地点(默认为北京市);在日期选择框选择日期(默认为当天时间);通过滑动时间轴来确定时间并模拟太阳光影的变化。 ↩︎