gpt4 book ai didi

javascript - three.js 中有许多带阴影的灯导致片段着色器错误

转载 作者:行者123 更新时间:2023-11-29 11:03:40 25 4
gpt4 key购买 nike

假设有一个场景,街道上有许多路灯(超过 20 个),您将一个物体移近它们,您期望有一个阴影。

灯光,简单

var light = new THREE.PointLight(0xffffff, 0.5, 6.0);

只有街道有.receiveShadow = true,只有汽车有.castShadow = true(除了后面的灯)

example

在 three.js 中,向所有灯添加 .castShadow = true 会导致以下错误

THREE.WebGLProgram: shader error:  0 gl.VALIDATE_STATUS false 
gl.getProgramInfoLog Fragment shader sampler count exceeds MAX_TEXTURE_IMAGE_UNITS (16).

幸运的是,在小时场景中,我们只需要几个(最多 4 个)来转换阴影,因为大多数灯无论如何都够不着。

我尝试使用两种方法

  1. 循环遍历所有灯光并动态设置 .castShadow = true.castShadow = false

  2. 完全添加和移除灯光,但将它们设置为没有阴影或有阴影。

对于他们两个,我都得到了同样的错误。

还有什么其他方法可行?

更新

@neeh 为它创建了一个 Fiddle here (导致错误更改 var numLightRows = 8; 到一个更大的数字)。不过请注意错误,如果灯太多,还会出现另一个错误,这不是由同一问题引起的

他还指出我们看到here pointShadowMap 即使在不使用时也会被创建。这解释了为什么“更聪明”的方法没有改变。这现在在 GLSL 代码中。

所以我们受到 GPU 的限制,在我的例子中它有 16 个 IMAGE_UNITS 但并非所有 GPU 都是这种情况(我的 CPU 实际上可以很好地处理更多)。您可以使用 renderer.capabilities.maxTextures 检查您的系统。但如前所述,我们实际上只需要 4 个。

问题依旧。

最佳答案

问题

一个new shadow map will be created对于具有 castShadow = true 的每个灯 (实际上,情况并非如此,检查 this issue )。阴影贴图是在其上计算阴影以便随后在表面上混合的绘制。

gl.getProgramInfoLog Fragment shader sampler count exceeds MAX_TEXTURE_IMAGE_UNITS (16).

这意味着您的设备可以每次绘制调用发送不超过 16 个纹理。通常,您要在其上放置阴影的汽车(街道?)是 1 个绘制调用。

要绘制接收阴影的对象,所有阴影贴图都应与漫反射贴图混合。因此,这需要为一次绘制调用使用 N+1 个纹理单元。 (N 是可以转换阴影的灯的数量。)

如果你深入研究 Three.js 着色器,你会发现 this :

#ifdef USE_SHADOWMAP

#if NUM_DIR_LIGHTS > 0

// Reserving NUM_DIR_LIGHTS texture units
uniform sampler2D directionalShadowMap[ NUM_DIR_LIGHTS ];
varying vec4 vDirectionalShadowCoord[ NUM_DIR_LIGHTS ];

#endif

...

#endif

检查 this tool查看您的浏览器可以处理多少纹理单元(片段着色器> 最大纹理图像单元)。


解决方案?

动态创建和删除灯光是不好的,因为它会占用大量内存(阴影贴图的分配...)。

但是,作为gaitat据说,您可以仅对最近的灯光启用阴影。只需在渲染循环中执行以下操作:

  1. 禁用所有阴影:light.castShadow = false;
  2. 寻找最近的灯光
  3. N 个最近的灯启用阴影:light.castShadow = true;

改进

这个算法很糟糕,因为它为每个光分配一个阴影贴图。除了消耗内存外,每次穿过未分配阴影贴图的新光源时,渲染都会卡住一点...

因此,我们的想法是为最近的灯光重用相同的阴影贴图。您可以像这样处理阴影贴图:

// create a new shadow map
var shadowMapCamera = new THREE.PerspectiveCamera(90, 1, 0.5, 500);
var shadow = new THREE.LightShadow(shadowMapCamera);

// use the shadow map on a light
light.shadow = shadow;
shadow.camera.position.copy(light.position);
light.castShadow = true;

您可以使用 renderer.capabilities.maxTextures 获得纹理单元的最大数量。因此,您可以根据它计算要创建的阴影贴图的数量,但请记住为更规则的贴图(如 diffuseMap、normalMap...)保留一些。

enter image description here

查看 this fiddle完整实现(仅使用 4 个阴影贴图)。

关于javascript - three.js 中有许多带阴影的灯导致片段着色器错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42877678/

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