You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

827 lines
31 KiB
JavaScript

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

// 全局变量
let scene, camera, renderer, controls;
let water, sun, sky;
let windTurbineModels = []; // 改为数组存储多个风电机组
let clock = new THREE.Clock();
// 在全局变量部分添加
let pointerLockControls;
let moveForward = false;
let moveBackward = false;
let moveLeft = false;
let moveRight = false;
let moveUp = false;
let moveDown = false;
let velocity = new THREE.Vector3();
let direction = new THREE.Vector3();
let prevTime = performance.now();
// 初始化Three.js场景
function init() {
console.log('开始初始化Three.js场景');
// 创建场景
scene = new THREE.Scene();
//scene.fog = new THREE.Fog(0x006994, 1, 1000);
console.log('场景创建完成');
//天空盒
scene.background = new THREE.CubeTextureLoader()
.setPath('./assets/sky/')
.load(['px.jpg', 'nx.jpg', 'py.jpg', 'ny.jpg', 'pz.jpg', 'nz.jpg']);
//环境光
const ambientLight = new THREE.AmbientLight(0x666666, 20); // 柔和的白光
scene.add(ambientLight);
// 创建相机
// 增大远裁剪面距离,确保远处的缩小模型也能显示
camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 5000);
// 向右旋转270度的相机位置设置根据你的代码
const cameraRotationAngle = THREE.MathUtils.degToRad(0);
const cameraRadius = 800; // 相机距离原点的距离
const cameraHeight = 50; // 降低相机高度,使其更接近水面
// 计算旋转后的位置(修复变量名错误)
const cameraX = cameraRadius * Math.sin(cameraRotationAngle);
const cameraZ = cameraRadius * Math.cos(cameraRotationAngle); // 修复使用cameraRotationAngle而不是cameraAngle
camera.position.set(cameraX, cameraHeight, cameraZ);
camera.lookAt(0, 0, 0); // 确保相机朝向场景中心
console.log('相机创建完成,位置:', camera.position.x, camera.position.y, camera.position.z);
//创建渲染器
renderer = new THREE.WebGLRenderer({
logarithmicDepthBuffer: true,//设置对数深度缓冲区,优化深度冲突问题
preserveDrawingBuffer: true,//把canvas画布上内容下载到本地,保存图片
antialias: true, // 正确开启抗锯齿
stencil: true,//开启模版缓存区,用于高级渲染技术,如阴影体积、遮挡剔除等
powerPreference: 'high-performance',//指定渲染器使用的 GPU 功率模式。默认 "default"
physicalCorrectLights: true,//是否使用物理上正确的照明模式;默认为 false
localClippingEnabled: true,//启用局部裁剪;默认为 false
alpha: true,//背景透明
});
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.shadowMap.enabled = true;
renderer.shadowMap.type = THREE.PCFSoftShadowMap;
renderer.setClearColor(0x87CEEB, 1);
// 确保canvas添加到正确的容器
const container = document.getElementById('container');
if (container) {
container.appendChild(renderer.domElement);
console.log('渲染器canvas已添加到container');
} else {
document.body.appendChild(renderer.domElement);
console.log('渲染器canvas已添加到body');
}
// 设置canvas样式确保可见
renderer.domElement.style.display = 'block';
renderer.domElement.style.position = 'absolute';
renderer.domElement.style.top = '0';
renderer.domElement.style.left = '0';
renderer.domElement.style.zIndex = '1';
console.log('渲染器创建完成canvas尺寸:', renderer.domElement.width, 'x', renderer.domElement.height);
// 初始化指针锁定控制器
if (typeof THREE.PointerLockControls !== 'undefined') {
pointerLockControls = new THREE.PointerLockControls(camera, document.body);
// 添加点击进入指针锁定的事件
document.addEventListener('click', function() {
if (pointerLockControls) {
pointerLockControls.lock();
}
});
// 添加键盘控制事件
document.addEventListener('keydown', onKeyDown, false);
document.addEventListener('keyup', onKeyUp, false);
console.log('指针锁定控制器创建完成');
} else {
console.warn('PointerLockControls未加载使用OrbitControls');
// 保留原有的OrbitControls作为备选
initOrbitControls();
}
// 添加相机控制 (OrbitControls 作为备选)
function initOrbitControls() {
if (typeof THREE.OrbitControls !== 'undefined') {
controls = new THREE.OrbitControls(camera, renderer.domElement);
controls.enableDamping = true;
controls.dampingFactor = 0.05;
controls.screenSpacePanning = false;
controls.minDistance = 10; // 减小最小距离
controls.maxDistance = 3000; // 最大距离
controls.maxPolarAngle = Math.PI / 2 - 0.1; // 限制垂直旋转角度,防止看到水面以下
controls.target.set(0, 0, 0);
controls.addEventListener('change', function () {
// 限制相机高度,防止进入水面以下
if (camera.position.y < 5) {
camera.position.y = 5;
}
});
console.log('相机控制器创建完成');
} else {
console.warn('OrbitControls未加载跳过相机控制器');
}
}
// const ambientLight = new THREE.AmbientLight(0x404040); // 环境光
// ambientLight.intensity = 0.5; // 光照强度
// scene.add(ambientLight);
addLights();
// loadHDRTexture()
// // 创建场景元素
// createSkybox(); // 创建天空盒
createOcean(); // 创建海洋
// 加载海上风电机组模型
loadWindTurbineField();
// 监听窗口大小变化
window.addEventListener('resize', onWindowResize, false);
console.log('Three.js场景初始化完成');
}
// 加载HDR环境纹理
function loadHDRTexture() {
// 检查RGBELoader是否可用
if (typeof THREE.RGBELoader === 'undefined') {
console.warn('RGBELoader未加载跳过HDR纹理加载');
return;
}
const hdrLoader = new THREE.RGBELoader();
hdrLoader.load("./textures/023.hdr", (texture) => {
// 设置背景和环境纹理
texture.mapping = THREE.EquirectangularReflectionMapping;
scene.background = texture;
scene.environment = texture;
console.log('HDR纹理加载完成');
}, undefined, (error) => {
console.error('HDR纹理加载失败:', error);
});
}
// 修改后的 createSkybox 函数:// 创建天空盒
function createSkybox() {
const skyGeometry = new THREE.SphereGeometry(1800, 24, 18); // 增大天空盒半径
const textureLoader = new THREE.TextureLoader().load('./textures/sky.jpg');
textureLoader.colorSpace = THREE.SRGBColorSpace;
// 创建天空材质(通常使用全景纹理)
const skyMaterial = new THREE.MeshBasicMaterial({
map: textureLoader,
side: THREE.BackSide // 重要:让材质渲染在球体内侧
});
// 创建天空网格
const skySphere = new THREE.Mesh(skyGeometry, skyMaterial);
scene.add(skySphere);
}
// 创建天空效果
function createSky() {
// 注释掉Sky.js的高级天空效果
sky = new THREE.Sky();
sky.scale.setScalar(450000);
scene.add(sky);
// 创建太阳
sun = new THREE.Vector3();
// 配置天空参数(正午阳光设置)
const skyUniforms = sky.material.uniforms;
skyUniforms['turbidity'].value = 2; // 降低湍流度,营造清澈的正午天空
skyUniforms['rayleigh'].value = 3; // 增强瑞利散射,让天空更蓝
skyUniforms['mieCoefficient'].value = 0.005;
skyUniforms['mieDirectionalG'].value = 0.8;
// 设置太阳位置(正午阳光效果)
const phi = THREE.MathUtils.degToRad(90 - 85); // 仰角 - 太阳接近天顶
const theta = THREE.MathUtils.degToRad(0); // 方位角 - 正南方向
sun.setFromSphericalCoords(1, phi, theta);
skyUniforms['sunPosition'].value.copy(sun);
// 使用sky.jpg作为天空盒纹理
const textureLoader = new THREE.TextureLoader();
textureLoader.load('./textures/sky.jpg', function (texture) {
// 创建天空盒几何体
const skyBoxGeometry = new THREE.SphereGeometry(2000, 32, 32);
const skyBoxMaterial = new THREE.MeshBasicMaterial({
map: texture,
side: THREE.BackSide
});
const skyBox = new THREE.Mesh(skyBoxGeometry, skyBoxMaterial);
scene.add(skyBox);
console.log('Sky texture loaded as skybox');
}, undefined, function (error) {
console.error('Sky texture loading failed:', error);
// 创建备用天空颜色
const skyGeometry = new THREE.SphereGeometry(500, 32, 32);
const skyMaterial = new THREE.MeshBasicMaterial({
color: 0x87CEEB,
side: THREE.BackSide
});
const sky = new THREE.Mesh(skyGeometry, skyMaterial);
scene.add(sky);
console.log('Fallback sky color created');
});
console.log('Sky created using sky.jpg texture');
}
// 创建海洋效果
function createOcean() {
// 加载水面法线纹理
const textureLoader = new THREE.TextureLoader();
const waterNormals = textureLoader.load('./textures/waternormals.jpg', function (texture) {
// 设置法线纹理的重复模式,增强水面效果
texture.wrapS = texture.wrapT = THREE.RepeatWrapping;
texture.repeat.set(2, 2); // 调整重复次数以控制波浪密度
console.log('水面法线纹理加载成功');
}, undefined, function (error) {
console.error('水面法线纹理加载失败:', error);
});
// 设置法线纹理的包装模式(即使纹理加载失败也要设置默认值)
waterNormals.wrapS = waterNormals.wrapT = THREE.RepeatWrapping;
waterNormals.repeat.set(2, 2); // 增加重复次数以获得更细腻的波浪效果
// 创建水面几何体,增大尺寸以匹配天空盒尺寸
const waterGeometry = new THREE.PlaneGeometry(10600, 10600); // 比天空盒稍大以确保完全覆盖
// 使用Water.js创建高级水面效果
// 其他碧绿色选项:
// waterColor: 0x0077be, // 经典碧绿色
// waterColor: 0x00a86b, // 绿松石色
// waterColor: 0x2a52be, // 地中海蓝
// waterColor: 0x008080, // 水鸭色
// waterColor: 0x40e0d0, // 青绿色
water = new THREE.Water(waterGeometry, {
textureWidth: 512,
textureHeight: 512,
waterNormals: waterNormals,
sunDirection: new THREE.Vector3(0.70707, 0.70707, 0.0),
sunColor: 0xffffff,
waterColor: 0x0077be,//0x001e0f 0x40e0d0
distortionScale: 3.7, // 控制波浪的扭曲程度
fog: scene.fog !== undefined,
alpha: 1.0, // 水面透明度
foam: 0.1 // 泡沫效果
});
water.rotation.x = -Math.PI / 2;
water.position.y = 0; // 确保水面在y=0位置
scene.add(water);
// 将water赋值给全局ocean变量以保持兼容性
ocean = water;
console.log('高级水面效果创建完成,使用法线纹理增强波浪凹凸效果');
}
// 修改 addLights 函数,增强光照效果// 修改 addLights 函数,进一步增强光照效果
function addLights() {
// 大幅增强环境光强度
const ambientLight = new THREE.AmbientLight(0xffffff, 1.2); // 使用白色光,强度更高
scene.add(ambientLight);
// 主方向光(太阳光)- 进一步调整位置和强度
const directionalLight = new THREE.DirectionalLight(0xffffff, 1.5); // 增加强度到1.5
directionalLight.position.set(100, 150, 100); // 调整到更合理的位置
directionalLight.castShadow = true;
directionalLight.shadow.mapSize.width = 2048;
directionalLight.shadow.mapSize.height = 2048;
directionalLight.shadow.camera.near = 0.5;
directionalLight.shadow.camera.far = 2000; // 增加远裁剪面
directionalLight.shadow.camera.left = -800;
directionalLight.shadow.camera.right = 800;
directionalLight.shadow.camera.top = 800;
directionalLight.shadow.camera.bottom = -800;
scene.add(directionalLight);
// 添加更强的补光 - 减少阴影
const fillLight = new THREE.DirectionalLight(0xffffff, 0.8); // 增加补光强度到0.8
fillLight.position.set(-100, 100, -100);
scene.add(fillLight);
// 添加天光 - 模拟天空反射
const hemiLight = new THREE.HemisphereLight(0x80deea, 0x4caf50, 0.5); // 增加强度到0.5
hemiLight.position.set(0, 200, 0);
scene.add(hemiLight);
// 添加背面光,确保模型背面也有光照
const backLight = new THREE.DirectionalLight(0xffffff, 0.6);
backLight.position.set(0, 50, -200);
scene.add(backLight);
}
// 加载海上风电场20个风电机组
function loadWindTurbineField() {
console.log('开始加载海上风电场');
const loader = new THREE.GLTFLoader();
// 定义风电场布局 - 4行5列的排列增加两排
const positions = [
// 第一排
// { x: -400, z: -600 },
// { x: -200, z: -600 },
// { x: 0, z: -600 },
// { x: 200, z: -600 },
// { x: 400, z: -600 },
// // 第二排
// { x: -400, z: -400 },
// { x: -200, z: -400 },
// { x: 0, z: -400 },
// { x: 200, z: -400 },
// { x: 400, z: -400 },
// 第三排
{ x: -400, z: -200 },
{ x: -200, z: -200 },
{ x: 0, z: -200 },
{ x: 200, z: -200 },
{ x: 400, z: -200 },
// 第四排
{ x: -400, z: 200 },
{ x: -200, z: 200 },
{ x: 0, z: 200 },
{ x: 200, z: 200 },
{ x: 400, z: 200 }
];
// 旋转角度右转50度
const rotationAngle = THREE.MathUtils.degToRad(50); // 转换为弧度
const cosAngle = Math.cos(rotationAngle);
const sinAngle = Math.sin(rotationAngle);
let loadedCount = 0;
const totalCount = positions.length;
positions.forEach((position, index) => {
// 应用旋转变换到每个风电机组的位置
const rotatedX = position.x * cosAngle - position.z * sinAngle;
const rotatedZ = position.x * sinAngle + position.z * cosAngle;
loader.load(
'./models/风电组.glb',
function (gltf) {
console.log(`风电组.glb模型 ${index + 1} 加载成功`);
const model = gltf.scene.clone(); // 克隆模型以创建多个实例
// 调整模型缩放和位置(使用旋转后的位置)
model.scale.set(0.8, 0.8, 0.8);
// 将风机位置设置在水面上y=0
model.position.set(rotatedX, 0, rotatedZ);
// 设置模型的旋转角度(使风机面向正确的方向)
model.rotation.y = -rotationAngle; // 负号是因为我们希望风机正面朝向旋转方向
// 调整模型材质
// 调整模型材质,使其更亮
model.traverse(function (child) {
if (child.isMesh) {
child.castShadow = true;
child.receiveShadow = true;
child.frustumCulled = false;
// 如果材质存在,调整其属性
if (child.material) {
// 添加更强的自发光效果
child.material.emissive = new THREE.Color(0x444444); // 增加自发光强度
// 调整材质颜色,使其更亮
if (child.material.color) {
// 可以稍微提亮原始颜色
child.material.color.multiplyScalar(1.2);
}
// 确保材质响应光照
if (child.material.type === 'MeshBasicMaterial') {
// 如果是基础材质,替换为标准材质
child.material = new THREE.MeshStandardMaterial({
color: child.material.color || 0xffffff,
map: child.material.map,
metalness: 0.1,
roughness: 0.6,
emissive: new THREE.Color(0x333333), // 添加自发光
emissiveIntensity: 0.3
});
} else if (child.material.type === 'MeshStandardMaterial') {
// 调整标准材质参数使其更亮
child.material.metalness = Math.max(0.05, child.material.metalness || 0.1);
child.material.roughness = Math.min(0.8, child.material.roughness || 0.6);
child.material.emissive = new THREE.Color(0x333333);
child.material.emissiveIntensity = 0.3; // 添加自发光强度
} else if (child.material.type === 'MeshLambertMaterial') {
// 对于Lambert材质也添加自发光
child.material.emissive = new THREE.Color(0x333333);
}
}
}
});
// 添加到场景和数组
scene.add(model);
windTurbineModels.push(model);
loadedCount++;
console.log(`风电场进度: ${loadedCount}/${totalCount} 个风电机组已加载`);
if (loadedCount === totalCount) {
console.log('海上风电场加载完成!');
}
},
function (progress) {
if (progress.total > 0) {
const percent = (progress.loaded / progress.total * 100).toFixed(1);
console.log(`风电机组 ${index + 1} 加载进度: ${percent}%`);
}
},
function (error) {
console.error(`风电机组 ${index + 1} 加载失败:`, error);
// 如果单个模型加载失败,创建备用模型(同样应用旋转变换)
createFallbackWindTurbine(rotatedX, rotatedZ, index);
loadedCount++;
}
);
});
}
// 修改备用风机创建函数,也应用旋转变换
function createFallbackWindTurbine(x = 0, z = 0, index = 0) {
console.log(`创建备用风电机组模型 ${index + 1}`);
// 创建风电机组主体(塔筒)
const towerGeometry = new THREE.CylinderGeometry(1.6, 2.4, 24, 8); // 缩小尺寸
const towerMaterial = new THREE.MeshLambertMaterial({ color: 0xcccccc });
const tower = new THREE.Mesh(towerGeometry, towerMaterial);
tower.position.set(0, 12, 0);
tower.castShadow = true;
tower.receiveShadow = true;
tower.frustumCulled = false; // 禁用视锥体剔除
// 创建机舱
const nacelleGeometry = new THREE.BoxGeometry(6.4, 3.2, 3.2); // 缩小尺寸
const nacelleMaterial = new THREE.MeshLambertMaterial({ color: 0xffffff });
const nacelle = new THREE.Mesh(nacelleGeometry, nacelleMaterial);
nacelle.position.set(0, 24, 0);
nacelle.castShadow = true;
nacelle.frustumCulled = false; // 禁用视锥体剔除
// 创建叶片轮毂组(用于旋转)
const rotorGroup = new THREE.Group();
// 创建叶片轮毂
const hubGeometry = new THREE.SphereGeometry(1.2, 8, 8); // 缩小尺寸
const hubMaterial = new THREE.MeshLambertMaterial({ color: 0x666666 });
const hub = new THREE.Mesh(hubGeometry, hubMaterial);
hub.position.set(0, 0, 0); // 相对于rotorGroup的位置
hub.castShadow = true;
hub.frustumCulled = false; // 禁用视锥体剔除
// 创建叶片
const bladeGeometry = new THREE.BoxGeometry(0.4, 12, 0.8); // 缩小尺寸
const bladeMaterial = new THREE.MeshLambertMaterial({ color: 0xffffff });
const blade1 = new THREE.Mesh(bladeGeometry, bladeMaterial);
blade1.position.set(0, 6, 0); // 相对于rotorGroup的位置
blade1.castShadow = true;
blade1.frustumCulled = false; // 禁用视锥体剔除
const blade2 = new THREE.Mesh(bladeGeometry, bladeMaterial);
blade2.position.set(0, 0, 6);
blade2.rotation.z = Math.PI * 2 / 3;
blade2.castShadow = true;
blade2.frustumCulled = false; // 禁用视锥体剔除
const blade3 = new THREE.Mesh(bladeGeometry, bladeMaterial);
blade3.position.set(0, 0, -6);
blade3.rotation.z = Math.PI * 4 / 3;
blade3.castShadow = true;
blade3.frustumCulled = false; // 禁用视锥体剔除
// 将轮毂和叶片添加到旋转组
rotorGroup.add(hub);
rotorGroup.add(blade1);
rotorGroup.add(blade2);
rotorGroup.add(blade3);
// 设置旋转组的位置
rotorGroup.position.set(3.2, 24, 0);
// 给旋转组添加一个标识,方便动画识别
rotorGroup.name = 'rotor_group';
// 组合风电机组
const windTurbine = new THREE.Group();
windTurbine.add(tower);
windTurbine.add(nacelle);
windTurbine.add(rotorGroup);
// 将风机放置在水面上y=0
windTurbine.position.set(x, 0, z);
windTurbine.scale.set(0.8, 0.8, 0.8); // 整体缩放
// 应用旋转(与主风电场一致)
const rotationAngle = THREE.MathUtils.degToRad(50);
windTurbine.rotation.y = -rotationAngle;
// 禁用整个组的视锥体剔除
windTurbine.traverse(function (child) {
child.frustumCulled = false;
});
scene.add(windTurbine);
windTurbineModels.push(windTurbine);
console.log(`备用风电机组模型 ${index + 1} 创建完成`);
}
// 动画循环
function animate() {
requestAnimationFrame(animate);
const time = clock.getElapsedTime();
// 漫游控制逻辑
const delta = Math.min(0.1, (time - prevTime));
// 如果使用指针锁定控制器且已锁定
if (pointerLockControls && pointerLockControls.isLocked) {
// 计算移动方向
direction.z = Number(moveForward) - Number(moveBackward);
direction.x = Number(moveRight) - Number(moveLeft);
direction.y = Number(moveUp) - Number(moveDown);
direction.normalize();
// 设置移动速度
const speed = 100.0;
// 根据方向和速度更新速度向量
if (moveForward || moveBackward) velocity.z -= direction.z * speed * delta;
if (moveLeft || moveRight) velocity.x -= direction.x * speed * delta;
if (moveUp || moveDown) velocity.y -= direction.y * speed * delta;
// 应用阻尼(摩擦力)
velocity.x -= velocity.x * 10.0 * delta;
velocity.y -= velocity.y * 10.0 * delta;
velocity.z -= velocity.z * 10.0 * delta;
// 移动相机
pointerLockControls.moveRight(-velocity.x * delta);
pointerLockControls.moveForward(-velocity.z * delta);
// 垂直移动
camera.position.y -= velocity.y * delta;
// 简单的高度限制
if (camera.position.y < 5) {
camera.position.y = 5;
velocity.y = 0;
}
if (camera.position.y > 500) {
camera.position.y = 500;
velocity.y = 0;
}
}
// 如果使用OrbitControls
else if (controls) {
controls.update();
}
prevTime = time;
// 在前几秒强制更新材质(解决材质加载延迟问题)
if (time < 3 && windTurbineModels.length > 0) {
windTurbineModels.forEach(model => {
model.traverse(function (child) {
if (child.isMesh && child.material) {
if (child.material.needsUpdate !== undefined) {
child.material.needsUpdate = true;
}
// 持续调整材质亮度
if (child.material.emissive) {
child.material.emissiveIntensity = 0.3;
}
}
});
});
}
// 更新水面动画 - 增强水面波动效果
if (water && water.material.uniforms) {
// 通过改变time值来控制水面波动动画
water.material.uniforms['time'].value += 1.0 / 60.0;
// 可选:增加波动速度和强度
// water.material.uniforms['time'].value += 1.0 / 30.0;
}
// 风电机组动画
if (windTurbineModels.length > 0) {
windTurbineModels.forEach((model, index) => {
// 每个风电机组有轻微的相位差,创造更自然的效果
const phaseOffset = index * 0.2;
// model.position.y = -3 + Math.sin(time * 0.5 + phaseOffset) * 1.5;
// 叶片旋转动画
// 如果还没有缓存旋转中心和初始偏移,先进行初始化
if (!model.userData.rotorInitialized) {
let rotorCenter = null;
// 找到186部件作为旋转中心
model.traverse((child) => {
if (child.name && child.name.toLowerCase().includes('186')) {
rotorCenter = child;
}
});
// 缓存旋转中心和叶片的初始偏移
if (rotorCenter) {
model.userData.rotorCenter = rotorCenter;
model.userData.rotorCenterPosition = {
x: rotorCenter.position.x,
y: rotorCenter.position.y,
z: rotorCenter.position.z
};
// 为每个叶片计算并缓存初始偏移
model.traverse((child) => {
if (child.name && (child.name.toLowerCase().includes('200') ||
child.name.toLowerCase().includes('214') ||
child.name.toLowerCase().includes('228') ||
child.name.toLowerCase().includes('风轮'))) {
child.userData.initialOffset = {
x: child.position.x - rotorCenter.position.x,
y: child.position.y - rotorCenter.position.y,
z: child.position.z - rotorCenter.position.z
};
}
});
}
model.userData.rotorInitialized = true;
}
// 执行旋转动画
model.traverse((child) => {
// 如果是备用模型的旋转组
if (child.name === 'rotor_group') {
child.rotation.x = time * 2.0; // 绕X轴旋转
}
// 如果是GLB模型的叶片部件
else if (child.name && (child.name.toLowerCase().includes('200') ||
child.name.toLowerCase().includes('214') ||
child.name.toLowerCase().includes('228') ||
child.name.toLowerCase().includes('风轮'))) {
if (model.userData.rotorCenter && child.userData.initialOffset) {
// 使用缓存的旋转中心位置(固定不变)
const centerPos = model.userData.rotorCenterPosition;
// 输出第一个风电机组的centerPos到控制台
// if (index === 0 && child.name.toLowerCase().includes('200')) {
// console.log('第一个风电机组的centerPos:', centerPos);
// }
const offset = child.userData.initialOffset;
// 围绕固定的旋转中心做圆周运动
const angle = time * 2.0;
const cosAngle = Math.cos(angle);
const sinAngle = Math.sin(angle);
child.position.x = centerPos.x + (offset.x * cosAngle - offset.y * sinAngle);
child.position.y = centerPos.y + (offset.x * sinAngle + offset.y * cosAngle) + 4;
child.position.z = centerPos.z + offset.z - 4;
// 同时让叶片自身也旋转
child.rotation.z = angle;
} else {
// 如果没有找到186部件使用原来的旋转方式
child.rotation.z = time * 2.0;
}
}
});
});
}
// 渲染场景
if (scene && camera && renderer) {
renderer.render(scene, camera);
// 每隔一段时间输出渲染信息
if (Math.floor(time) % 5 === 0 && time % 1 < 0.1) {
console.log('正在渲染场景,时间:', Math.floor(time), '场景对象数量:', scene.children.length);
}
} else {
console.warn('场景、相机或渲染器未初始化');
}
}
// 窗口大小变化处理
function onWindowResize() {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize(window.innerWidth, window.innerHeight);
}
// 页面加载完成后初始化
window.addEventListener('DOMContentLoaded', function () {
console.log('DOM加载完成开始初始化Three.js场景');
// 检查Three.js是否加载
if (typeof THREE === 'undefined') {
console.error('Three.js未加载');
document.getElementById('loading').innerHTML = '错误Three.js库未加载';
return;
}
console.log('Three.js版本:', THREE.REVISION);
// 隐藏加载提示
const loadingElement = document.getElementById('loading');
if (loadingElement) {
loadingElement.style.display = 'none';
}
init();
animate();
});
// 添加一个切换控制模式的函数
function toggleControls() {
if (pointerLockControls) {
if (pointerLockControls.isLocked) {
pointerLockControls.unlock();
} else {
pointerLockControls.lock();
}
}
}
// 键盘事件处理函数
function onKeyDown(event) {
switch (event.code) {
case 'ArrowUp':
case 'KeyW':
moveForward = true;
break;
case 'ArrowLeft':
case 'KeyA':
moveLeft = true;
break;
case 'ArrowDown':
case 'KeyS':
moveBackward = true;
break;
case 'ArrowRight':
case 'KeyD':
moveRight = true;
break;
case 'KeyQ':
moveUp = true;
break;
case 'KeyE':
moveDown = true;
break;
}
}
function onKeyUp(event) {
switch (event.code) {
case 'ArrowUp':
case 'KeyW':
moveForward = false;
break;
case 'ArrowLeft':
case 'KeyA':
moveLeft = false;
break;
case 'ArrowDown':
case 'KeyS':
moveBackward = false;
break;
case 'ArrowRight':
case 'KeyD':
moveRight = false;
break;
case 'KeyQ':
moveUp = false;
break;
case 'KeyE':
moveDown = false;
break;
}
}