为什么 three.js 投射阴影不适用于 3D 模型
why is three.js cast shadow not working on a 3D model
我有这样的 3D 模型:
我想添加类似这样的投射阴影:
我有以下一段代码负责模型:
var ambLight = new THREE.AmbientLight( 0x404040 );
this.scene.add(ambLight)
var loader = new THREE.GLTFLoader();
loader.load(path,function (gltf) {
gltf.scene.traverse( function( model ) {
if (model.isMesh){
model.castShadow = true;
}
});
this.scene.add(gltf.scene);
}
我添加了这个 Whosebug 中看到的 castSHadow
部分。
我试过 model.castShadow = true
并且我试过删除 if
条件并只保留 castShadow
但这也不起作用。我错过了一步吗?如果有帮助,完整的自定义层代码是 here。
- 您的场景中只有一个
AmbientLight
实例,它没有投射阴影的光。
- 只有将
Object3D.receiveShadow
设置为 true
且 material 未点亮时,3D 对象才能接收到阴影。意思是 MeshBasicMaterial
不能作为地面的 material.
- 您必须通过以下方式全局启用阴影:
renderer.shadowMap.enabled = true;
我建议你仔细看看这个official example的阴影设置。
根据您的代码,您正在尝试在 Mapbox 顶部添加阴影。
为此,除了@Mugen87 的建议外,您还需要创建一个表面来接收阴影,并将其放置在您正在加载的模型正下方,同时还要考虑您要加载的对象的大小重新加载以避免阴影超出平面......然后你会得到这个。
相关代码在this fiddle I have created。我稍微改变了灯光,为了清晰起见我添加了一个灯光助手。
var customLayer = {
id: '3d-model',
type: 'custom',
renderingMode: '3d',
onAdd: function(map, gl) {
this.camera = new THREE.Camera();
this.scene = new THREE.Scene();
const dirLight = new THREE.DirectionalLight(0xffffff, 1);
dirLight.position.set(0, 70, 100);
let d = 1000;
let r = 2;
let mapSize = 8192;
dirLight.castShadow = true;
dirLight.shadow.radius = r;
dirLight.shadow.mapSize.width = mapSize;
dirLight.shadow.mapSize.height = mapSize;
dirLight.shadow.camera.top = dirLight.shadow.camera.right = d;
dirLight.shadow.camera.bottom = dirLight.shadow.camera.left = -d;
dirLight.shadow.camera.near = 1;
dirLight.shadow.camera.far = 400000000;
//dirLight.shadow.camera.visible = true;
this.scene.add(dirLight);
this.scene.add(new THREE.DirectionalLightHelper(dirLight, 10));
// use the three.js GLTF loader to add the 3D model to the three.js scene
var loader = new THREE.GLTFLoader();
loader.load(
'https://docs.mapbox.com/mapbox-gl-js/assets/34M_17/34M_17.gltf',
function(gltf) {
gltf.scene.traverse(function(model) {
if (model.isMesh) {
model.castShadow = true;
}
});
this.scene.add(gltf.scene);
// we add the shadow plane automatically
const s = new THREE.Box3().setFromObject(gltf.scene).getSize(new THREE.Vector3(0, 0, 0));
const sizes = [s.x, s.y, s.z];
const planeSize = Math.max(...sizes) * 10;
const planeGeo = new THREE.PlaneBufferGeometry(planeSize, planeSize);
const planeMat = new THREE.ShadowMaterial();
planeMat.opacity = 0.5;
let plane = new THREE.Mesh(planeGeo, planeMat);
plane.rotateX(-Math.PI / 2);
plane.receiveShadow = true;
this.scene.add(plane);
}.bind(this)
);
this.map = map;
// use the Mapbox GL JS map canvas for three.js
this.renderer = new THREE.WebGLRenderer({
canvas: map.getCanvas(),
context: gl,
antialias: true
});
this.renderer.autoClear = false;
this.renderer.shadowMap.enabled = true;
},
render: function(gl, matrix) {
var rotationX = new THREE.Matrix4().makeRotationAxis(
new THREE.Vector3(1, 0, 0),
modelTransform.rotateX
);
var rotationY = new THREE.Matrix4().makeRotationAxis(
new THREE.Vector3(0, 1, 0),
modelTransform.rotateY
);
var rotationZ = new THREE.Matrix4().makeRotationAxis(
new THREE.Vector3(0, 0, 1),
modelTransform.rotateZ
);
var m = new THREE.Matrix4().fromArray(matrix);
var l = new THREE.Matrix4()
.makeTranslation(
modelTransform.translateX,
modelTransform.translateY,
modelTransform.translateZ
)
.scale(
new THREE.Vector3(
modelTransform.scale,
-modelTransform.scale,
modelTransform.scale
)
)
.multiply(rotationX)
.multiply(rotationY)
.multiply(rotationZ);
this.camera.projectionMatrix = m.multiply(l);
this.renderer.state.reset();
this.renderer.render(this.scene, this.camera);
this.map.triggerRepaint();
}
};
我有这样的 3D 模型:
我想添加类似这样的投射阴影:
我有以下一段代码负责模型:
var ambLight = new THREE.AmbientLight( 0x404040 );
this.scene.add(ambLight)
var loader = new THREE.GLTFLoader();
loader.load(path,function (gltf) {
gltf.scene.traverse( function( model ) {
if (model.isMesh){
model.castShadow = true;
}
});
this.scene.add(gltf.scene);
}
我添加了这个 Whosebug castSHadow
部分。
我试过 model.castShadow = true
并且我试过删除 if
条件并只保留 castShadow
但这也不起作用。我错过了一步吗?如果有帮助,完整的自定义层代码是 here。
- 您的场景中只有一个
AmbientLight
实例,它没有投射阴影的光。 - 只有将
Object3D.receiveShadow
设置为true
且 material 未点亮时,3D 对象才能接收到阴影。意思是MeshBasicMaterial
不能作为地面的 material. - 您必须通过以下方式全局启用阴影:
renderer.shadowMap.enabled = true;
我建议你仔细看看这个official example的阴影设置。
根据您的代码,您正在尝试在 Mapbox 顶部添加阴影。
为此,除了@Mugen87 的建议外,您还需要创建一个表面来接收阴影,并将其放置在您正在加载的模型正下方,同时还要考虑您要加载的对象的大小重新加载以避免阴影超出平面......然后你会得到这个。
相关代码在this fiddle I have created。我稍微改变了灯光,为了清晰起见我添加了一个灯光助手。
var customLayer = {
id: '3d-model',
type: 'custom',
renderingMode: '3d',
onAdd: function(map, gl) {
this.camera = new THREE.Camera();
this.scene = new THREE.Scene();
const dirLight = new THREE.DirectionalLight(0xffffff, 1);
dirLight.position.set(0, 70, 100);
let d = 1000;
let r = 2;
let mapSize = 8192;
dirLight.castShadow = true;
dirLight.shadow.radius = r;
dirLight.shadow.mapSize.width = mapSize;
dirLight.shadow.mapSize.height = mapSize;
dirLight.shadow.camera.top = dirLight.shadow.camera.right = d;
dirLight.shadow.camera.bottom = dirLight.shadow.camera.left = -d;
dirLight.shadow.camera.near = 1;
dirLight.shadow.camera.far = 400000000;
//dirLight.shadow.camera.visible = true;
this.scene.add(dirLight);
this.scene.add(new THREE.DirectionalLightHelper(dirLight, 10));
// use the three.js GLTF loader to add the 3D model to the three.js scene
var loader = new THREE.GLTFLoader();
loader.load(
'https://docs.mapbox.com/mapbox-gl-js/assets/34M_17/34M_17.gltf',
function(gltf) {
gltf.scene.traverse(function(model) {
if (model.isMesh) {
model.castShadow = true;
}
});
this.scene.add(gltf.scene);
// we add the shadow plane automatically
const s = new THREE.Box3().setFromObject(gltf.scene).getSize(new THREE.Vector3(0, 0, 0));
const sizes = [s.x, s.y, s.z];
const planeSize = Math.max(...sizes) * 10;
const planeGeo = new THREE.PlaneBufferGeometry(planeSize, planeSize);
const planeMat = new THREE.ShadowMaterial();
planeMat.opacity = 0.5;
let plane = new THREE.Mesh(planeGeo, planeMat);
plane.rotateX(-Math.PI / 2);
plane.receiveShadow = true;
this.scene.add(plane);
}.bind(this)
);
this.map = map;
// use the Mapbox GL JS map canvas for three.js
this.renderer = new THREE.WebGLRenderer({
canvas: map.getCanvas(),
context: gl,
antialias: true
});
this.renderer.autoClear = false;
this.renderer.shadowMap.enabled = true;
},
render: function(gl, matrix) {
var rotationX = new THREE.Matrix4().makeRotationAxis(
new THREE.Vector3(1, 0, 0),
modelTransform.rotateX
);
var rotationY = new THREE.Matrix4().makeRotationAxis(
new THREE.Vector3(0, 1, 0),
modelTransform.rotateY
);
var rotationZ = new THREE.Matrix4().makeRotationAxis(
new THREE.Vector3(0, 0, 1),
modelTransform.rotateZ
);
var m = new THREE.Matrix4().fromArray(matrix);
var l = new THREE.Matrix4()
.makeTranslation(
modelTransform.translateX,
modelTransform.translateY,
modelTransform.translateZ
)
.scale(
new THREE.Vector3(
modelTransform.scale,
-modelTransform.scale,
modelTransform.scale
)
)
.multiply(rotationX)
.multiply(rotationY)
.multiply(rotationZ);
this.camera.projectionMatrix = m.multiply(l);
this.renderer.state.reset();
this.renderer.render(this.scene, this.camera);
this.map.triggerRepaint();
}
};