gpt4 book ai didi

three.js - 如何在 Three.js 中操纵阴影而不编辑底层网格?

转载 作者:行者123 更新时间:2023-12-02 19:10:53 27 4
gpt4 key购买 nike

我正在开发一个应用程序,该应用程序应该允许用户操纵场景中的 3D 对象并观察它们的更改如何影响地面阴影:

enter image description here

在此场景中,黄色圆柱体在白色平面上转换阴影,圆柱体的中间包含在绿色立方体中。我希望发生的是让立方体去除阴影的中间,如下所示:

enter image description here

显然,我的第一个想法是从黄色圆柱体体积中减去绿色立方体体积,经过一番谷歌搜索后我发现了 CSG.js。不幸的是,CSG.js 对于我要使用的实际模型来说太慢了,该模型至少有 15k 个顶点。

我开始深入研究 Three.js 源代码并阅读有关阴影贴图的内容,以了解阴影是如何生成的,但我的着色器功能还不够强大,无法完全掌握如何调整阴影渲染。

如何实现这种“阴影减法”效果?

var camera, scene, renderer;

init();
animate();

function init() {
scene = new THREE.Scene();

camera = new THREE.PerspectiveCamera( 70, window.innerWidth / window.innerHeight, 1, 1000 );
camera.position.z = 500;
camera.position.y = 100;
camera.lookAt(scene.position);

var ambient = new THREE.AmbientLight(0x909090);
scene.add(ambient);

var directionalLight = new THREE.DirectionalLight( 0xffffff, 1.0 );
directionalLight.position.set( -300, 300, 0 );
directionalLight.castShadow = true;
directionalLight.shadow.camera.near = 10;
directionalLight.shadow.camera.far = 2000;
directionalLight.shadow.camera.right = 350;
directionalLight.shadow.camera.left = -350;
directionalLight.shadow.camera.top = 350;
directionalLight.shadow.camera.bottom = -350;
directionalLight.shadow.mapSize.width = 1024;
directionalLight.shadow.mapSize.height = 1024;
scene.add( directionalLight );

//var lightHelper = new THREE.CameraHelper(directionalLight.shadow.camera);
//scene.add(lightHelper);

var geometry = new THREE.CylinderGeometry( 50, 50, 400, 32 );
var material = new THREE.MeshPhongMaterial( {color: 0xffff00} );
var cylinder = new THREE.Mesh( geometry, material );
cylinder.castShadow = true;
scene.add( cylinder );

var geometry = new THREE.BoxGeometry( 110, 110, 110 );
var material = new THREE.MeshPhongMaterial( {color: 0x00ff00} );
var cube = new THREE.Mesh( geometry, material );
cube.castShadow = true;
scene.add( cube );

var geometry = new THREE.PlaneGeometry( 3000, 3000, 32 );
var material = new THREE.MeshPhongMaterial( {color: 0xffffff, side: THREE.DoubleSide} );
var plane = new THREE.Mesh( geometry, material );
plane.lookAt(new THREE.Vector3(0, 1, 0));
plane.position.y = -200;
plane.receiveShadow = true;
scene.add( plane );

renderer = new THREE.WebGLRenderer();
renderer.setPixelRatio( window.devicePixelRatio );
renderer.setSize( window.innerWidth, window.innerHeight );
renderer.shadowMap.enabled = true;
renderer.shadowMap.type = THREE.BasicShadowMap;
document.body.appendChild( renderer.domElement );

window.addEventListener( 'resize', onWindowResize, false );
}

function onWindowResize() {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();

renderer.setSize( window.innerWidth, window.innerHeight );
}

function animate() {
requestAnimationFrame( animate );

renderer.render( scene, camera );
}

jsFiddle

更新:

更复杂的场景怎么样?红色圆柱体的阴影是否可能不受影响(您可以看到它被 cube.customDepthMaterial = new THREE.MeshBasicMaterial({ heightTest: false}) 切成两半)?

enter image description here

Updated jsFiddle

最佳答案

您可以通过设置对象的 .customDepthMaterial 属性,从场景的其余部分中减去对象的阴影,如下所示:

var cube = new THREE.Mesh( geometry, material );
cube.castShadow = true;
cube.receiveShadow = false;

// The secret sauce
cube.customDepthMaterial =
new THREE.MeshBasicMaterial({ depthTest: false});

scene.add( cube );

jsFiddle

不需要着色器。

为什么有效
渲染阴影贴图时,每个对象的深度 Material (.customDepthMaterial 或默认值)为 used to render the scene from the light's perspective 。深度 Material 的渲染结果表示来自相机的对象深度(以 RGBA 形式封装)。由于 THREE.MeshBasicMaterial 默认为 { color: 0xffffff, opacity: 1 },因此它将返回使对象比阴影相机的 far< 更远的最大深度.

我禁用了深度测试,因为在您想要的结果屏幕截图中,您剪切了立方体指定的圆柱体不存在的区域。禁用 深度测试 意味着立方体被圆柱体阻挡的部分仍会切除阴影,从而提供您想要的结果。

文档
不幸的是,还没有关于 .customDepthMaterial 的文档,但我确实找到了 an official example在哪里使用它。

更新答案:
允许对象的阴影始终显示:

  1. 您可以使用与上面相同的技巧,只需将 Material 的颜色不透明度设置为0
  2. 确保将其添加到场景中“减法阴影”对象之后。这样,即使它们都禁用了 深度测试,附加阴影也会胜出。

updated jsFiddle

如果您有更复杂的事情,则需要您找出一种方法来管理阴影渲染的顺序。

在 r77 中测试

关于three.js - 如何在 Three.js 中操纵阴影而不编辑底层网格?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37311086/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com