three.js + suncalc 在vue中模拟太阳运行轨迹以及光照效果
·
近期项目需要实现一个在three中出现 一个光照的效果,遂开始学习three.js,中间遇到了一些坑这边记录一下。
一开始想的比较简单,觉得只要熟悉three.js 的api后,就直接模拟了一个光照环形运转的效果出来。可惜等我做出来直接就被否定了,实际的太阳运行阶段要按当地经纬度来计算太阳位置。遂查询资料,发现有库suncalc可以计算太阳的角度。废话不多说直接贴代码吧:
<template>
<canvas id="canvas">
</canvas>
</template>
<script>
// 引入three
import * as THREE from 'three';
// 引入轨道控制器扩展库OrbitControls.js
// 网上的方案是这种 but
// import { OrbitControls } from 'three/addons/controls/OrbitControls.js';
// "suncalc": "^1.9.0",引入方式
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls.js';
let scene, camera, renderer
export default {
data() {
return {}
},
onLoad() {
},
onReady() {
// 默认经纬度
const latitude = 116.40400, longitude = 39.92800;
const currentTime = new Date();
// 凌晨时分
currentTime.setHours(0, 0, 0, 0);
let timeInterval = 120000; // 2分钟的时间间隔(毫秒)
// 太阳高度
const distance = 10;
let sunX = 200; // 初始x坐标
let sunY = 200; // 初始y坐标
// 更新太阳位置和高度
function updateSunPosition() {
const sunPosition = SunCalc.getPosition(currentTime, latitude, longitude);
const sunAltitude = sunPosition.altitude * (180 / Math.PI);
const sunAzimuth = sunPosition.azimuth * (180 / Math.PI);
const theta = (90 - sunAltitude) * (Math.PI / 180);
const phi = (-sunAzimuth + 180) * (Math.PI / 180); // 考虑太阳在地平线以下的情况
const x = 10 * Math.sin(theta) * Math.cos(phi);
const y = 10 * Math.cos(theta);
const z = 10 * Math.sin(theta) * Math.sin(phi);
// 时间推移
currentTime.setTime(currentTime.getTime() + timeInterval);
// 因为太阳是从底部出来,所以数据去反就好了;
directionalLight.position.set(-x, -y, -z);
}
// 创建场景
scene = new THREE.Scene();
// 创建相机
camera = new THREE.PerspectiveCamera(
45,// 视角
window.innerWidth / window.innerHeight, //宽高比
0.1, //近平面
1000 // 远平面
)
// 创建渲染器
renderer = new THREE.WebGLRenderer({ antialias: true })
renderer.setSize(window.innerWidth, window.innerHeight)
renderer.shadowMap.enabled = true;// 可以产生阴影
// 将渲染器绑定到dom节点上
const myCanvas = document.getElementById("canvas")
myCanvas.appendChild(renderer.domElement)
// 创建几何体
const geometry = new THREE.BoxGeometry(1, 1, 5);
// 创建材质
const material = new THREE.MeshStandardMaterial(); // 基础材质
// 父元素
const cube = new THREE.Mesh(geometry, material);
// 设置物体投射阴影
cube.castShadow = true;
// 设置立方体和平面接收阴影
cube.receiveShadow = true;
cube.position.set(0, 0, 0.5);
scene.add(cube)
// 创建平面
const planeGeometry = new THREE.PlaneGeometry(10, 10);
const plane = new THREE.Mesh(planeGeometry, material);
plane.position.set(0, -1, 0);
plane.receiveShadow = true;
// plane.setRotationFromMatrix(-Math.PI / 2);
scene.add(plane);
// 设置相机位置
camera.position.z = 10;
camera.position.y = -14;
camera.position.x = 0;
camera.lookAt(0, 0, 0)
// 添加世界坐标辅助器
// const axesHelper = new THREE.AxesHelper(5);
// scene.add(axesHelper);
// 灯光
// 环境光
const light = new THREE.AmbientLight(0xffffff, 0.5);
scene.add(light);
// 直线光源
const directionalLight = new THREE.DirectionalLight(0xffffff, 10);
directionalLight.position.set(sunX, sunY, distance);
// 开启光照投射阴影
directionalLight.castShadow = true;
scene.add(directionalLight);
// 添加轨道控制器
const controls = new OrbitControls(camera, renderer.domElement);
// 设置带阻尼惯性
controls.enableDamping = true;
// 设置带阻尼系数
controls.dampingFactor = 0.01;
// 设置自动旋转
// controls.autoRotate = true;
// 渲染函数
function animate() {
controls.update();
updateSunPosition();
// // 调用getSunXY函数来计算太阳的位置
// const [sunX, sunY, sunZ] = getSunXYZ();
// // console.log("sunY",sunY)
// directionalLight.position.set(sunX, sunY, sunZ);
// 旋转
// cube.rotation.x += 0.01;
// cube.rotation.y += 0.01;
// 渲染
renderer.render(scene, camera);
requestAnimationFrame(animate);
}
animate();
// 页面监听窗口大小变化
window.addEventListener('resize', () => {
// 重置渲染器宽高比
renderer.setSize(window.innerWidth, window.innerHeight);
// 重置相机宽高比
camera.aspect = window.innerWidth / window.innerHeight;
// 更新相机投影矩阵
camera.updateProjectionMatrix();
})
},
methods: {
}
}
</script>
<style></style>
思考,这里可以做一个优化就是把每个频率的xyz记录到一个Array中,等一天跑完了,这边就可以直接使用array中的值。不用再复杂的去计算了。
以上就是全部内容。
更多推荐
已为社区贡献2条内容
所有评论(0)