239 lines
7.0 KiB
JavaScript
239 lines
7.0 KiB
JavaScript
import * as THREE from 'three';
|
||
import { RectAreaLightUniformsLib } from 'three/examples/jsm/lights/RectAreaLightUniformsLib.js';
|
||
import { RectAreaLightHelper } from 'three/examples/jsm/helpers/RectAreaLightHelper.js';
|
||
|
||
RectAreaLightUniformsLib.init();
|
||
|
||
/**
|
||
* Базовый свет сцены (Ambient + Directional)
|
||
*/
|
||
export function setupLights(scene) {
|
||
const ambient = new THREE.AmbientLight(0xffffff, 0.8);
|
||
scene.add(ambient);
|
||
|
||
const key = new THREE.DirectionalLight(0xffffff, 0.2);
|
||
key.position.set(0, 0, 0);
|
||
scene.add(key);
|
||
|
||
const fill = new THREE.DirectionalLight(0xffffff, 0.2);
|
||
fill.position.set(0, 0, 0);
|
||
scene.add(fill);
|
||
}
|
||
|
||
/**
|
||
* Потолочные споты, привязанные к Spot_*
|
||
*/
|
||
export function setupRoomLights(room) {
|
||
const spotNames = [
|
||
'Spot_001','Spot_002','Spot_003','Spot_004',
|
||
'Spot_005','Spot_006','Spot_007','Spot_008'
|
||
];
|
||
|
||
spotNames.forEach((spotName) => {
|
||
const spotObject = room.getObjectByName(spotName);
|
||
if (!spotObject) {
|
||
console.warn(`Объект не найден: ${spotName}`);
|
||
return;
|
||
}
|
||
|
||
// === СПОТ-СВЕТ ===
|
||
const spotLight = new THREE.SpotLight(
|
||
0xffffff,
|
||
5, // intensity
|
||
80, // distance
|
||
Math.PI / 4, // angle
|
||
0.5, // penumbra
|
||
1.5 // decay (физически корректный)
|
||
);
|
||
|
||
spotObject.add(spotLight);
|
||
spotLight.position.set(0, 0, 0);
|
||
|
||
// === Target (локально по -Z) ===
|
||
spotObject.add(spotLight.target);
|
||
spotLight.target.position.set(0, 0, -1);
|
||
spotLight.target.updateMatrixWorld(true);
|
||
|
||
// === ВИЗУАЛЬНЫЙ СВЕТЯЩИЙСЯ КРУГ (LED-линза) ===
|
||
const bulb = new THREE.Mesh(
|
||
new THREE.CircleGeometry(0.01, 24),
|
||
new THREE.MeshStandardMaterial({
|
||
color: 0xffffff,
|
||
emissive: 0xffffff,
|
||
emissiveIntensity: 2.5,
|
||
roughness: 0.2,
|
||
metalness: 0.0,
|
||
side: THREE.DoubleSide
|
||
})
|
||
);
|
||
|
||
// CircleGeometry смотрит по +Z → поворачиваем вниз
|
||
bulb.rotation.x = -Math.PI;
|
||
bulb.position.set(0, 0, 0.001);
|
||
|
||
spotObject.add(bulb);
|
||
|
||
console.log(`Спот корректно создан: ${spotName}`);
|
||
});
|
||
}
|
||
|
||
/**
|
||
* Создает LED-ленту с рассеянным светом на объекте ceilinglight
|
||
* @param {THREE.Object3D} ceilinglight - объект для привязки LED-ленты
|
||
* @param {Object} options - настройки { position: [x,y,z], rotationDeg: [x,y,z], ... }
|
||
*/
|
||
function createLEDStrip(ceilinglight, options = {}) {
|
||
// Конвертация градусов в радианы
|
||
const toRad = (deg) => deg * Math.PI / 180;
|
||
|
||
// Размеры LED-ленты (подстрой под модель)
|
||
const width = options.width || 0.01;
|
||
const height = options.height || 1.0;
|
||
|
||
// RectAreaLight - рассеянный свет
|
||
const rectLight = new THREE.RectAreaLight(
|
||
options.color || 0xffffff,
|
||
options.intensity || 6,
|
||
width,
|
||
height
|
||
);
|
||
ceilinglight.add(rectLight);
|
||
|
||
// Позиция
|
||
if (options.position) {
|
||
rectLight.position.set(...options.position);
|
||
}
|
||
|
||
// Поворот (градусы)
|
||
if (options.rotationDeg) {
|
||
rectLight.rotation.set(...options.rotationDeg.map(toRad));
|
||
}
|
||
|
||
// Направление света (target - локальные координаты)
|
||
if (options.target) {
|
||
const targetObj = new THREE.Object3D();
|
||
targetObj.position.set(...options.target);
|
||
ceilinglight.add(targetObj);
|
||
rectLight.target = targetObj;
|
||
}
|
||
|
||
// Визуальная полоса LED
|
||
const ledMesh = new THREE.Mesh(
|
||
new THREE.PlaneGeometry(width, height),
|
||
new THREE.MeshStandardMaterial({
|
||
color: 0xffffff,
|
||
emissive: 0xffffff,
|
||
emissiveIntensity: 2,
|
||
side: THREE.DoubleSide
|
||
})
|
||
);
|
||
if (options.position) {
|
||
ledMesh.position.set(...options.position);
|
||
}
|
||
if (options.rotationDeg) {
|
||
ledMesh.rotation.set(...options.rotationDeg.map(toRad));
|
||
}
|
||
ceilinglight.add(ledMesh);
|
||
|
||
// Helper для визуализации RectAreaLight
|
||
const rectLightHelper = new RectAreaLightHelper(rectLight, 0xff0000);
|
||
if (options.position) {
|
||
rectLightHelper.position.set(...options.position);
|
||
}
|
||
if (options.rotationDeg) {
|
||
rectLightHelper.rotation.set(...options.rotationDeg.map(toRad));
|
||
}
|
||
ceilinglight.add(rectLightHelper);
|
||
|
||
// DirectionalLight для теней
|
||
const shadowLight = new THREE.DirectionalLight(0xffffff, 0.5);
|
||
shadowLight.castShadow = true;
|
||
shadowLight.shadow.mapSize.width = 1024;
|
||
shadowLight.shadow.mapSize.height = 1024;
|
||
shadowLight.shadow.camera.near = 0.1;
|
||
shadowLight.shadow.camera.far = 10;
|
||
shadowLight.shadow.camera.left = -5;
|
||
shadowLight.shadow.camera.right = 5;
|
||
shadowLight.shadow.camera.top = 5;
|
||
shadowLight.shadow.camera.bottom = -5;
|
||
shadowLight.shadow.bias = -0.001;
|
||
|
||
if (options.shadowPosition) {
|
||
shadowLight.position.set(...options.shadowPosition);
|
||
} else {
|
||
shadowLight.position.set(0, 0, 0);
|
||
}
|
||
shadowLight.target.position.set(0, 1, 0);
|
||
ceilinglight.add(shadowLight);
|
||
ceilinglight.add(shadowLight.target);
|
||
}
|
||
|
||
/**
|
||
* Создает LED-ленты на всех объектах ceilinglight_001 - ceilinglight_004
|
||
* @param {THREE.Object3D} room - объект комнаты, содержащий ceilinglight объекты
|
||
*/
|
||
export function setupLEDStrip(room) {
|
||
// Настройки для каждой ленты
|
||
const ledConfigs = {
|
||
ceilinglight_001: {
|
||
position: [0, 0, 0.01],
|
||
rotationDeg: [0, 0, 0],
|
||
target: [0, 1, 0],
|
||
shadowPosition: [0, 0, 0],
|
||
width: 0.01,
|
||
height: 1.75,
|
||
color: 0xffffff,
|
||
intensity: 50
|
||
},
|
||
ceilinglight_002: {
|
||
position: [0, 0, 0.01],
|
||
rotationDeg: [0, 0, 90],
|
||
target: [0, 1, 0],
|
||
shadowPosition: [0, 0, 0],
|
||
width: 0.01,
|
||
height: 3.6,
|
||
color: 0xffffff,
|
||
intensity: 50
|
||
},
|
||
ceilinglight_003: {
|
||
position: [0, 0, 0.01],
|
||
rotationDeg: [0, 0, 0],
|
||
target: [0, 1, 0],
|
||
shadowPosition: [0, 0, 0],
|
||
width: 0.01,
|
||
height: 1.75,
|
||
color: 0xffffff,
|
||
intensity: 50
|
||
},
|
||
ceilinglight_004: {
|
||
position: [0, 0, 0.01],
|
||
rotationDeg: [0, 0, 90],
|
||
target: [0, 1, 0],
|
||
shadowPosition: [0, 0, 0],
|
||
width: 0.01,
|
||
height: 3.6,
|
||
color: 0xffffff,
|
||
intensity: 50
|
||
}
|
||
};
|
||
|
||
let created = 0;
|
||
|
||
for (let i = 1; i <= 4; i++) {
|
||
const name = `ceilinglight_${String(i).padStart(3, '0')}`;
|
||
const ceilinglight = room.getObjectByName(name);
|
||
const options = ledConfigs[name] || {};
|
||
if (ceilinglight) {
|
||
createLEDStrip(ceilinglight, options);
|
||
const worldPos = new THREE.Vector3();
|
||
ceilinglight.getWorldPosition(worldPos);
|
||
console.log(`LED-лента создана: ${name} | позиция: (${worldPos.x.toFixed(2)}, ${worldPos.y.toFixed(2)}, ${worldPos.z.toFixed(2)})`);
|
||
created++;
|
||
} else {
|
||
console.warn(`Объект не найден: ${name}`);
|
||
}
|
||
}
|
||
|
||
console.log(`Создано LED-лент: ${created}`);
|
||
}
|