cube-parameters
Version:
A sophisticated 3D model viewer built with React, TypeScript, and Three.js, featuring advanced visualization tools, measurement capabilities, and lighting controls.
119 lines (93 loc) • 3.49 kB
text/typescript
import { useRef, useEffect } from 'react';
import * as THREE from 'three';
interface SunlightSettings {
intensity: number;
azimuth: number;
elevation: number;
color: string;
castShadow: boolean;
}
interface AmbientLightSettings {
intensity: number;
color: string;
}
export const useLighting = (
scene: THREE.Scene | null,
sunlight: SunlightSettings,
ambientLight: AmbientLightSettings,
shadowQuality: 'low' | 'medium' | 'high'
) => {
const directionalLightRef = useRef<THREE.DirectionalLight | null>(null);
const ambientLightRef = useRef<THREE.AmbientLight | null>(null);
useEffect(() => {
if (!scene) return;
// Ambient Light
const ambient = new THREE.AmbientLight(ambientLight.color, ambientLight.intensity);
ambientLightRef.current = ambient;
scene.add(ambient);
// Directional Light (Sun)
const directional = new THREE.DirectionalLight(sunlight.color, sunlight.intensity);
directionalLightRef.current = directional;
// Position sun based on azimuth and elevation
const azimuthRad = (sunlight.azimuth * Math.PI) / 180;
const elevationRad = (sunlight.elevation * Math.PI) / 180;
const x = Math.cos(elevationRad) * Math.sin(azimuthRad);
const y = Math.sin(elevationRad);
const z = Math.cos(elevationRad) * Math.cos(azimuthRad);
directional.position.set(x * 10, y * 10, z * 10);
directional.castShadow = sunlight.castShadow;
// Shadow settings based on quality
const shadowMapSize = {
low: 512,
medium: 1024,
high: 2048
};
directional.shadow.mapSize.width = shadowMapSize[shadowQuality];
directional.shadow.mapSize.height = shadowMapSize[shadowQuality];
directional.shadow.camera.near = 0.5;
directional.shadow.camera.far = 50;
directional.shadow.camera.left = -10;
directional.shadow.camera.right = 10;
directional.shadow.camera.top = 10;
directional.shadow.camera.bottom = -10;
scene.add(directional);
return () => {
if (ambient) scene.remove(ambient);
if (directional) scene.remove(directional);
};
}, [scene]);
// Update sunlight properties
useEffect(() => {
if (!directionalLightRef.current) return;
const light = directionalLightRef.current;
light.intensity = sunlight.intensity;
light.color.set(sunlight.color);
light.castShadow = sunlight.castShadow;
// Update position
const azimuthRad = (sunlight.azimuth * Math.PI) / 180;
const elevationRad = (sunlight.elevation * Math.PI) / 180;
const x = Math.cos(elevationRad) * Math.sin(azimuthRad);
const y = Math.sin(elevationRad);
const z = Math.cos(elevationRad) * Math.cos(azimuthRad);
light.position.set(x * 10, y * 10, z * 10);
}, [sunlight]);
// Update ambient light properties
useEffect(() => {
if (!ambientLightRef.current) return;
ambientLightRef.current.intensity = ambientLight.intensity;
ambientLightRef.current.color.set(ambientLight.color);
}, [ambientLight]);
// Update shadow quality
useEffect(() => {
if (!directionalLightRef.current) return;
const shadowMapSize = {
low: 512,
medium: 1024,
high: 2048
};
const light = directionalLightRef.current;
light.shadow.mapSize.width = shadowMapSize[shadowQuality];
light.shadow.mapSize.height = shadowMapSize[shadowQuality];
}, [shadowQuality]);
return { directionalLightRef, ambientLightRef };
};