Прозрачность появляется только при прямоугольном освещении, а не точечный источник света.
Посмотрите демонстрационное видео, и вы увидите, что свет появляется снаружи, как если бы коробка была полупрозрачной.
Код: Выделить всё
Simple Rectangle Light
body { margin: 0; }
canvas { display: block; }
#controls {
position: fixed;
top: 10px;
left: 10px;
background: rgba(0,0,0,0.7);
padding: 10px;
border-radius: 5px;
color: white;
font-family: Arial;
}
Rectangle Light
Point Light
Rectangle Light Position:
X:
Y:
Z:
Rectangle Light Rotation:
X:
Y:
Z:
Rectangle Light Size:
Width:
Height:
Material Properties:
Color:
Roughness:
Metalness:
{
"imports": {
"three": "https://unpkg.com/three@0.160.0/build/three.module.js",
"three/examples/jsm/controls/OrbitControls.js": "https://unpkg.com/three@0.160.0/examples/jsm/controls/OrbitControls.js",
"three/examples/jsm/lights/RectAreaLightUniformsLib.js": "https://unpkg.com/three@0.160.0/examples/jsm/lights/RectAreaLightUniformsLib.js",
"three/examples/jsm/helpers/RectAreaLightHelper.js": "https://unpkg.com/three@0.160.0/examples/jsm/helpers/RectAreaLightHelper.js"
}
}
import * as THREE from 'three';
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls.js';
import { RectAreaLightUniformsLib } from 'three/examples/jsm/lights/RectAreaLightUniformsLib.js';
import { RectAreaLightHelper } from 'three/examples/jsm/helpers/RectAreaLightHelper.js';
// Scene setup
const scene = new THREE.Scene();
scene.background = new THREE.Color(0x000000);
// Camera setup
const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
camera.position.z = 5;
// Renderer setup
const renderer = new THREE.WebGLRenderer({ antialias: true });
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
// Initialize rect area light uniforms
RectAreaLightUniformsLib.init();
// Controls
const controls = new OrbitControls(camera, renderer.domElement);
// Comment out texture loading
// const textureLoader = new THREE.TextureLoader();
// const skinTexture = textureLoader.load('skin-image.png');
// Add material definition before box creation
const material = new THREE.MeshStandardMaterial({
color: 0x333333,
roughness: 0.9,
metalness: 0.0,
opacity: 1.0,
transparent: false
});
// Create box
const outerSize = 2;
const thickness = 0.2; // Back to original thickness
const box = new THREE.Group();
// Bottom
const bottom = new THREE.Mesh(
new THREE.BoxGeometry(outerSize, thickness, outerSize),
material
);
bottom.position.y = -outerSize/2;
box.add(bottom);
// Front wall
const front = new THREE.Mesh(
new THREE.BoxGeometry(outerSize, outerSize, thickness),
material
);
front.position.z = outerSize/2 - thickness/2;
front.position.y = -thickness/2;
box.add(front);
// Back wall
const back = new THREE.Mesh(
new THREE.BoxGeometry(outerSize, outerSize, thickness),
material
);
back.position.z = -outerSize/2 + thickness/2;
back.position.y = -thickness/2;
box.add(back);
// Left wall
const left = new THREE.Mesh(
new THREE.BoxGeometry(thickness, outerSize, outerSize),
material
);
left.position.x = -outerSize/2 + thickness/2;
left.position.y = -thickness/2;
box.add(left);
// Right wall
const right = new THREE.Mesh(
new THREE.BoxGeometry(thickness, outerSize, outerSize),
material
);
right.position.x = outerSize/2 - thickness/2;
right.position.y = -thickness/2;
box.add(right);
scene.add(box);
// Rectangle light at bottom
const width = 1.0; // Smaller than inner width (was 1.8)
const height = 1.0; // Make it square like the box (was 1.8)
const intensity = 10;
const rectLight = new THREE.RectAreaLight(0xff0000, intensity, width, height);
rectLight.position.set(0, -0.9 + 0.01, 0); // Keep it just above bottom
rectLight.rotation.x = Math.PI / 2; // Face up
scene.add(rectLight);
// Add visible helper for the light
const helper = new RectAreaLightHelper(rectLight);
rectLight.add(helper);
// Move ambient light before PMREM setup
const ambientLight = new THREE.AmbientLight(0xffffff, 2.0);
scene.add(ambientLight);
// Add point light inside box
const pointLight = new THREE.PointLight(0xff0000, 10.0);
pointLight.position.set(0, -0.5, 0);
pointLight.distance = 3; // How far the light reaches
pointLight.decay = 1; // How quickly it fades with distance
scene.add(pointLight);
// Make the visualization sphere bigger
const sphereGeometry = new THREE.SphereGeometry(0.2, 16, 16); // Increase from 0.05 to 0.2
const sphereMaterial = new THREE.MeshBasicMaterial({ color: 0xff0000 });
const lightSphere = new THREE.Mesh(sphereGeometry, sphereMaterial);
lightSphere.position.copy(pointLight.position);
scene.add(lightSphere);
// Animation
function animate() {
requestAnimationFrame(animate);
controls.update();
renderer.render(scene, camera);
}
animate();
// Handle window resize
window.addEventListener('resize', () => {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize(window.innerWidth, window.innerHeight);
});
document.getElementById('rectLight').addEventListener('change', (e) => {
rectLight.visible = e.target.checked;
helper.visible = e.target.checked;
});
document.getElementById('pointLight').addEventListener('change', (e) => {
pointLight.visible = e.target.checked;
lightSphere.visible = e.target.checked;
});
document.getElementById('rectX').addEventListener('input', (e) => {
rectLight.position.x = parseFloat(e.target.value);
updateURL();
});
document.getElementById('rectY').addEventListener('input', (e) => {
rectLight.position.y = parseFloat(e.target.value) + 0.01; // Keep slight offset from bottom
});
document.getElementById('rectZ').addEventListener('input', (e) => {
rectLight.position.z = parseFloat(e.target.value);
});
document.getElementById('rectRotX').addEventListener('input', (e) => {
rectLight.rotation.x = parseFloat(e.target.value);
});
document.getElementById('rectRotY').addEventListener('input', (e) => {
rectLight.rotation.y = parseFloat(e.target.value);
});
document.getElementById('rectRotZ').addEventListener('input', (e) => {
rectLight.rotation.z = parseFloat(e.target.value);
});
document.getElementById('rectWidth').addEventListener('input', (e) => {
rectLight.width = parseFloat(e.target.value);
helper.update(); // Update the helper to show new size
});
document.getElementById('rectHeight').addEventListener('input', (e) => {
rectLight.height = parseFloat(e.target.value);
helper.update(); // Update the helper to show new size
});
document.getElementById('matColor').addEventListener('input', (e) => {
const value = parseInt(e.target.value);
material.color.setRGB(value/255, value/255, value/255);
updateURL();
});
document.getElementById('matRough').addEventListener('input', (e) => {
material.roughness = parseFloat(e.target.value);
});
document.getElementById('matMetal').addEventListener('input', (e) => {
material.metalness = parseFloat(e.target.value);
});
// Add function to update URL with current settings
function updateURL() {
const params = new URLSearchParams();
// Material settings
params.set('color', document.getElementById('matColor').value);
params.set('rough', document.getElementById('matRough').value);
params.set('metal', document.getElementById('matMetal').value);
// Light visibility
params.set('rectVisible', document.getElementById('rectLight').checked);
params.set('pointVisible', document.getElementById('pointLight').checked);
// Rectangle light settings
params.set('rectX', document.getElementById('rectX').value);
params.set('rectY', document.getElementById('rectY').value);
params.set('rectZ', document.getElementById('rectZ').value);
params.set('rectRotX', document.getElementById('rectRotX').value);
params.set('rectRotY', document.getElementById('rectRotY').value);
params.set('rectRotZ', document.getElementById('rectRotZ').value);
params.set('rectWidth', document.getElementById('rectWidth').value);
params.set('rectHeight', document.getElementById('rectHeight').value);
window.history.replaceState({}, '', `${window.location.pathname}?${params.toString()}`);
}
// Also add function to load settings from URL on page load
function loadFromURL() {
const params = new URLSearchParams(window.location.search);
// Helper function to load a parameter
function loadParam(id, prop, obj, converter = parseFloat) {
if(params.has(id)) {
const value = converter(params.get(id));
document.getElementById(id).value = value;
if(obj && prop) obj[prop] = value;
}
}
// Load all parameters
loadParam('color', null, null, value => {
const v = parseInt(value);
material.color.setRGB(v/255, v/255, v/255);
return v;
});
loadParam('rough', 'roughness', material);
loadParam('metal', 'metalness', material);
loadParam('rectX', 'x', rectLight.position);
// ... etc for all parameters
}
// Call on page load
loadFromURL();
Подробнее здесь: https://stackoverflow.com/questions/793 ... n-three-js