三.js SpotLight 急性光束不起作用

Posted

技术标签:

【中文标题】三.js SpotLight 急性光束不起作用【英文标题】:three.js SpotLight acute beam not working 【发布时间】:2021-03-21 10:07:06 【问题描述】:

我是 three.js 的新手,但我在 Unity 有过 3d 对象和渲染方面的经验, 我在使用 SpotLight 时遇到问题,我试图从一个进口的 obj 中发光,让它看起来像一盏工作灯。 我无法将灯光的角度设置为锐角,因为当它超过某个值时它就不会发光。

这是相关的代码:

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,我可以让它变得尖锐,直到 Math.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();

【问题讨论】:

【参考方案1】:

我认为这是因为您使用的是MeshLambertMaterial,它计算每个顶点的光照,而不是计算每个面部像素。当光线照射到顶点(广角)时,它会发光。但是当光线只照射到面并且不接触顶点(在更窄的角度上)时,平面就不会显示光线。此外,由于光的性质,在蓝色盒子上发出黄光不会显示任何内容:#ffff00 * #0000ff = #000000

尝试更改为MeshPhongMaterial,您会发现灯光和阴影的计算更加准确。运行下面的代码 sn-p 以查看它的实际效果。

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>

【讨论】:

正确。见***.com/questions/15801971/…。 就是这样!材料本身,现在它完美地工作了!感谢您的帮助和其他信息。

以上是关于三.js SpotLight 急性光束不起作用的主要内容,如果未能解决你的问题,请参考以下文章

js 中 onkeyup 不起作用

Js文件在Angular项目中导入时不起作用

MailChimp JS 验证不起作用

React.js:为啥删除按钮不起作用?

为啥 GET 请求在 Node.js 中不起作用?

Next.js - 导入 css 文件不起作用