Three.js - 在着色器材质上应用简单纹理

3
使用WebGL渲染器和Three.js(67)时,我似乎无法使具有着色器材质的平面穿上它的纹理。无论我怎么做,材质看起来都是黑色的。
目前我的代码非常基本:
var grassT = new Three.Texture(grass); // grass is an already loaded image.
grassT.wrapS = grassT.wrapT = Three.ClampToEdgeWrapping;
grassT.flipY = false;
grassT.minFilter = Three.NearestFilter;
grassT.magFilter = Three.NearestFilter;
grassT.needsUpdate = true;

var terrainUniforms = {
  grassTexture : { type: "t", value: grassT},
}

然后我只需在vertexShader中添加这个相关部分:

vUv = uv;

在 fragmentShader 方面:
gl_FragColor = texture2D(grassTexture, vUv);

这将导致:
  • 黑色材料。
  • 控制台没有错误。
  • gl_FragColor的值始终为(0.0, 0.0, 0.0, 1.0)。
我尝试/检查过的内容:
  • 如果只应用自定义纯色,一切都正常。
  • 如果我也使用vertexColors和纯色,一切都正常。
  • 我的纹理宽度/高度确实是2的幂次方。
  • 图像与代码在同一台服务器上。
  • 测试了其他结果相同的图像。
  • 图像实际上在浏览器调试器中加载。
  • 网格的UVS是正确的。
  • 调整wrapT、wrapS、minFilter、magFilter。
  • 调整网格大小,使纹理具有1:1比例。
  • 使用requirejs图像插件预加载图像,并从THREE.Texture()创建纹理,而不是使用THREE.ImageUtils();
  • 尝试添加needsUpdate : true;
  • 在材质实例化期间尝试添加defines['USE_MAP']。
  • 尝试添加material.dynamic = true。
  • 我有一个正确的渲染循环(与地形的交互正在工作)。
我仍然想知道:
  • 这是使用express + socket.io使用自定义端口的多人游戏。我是否受到任何Webgl安全策略的影响?
  • 我目前没有灯光逻辑,这是问题吗?
  • 也许着色器材质需要其他“defines”在实例化时?
我想我可能忽略了一些更简单的东西,这就是为什么我在问...谢谢。

没有全部代码有点难以调试 - 但我肯定建议在场景中添加一个AmbientLight来检查模型是否真的有纹理。我发现你经常会发现一个纹理渲染(例如草)并且看起来正确,只是意识到你做错了,它正在忽略照明。 :) - FunnyLookinHat
非常感谢您的建议。我已经打开了灯光,但情况并没有改善。不过,我通过深入渲染器代码来取得了一些进展。我发现由于某种原因,texture.needsUpdate属性被设置为false!如果我删除26278行-setTexture函数-处的条件检查,则可以呈现纹理。 - Julien Garcia
因此,新的问题是:纹理的needsUpdate属性在哪里和为什么会从true更改为false。 - Julien Garcia
2个回答

2
我正在同一个着色器上应用各种效果。我有一个自定义API,通过使用Three.UniformsUtils.merge()将所有不同的效果uniform简单合并。但是,这个函数会调用纹理上的clone()方法,这会导致在纹理到达渲染器之前重置needsUpdatefalse
看起来你应该在达到材质级别时将纹理的needsUpdate属性设置为true。在纹理级别上,如果您设置的uniform被后面的过程合并并因此被克隆,它将失去其needsUpdate属性。
这个问题也在这里详细说明:https://github.com/mrdoob/three.js/issues/3393 在我的情况下,以下内容没有起作用(grassT是我的纹理):
grassT.needsUpdate = true

而以下代码在后面运行得非常完美:

material.uniforms.grassTexture.value.needsUpdate = true;

1

图像加载是异步的。很可能在纹理图像加载之前,您正在渲染场景。

必须在图像加载后将texture.needsUpdate标志设置为truethree.js有一个实用程序可以为您完成此操作:

var texture = THREE.ImageUtils.loadTexture( "texture.jpg" );

一旦渲染完毕,渲染器会将texture.needsUpdate标志设置为false
three.js r.68

谢谢您。我尝试了同样的方法,但结果相同。实际上,当代码运行时,图像已经加载。问题来自其他地方:我正在同一个着色器上应用各种效果。我有一个自定义API,通过使用:Three.UniformsUtils.merge() 来合并所有不同的效果uniforms。然而,这个函数调用纹理的clone()方法,这会导致在纹理到达渲染器之前将needsUpdate重置为false!! - Julien Garcia
当到达材质级别时,似乎应将纹理的needsUpdate属性设置为true,因为在纹理级别上,如果您设置的uniform稍后在过程中合并(因此克隆),它将失去其needsUpdate属性!在我的情况下,这是不起作用的(grassT是我的纹理):grassT.needsUpdate = true而以下代码完美运行:material.uniforms.grassTexture.value.needsUpdate = true; - Julien Garcia
嘿,WestLangley!毕竟这对你来说非常熟悉:我刚刚遇到了这个问题:https://github.com/mrdoob/three.js/issues/3393 - Julien Garcia
请在您的原始帖子中提供回答您问题所需的所有信息。 - WestLangley
我一定会的。我需要等待额外的3个小时,因为我的声望太低了。少于10分的情况下,我们只能在8个小时后回复自己。 - Julien Garcia

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接