three.js SpotLight 锐角光束不工作
three.js SpotLight acute beam not working
我是 three.js 的新手,但我过去有 Unity 的 3d 对象和渲染经验,
我在使用 SpotLight 时遇到了问题,我正在尝试从导入的 obj 中发光,以使其看起来像一个工作 lamp。
我无法将光线的角度设置为锐角,因为当它超过某个值时它就不亮了。
这是相关代码:
const objLight = new THREE.SpotLight('yellow', 5);
objLight.angle = Math.PI/2;
objLight.penumbra = 0.1;
objLight.decay = 1;
objLight.distance = 40;
objLight.position.set(-0.48, 0.7, 0);
objLight.target.position.set(-0.9, 0, 0);
objLight.castShadow = true;
scene.add(objLight);
scene.add(objLight.target);
这是角度设置为
时的样子
Math.PI/2
:https://prnt.sc/vzddfy。
Math.PI/3
:https://prnt.sc/vzdeel。
Math.PI/4
: https://prnt.sc/vzdeks .
现在我将相机移近一些,我看到光线正在照亮物体,仅此而已:https://prnt.sc/vzder0 .
我试了一个小时的值,但找不到解决方案,我什至尝试删除 obj 和盒子,但它没有做任何事情。
不过我确实发现,如果我将光线从 x=-0.48
移到 x=-4.48
,我可以使它变得锐利,直到数学。PI/6:https://prnt.sc/vzdgls
如果我想让它更尖锐,我需要把它移得更远。
我的理论是它与它与目标的距离或其他东西有关,我试图将目标移开一点但它没有做任何事情。
有人知道可能是什么问题吗?
其余代码:
let renderer, camera, scene;
// const THREE = require('three');
function init() {
renderer = new THREE.WebGLRenderer({antialias: true});
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.shadowMap.enabled = true;
document.body.appendChild(renderer.domElement);
scene = new THREE.Scene();
// scene.background = new THREE.Color('red');
camera = new THREE.PerspectiveCamera(75, window.innerWidth/window.innerHeight, 0.1, 1000);
camera.position.z = 5;
new THREE.OrbitControls(camera, renderer.domElement);
const light = new THREE.AmbientLight('white', 0.2);
scene.add(light);
const BoxGeo = new THREE.BoxGeometry(1, 1, 1);
const BoxMat = new THREE.MeshLambertMaterial({color: 'blue'});
const Box = new THREE.Mesh(BoxGeo, BoxMat);
Box.castShadow = true;
scene.add(Box);
const TopPlaneGeo = new THREE.PlaneGeometry(10, 10, 1);
const TopPlaneMat = new THREE.MeshLambertMaterial({color: 'white', side: THREE.DoubleSide});
const TopPlane = new THREE.Mesh(TopPlaneGeo, TopPlaneMat);
TopPlane.position.y = 5;
TopPlane.rotation.x = Math.PI/2;
TopPlane.receiveShadow = true;
scene.add(TopPlane);
const BotPlaneGeo = new THREE.PlaneGeometry(10, 10, 1);
const BotPlaneMat = new THREE.MeshLambertMaterial({color: 'white', side: THREE.DoubleSide});
const BotPlane = new THREE.Mesh(BotPlaneGeo, BotPlaneMat);
BotPlane.position.y = -1;
BotPlane.rotation.x = Math.PI/2;
BotPlane.receiveShadow = true;
scene.add(BotPlane);
const loader = new THREE.OBJLoader();
loader.load
(
'objects/Lampe_FerBlanc.obj',
function(obj) {
obj.position.set(-0.40, 0.5, 0);
obj.scale.set(0.01, 0.01, 0.01);
scene.add(obj);
}
)
const objLight = new THREE.SpotLight('yellow', 5);
objLight.angle = Math.PI/6;
objLight.penumbra = 0.1;
objLight.decay = 1;
objLight.distance = 40;
objLight.position.set(-4.48, 0.7, 0);
objLight.target.position.set(-0.9, 0, 0);
objLight.castShadow = true;
scene.add(objLight);
scene.add(objLight.target);
const helper = new THREE.SpotLightHelper(objLight);
helper.name = 'helper';
scene.add(helper);
window.addEventListener('resize', () => {
renderer.setSize(window.innerWidth, window.innerHeight);
camera.aspect = window.innerWidth/window.innerHeight;
camera.updateProjectionMatrix();
})
}
function animate() {
requestAnimationFrame(animate);
scene.getObjectByName('helper').update();
renderer.render(scene, camera);
}
init();
animate();
我认为这是因为您使用的是 MeshLambertMaterial
,它计算每个顶点的光照,而不是计算每个面部像素。当光线照射到一个顶点(广角)时,它就会亮起。但是当光线只照射到面而没有接触到顶点(在较窄的角度上)时,平面不会显示光线。另外,由于光的性质,用黄光照射蓝色盒子不会显示任何东西:#ffff00 * #0000ff = #000000
.
尝试更改为 MeshPhongMaterial
,您会发现灯光和阴影的计算更加准确。 运行 下面的代码片段可以看到它的实际效果。
let renderer, camera, scene;
let objLight;
let objLightPos = 0;
let objLightAngle = 1;
// const THREE = require('three');
function init() {
renderer = new THREE.WebGLRenderer({antialias: true});
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.shadowMap.enabled = true;
document.body.appendChild(renderer.domElement);
scene = new THREE.Scene();
camera = new THREE.PerspectiveCamera(75, window.innerWidth/window.innerHeight, 0.1, 100);
camera.position.z = 5;
new THREE.OrbitControls(camera, renderer.domElement);
const light = new THREE.AmbientLight('white', 0.2);
scene.add(light);
const BoxGeo = new THREE.BoxGeometry(1, 1, 1);
const BoxMat = new THREE.MeshPhongMaterial({color: 'white'});
const Box = new THREE.Mesh(BoxGeo, BoxMat);
Box.castShadow = true;
scene.add(Box);
const TopPlaneGeo = new THREE.PlaneGeometry(10, 10, 1);
const TopPlaneMat = new THREE.MeshPhongMaterial({color: 'white', side: THREE.DoubleSide});
const TopPlane = new THREE.Mesh(TopPlaneGeo, TopPlaneMat);
TopPlane.position.y = 5;
TopPlane.rotation.x = Math.PI/2;
TopPlane.receiveShadow = true;
scene.add(TopPlane);
const BotPlaneGeo = new THREE.PlaneGeometry(10, 10, 1);
const BotPlaneMat = new THREE.MeshPhongMaterial({color: 'white', side: THREE.DoubleSide});
const BotPlane = new THREE.Mesh(BotPlaneGeo, BotPlaneMat);
BotPlane.position.y = -1;
BotPlane.rotation.x = Math.PI/2;
BotPlane.receiveShadow = true;
scene.add(BotPlane);
objLight = new THREE.SpotLight('yellow', 5);
objLight.angle = Math.PI/6;
objLight.penumbra = 0.1;
objLight.decay = 1;
objLight.distance = 40;
objLight.position.set(-0.48, 0.7, 0);
objLight.target.position.set(-0.9, 0, 0);
objLight.castShadow = true;
scene.add(objLight);
scene.add(objLight.target);
const helper = new THREE.SpotLightHelper(objLight);
helper.name = 'helper';
scene.add(helper);
window.addEventListener('resize', () => {
renderer.setSize(window.innerWidth, window.innerHeight);
camera.aspect = window.innerWidth/window.innerHeight;
camera.updateProjectionMatrix();
})
}
function animate() {
objLightPos += 0.01;
objLightAngle += 0.03;
requestAnimationFrame(animate);
objLight.position.set(Math.sin(objLightPos), 3, 0);
objLight.angle = Math.sin(objLightAngle) * 0.5 + 0.5;
scene.getObjectByName('helper').update();
renderer.render(scene, camera);
}
init();
animate();
body { margin: 0; }
canvas { width: 100vw; height: 100vh; display: block; }
<script src="https://threejs.org/build/three.js"></script>
<script src="https://cdn.jsdelivr.net/npm/three@0.123/examples/js/controls/OrbitControls.js"></script>
我是 three.js 的新手,但我过去有 Unity 的 3d 对象和渲染经验, 我在使用 SpotLight 时遇到了问题,我正在尝试从导入的 obj 中发光,以使其看起来像一个工作 lamp。 我无法将光线的角度设置为锐角,因为当它超过某个值时它就不亮了。
这是相关代码:
const objLight = new THREE.SpotLight('yellow', 5);
objLight.angle = Math.PI/2;
objLight.penumbra = 0.1;
objLight.decay = 1;
objLight.distance = 40;
objLight.position.set(-0.48, 0.7, 0);
objLight.target.position.set(-0.9, 0, 0);
objLight.castShadow = true;
scene.add(objLight);
scene.add(objLight.target);
这是角度设置为
时的样子Math.PI/2
:https://prnt.sc/vzddfy。
Math.PI/3
:https://prnt.sc/vzdeel。
Math.PI/4
: https://prnt.sc/vzdeks .
现在我将相机移近一些,我看到光线正在照亮物体,仅此而已:https://prnt.sc/vzder0 .
我试了一个小时的值,但找不到解决方案,我什至尝试删除 obj 和盒子,但它没有做任何事情。
不过我确实发现,如果我将光线从 x=-0.48
移到 x=-4.48
,我可以使它变得锐利,直到数学。PI/6:https://prnt.sc/vzdgls
如果我想让它更尖锐,我需要把它移得更远。
我的理论是它与它与目标的距离或其他东西有关,我试图将目标移开一点但它没有做任何事情。
有人知道可能是什么问题吗?
其余代码:
let renderer, camera, scene;
// const THREE = require('three');
function init() {
renderer = new THREE.WebGLRenderer({antialias: true});
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.shadowMap.enabled = true;
document.body.appendChild(renderer.domElement);
scene = new THREE.Scene();
// scene.background = new THREE.Color('red');
camera = new THREE.PerspectiveCamera(75, window.innerWidth/window.innerHeight, 0.1, 1000);
camera.position.z = 5;
new THREE.OrbitControls(camera, renderer.domElement);
const light = new THREE.AmbientLight('white', 0.2);
scene.add(light);
const BoxGeo = new THREE.BoxGeometry(1, 1, 1);
const BoxMat = new THREE.MeshLambertMaterial({color: 'blue'});
const Box = new THREE.Mesh(BoxGeo, BoxMat);
Box.castShadow = true;
scene.add(Box);
const TopPlaneGeo = new THREE.PlaneGeometry(10, 10, 1);
const TopPlaneMat = new THREE.MeshLambertMaterial({color: 'white', side: THREE.DoubleSide});
const TopPlane = new THREE.Mesh(TopPlaneGeo, TopPlaneMat);
TopPlane.position.y = 5;
TopPlane.rotation.x = Math.PI/2;
TopPlane.receiveShadow = true;
scene.add(TopPlane);
const BotPlaneGeo = new THREE.PlaneGeometry(10, 10, 1);
const BotPlaneMat = new THREE.MeshLambertMaterial({color: 'white', side: THREE.DoubleSide});
const BotPlane = new THREE.Mesh(BotPlaneGeo, BotPlaneMat);
BotPlane.position.y = -1;
BotPlane.rotation.x = Math.PI/2;
BotPlane.receiveShadow = true;
scene.add(BotPlane);
const loader = new THREE.OBJLoader();
loader.load
(
'objects/Lampe_FerBlanc.obj',
function(obj) {
obj.position.set(-0.40, 0.5, 0);
obj.scale.set(0.01, 0.01, 0.01);
scene.add(obj);
}
)
const objLight = new THREE.SpotLight('yellow', 5);
objLight.angle = Math.PI/6;
objLight.penumbra = 0.1;
objLight.decay = 1;
objLight.distance = 40;
objLight.position.set(-4.48, 0.7, 0);
objLight.target.position.set(-0.9, 0, 0);
objLight.castShadow = true;
scene.add(objLight);
scene.add(objLight.target);
const helper = new THREE.SpotLightHelper(objLight);
helper.name = 'helper';
scene.add(helper);
window.addEventListener('resize', () => {
renderer.setSize(window.innerWidth, window.innerHeight);
camera.aspect = window.innerWidth/window.innerHeight;
camera.updateProjectionMatrix();
})
}
function animate() {
requestAnimationFrame(animate);
scene.getObjectByName('helper').update();
renderer.render(scene, camera);
}
init();
animate();
我认为这是因为您使用的是 MeshLambertMaterial
,它计算每个顶点的光照,而不是计算每个面部像素。当光线照射到一个顶点(广角)时,它就会亮起。但是当光线只照射到面而没有接触到顶点(在较窄的角度上)时,平面不会显示光线。另外,由于光的性质,用黄光照射蓝色盒子不会显示任何东西:#ffff00 * #0000ff = #000000
.
尝试更改为 MeshPhongMaterial
,您会发现灯光和阴影的计算更加准确。 运行 下面的代码片段可以看到它的实际效果。
let renderer, camera, scene;
let objLight;
let objLightPos = 0;
let objLightAngle = 1;
// const THREE = require('three');
function init() {
renderer = new THREE.WebGLRenderer({antialias: true});
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.shadowMap.enabled = true;
document.body.appendChild(renderer.domElement);
scene = new THREE.Scene();
camera = new THREE.PerspectiveCamera(75, window.innerWidth/window.innerHeight, 0.1, 100);
camera.position.z = 5;
new THREE.OrbitControls(camera, renderer.domElement);
const light = new THREE.AmbientLight('white', 0.2);
scene.add(light);
const BoxGeo = new THREE.BoxGeometry(1, 1, 1);
const BoxMat = new THREE.MeshPhongMaterial({color: 'white'});
const Box = new THREE.Mesh(BoxGeo, BoxMat);
Box.castShadow = true;
scene.add(Box);
const TopPlaneGeo = new THREE.PlaneGeometry(10, 10, 1);
const TopPlaneMat = new THREE.MeshPhongMaterial({color: 'white', side: THREE.DoubleSide});
const TopPlane = new THREE.Mesh(TopPlaneGeo, TopPlaneMat);
TopPlane.position.y = 5;
TopPlane.rotation.x = Math.PI/2;
TopPlane.receiveShadow = true;
scene.add(TopPlane);
const BotPlaneGeo = new THREE.PlaneGeometry(10, 10, 1);
const BotPlaneMat = new THREE.MeshPhongMaterial({color: 'white', side: THREE.DoubleSide});
const BotPlane = new THREE.Mesh(BotPlaneGeo, BotPlaneMat);
BotPlane.position.y = -1;
BotPlane.rotation.x = Math.PI/2;
BotPlane.receiveShadow = true;
scene.add(BotPlane);
objLight = new THREE.SpotLight('yellow', 5);
objLight.angle = Math.PI/6;
objLight.penumbra = 0.1;
objLight.decay = 1;
objLight.distance = 40;
objLight.position.set(-0.48, 0.7, 0);
objLight.target.position.set(-0.9, 0, 0);
objLight.castShadow = true;
scene.add(objLight);
scene.add(objLight.target);
const helper = new THREE.SpotLightHelper(objLight);
helper.name = 'helper';
scene.add(helper);
window.addEventListener('resize', () => {
renderer.setSize(window.innerWidth, window.innerHeight);
camera.aspect = window.innerWidth/window.innerHeight;
camera.updateProjectionMatrix();
})
}
function animate() {
objLightPos += 0.01;
objLightAngle += 0.03;
requestAnimationFrame(animate);
objLight.position.set(Math.sin(objLightPos), 3, 0);
objLight.angle = Math.sin(objLightAngle) * 0.5 + 0.5;
scene.getObjectByName('helper').update();
renderer.render(scene, camera);
}
init();
animate();
body { margin: 0; }
canvas { width: 100vw; height: 100vh; display: block; }
<script src="https://threejs.org/build/three.js"></script>
<script src="https://cdn.jsdelivr.net/npm/three@0.123/examples/js/controls/OrbitControls.js"></script>