我正在开发一款应用,应该允许用户操作场景中的3D对象并观察他们的变化如何影响地面阴影:
在这个场景中,黄色圆柱体在白色平面上投下阴影,圆柱体的中间包含在绿色立方体中。我想要发生的是立方体去除阴影的中间,如下所示:
显而易见,我的第一个想法是从黄色圆柱体中减去绿色立方体体积,经过一些谷歌搜索后我找到了CSG.js.不幸的是,CSG.js对于我将要使用的实际模型来说太慢了,这将至少有15k个顶点。
我开始深入研究Three.js源码并阅读阴影贴图以了解阴影是如何产生的,但是我的shader-fu还不够强大,无法完全掌握如何调整阴影渲染。
我怎样才能实现这个"阴影减法"实现
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 );
}
更新
更复杂的场景怎么样?红色圆柱体的阴影是否可以不受影响(你可以看到它被cube.customDepthMaterial = new THREE.MeshBasicMaterial({ depthTest: false})
切成两半)?
答案 0 :(得分:4)
您可以通过设置对象的.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 );
不需要着色器。
为什么会这样做
渲染阴影贴图时,每个对象的深度材质(.customDepthMaterial
或默认值)为used to render the scene from the light's perspective。深度材质的结果渲染表示物体的深度来自作为RGBA打包的相机。由于THREE.MeshBasicMaterial
默认为{ color: 0xffffff, opacity: 1 }
,因此它将返回使对象比阴影相机far
更远的最大深度。
我已停用depthTest
,因为在您想要的结果屏幕截图中,您剪切了给定圆柱体的多维数据集所在的区域。禁用depthTest
意味着被圆柱体阻挡的立方体部分仍将切除阴影,为您提供所需的结果。
<强>文档强>
很遗憾,.customDepthMaterial
还没有关于color
的文档,但我确实找到了使用它的an official example。
更新后的答案:
允许对象的阴影始终显示:
opacity
和0
设置为depthTest
如果你有更复杂的事情,那么你需要找到一种方法来管理阴影渲染的顺序。
在r77中测试