Three.js/webgl RayCasting Sprites 在具有透明度或替代方案的场景中

Posted

技术标签:

【中文标题】Three.js/webgl RayCasting Sprites 在具有透明度或替代方案的场景中【英文标题】:Three.js/webgl RayCasting Sprites in Scene with Transparency or Alternatives 【发布时间】:2020-08-24 18:23:14 【问题描述】:

我正在开发一个需要选择绘制对象的网页游戏,而不是简单的几何形状。为此,我一直在使用 Three.JS 在画布上的场景中将它们绘制为精灵。几个月来,我一直在绞尽脑汁想弄清楚如何确定我的 webgl 上下文(使用 ThreeJS)中的光线投射器的光线是否与精灵的透明部分发生碰撞。我已经搜索并阅读了尽可能多的帖子,但我只找到了两个解决方案帖子:

var ctx =renderer.getContext("experimental-webgl", preserveDrawingBuffer: true)
const pixel = new Uint8Array(4)
ctx.readPixels(10,30,1,1, ctx.RGBA,  ctx.UNSIGNED_BYTE,  pixel); log(pixel);

这需要使用preserveDrawingBuffer,这会破坏我的表现,或者:

raycaster.intersectObject(scene.getObjectByName('some sprite')[0]].uv

然后使用数学魔法将UV坐标与图像本身进行比较,我猜想从scene.getObjectByName('some sprite').material.map.image.src.valueOf()的某个地方加载到缓冲区中,然后如果匹配的像素或模糊区域是透明的,那么我们不考虑选中的精灵.这将更加困难,因为精灵经常被旋转、缩放、中心偏移等。我什至不能 100% 确定我将如何实现它。

我想知道是否还有其他方法,尤其是更“正确”的方法。有什么方法可以将精灵图像转换为/提供我的图像与某种网格,然后用图像精确地绘制网格,这样光线追踪器实际上必须使用正确的对象形状而不仅仅是图像平面(精灵)?在 3D 建模程序中获取每个精灵并精心建模其边缘会更好吗?我尝试了“网格”、“几何”、“图像”、“精灵”等的所有组合,但没有找到解决方案。

感谢任何帮助。乞丐不能成为选择者,但我也希望最终能有动画对象,所以如果这个解决方案不是不可能实现的,那将是另外的帮助。

谢谢

e:见下面@gman 的评论。我在颜色选择系统中工作,只是将 emissive.setHex 更改为 material.color.set(id),然后检查颜色而不是自发光。效果很好,但似乎有点放慢了速度。将不得不看看我是否实施得不好,或者我是否可以提高效率。谢谢你们!!

【问题讨论】:

我不清楚您要做什么,但this article 中的技术可能会有所帮助。 @gman 我正在尝试您的两种解决方案,因为两者都很相似,但我至少需要一天的时间来实施,今天已经花了 3 个小时。我会在星期一之前更新这个结果。注意:我从你的开始,基本上重写我的精灵创建/渲染函数需要一些时间,因为它们都是动态填充的。 就我所做的而言,它与文章几乎相同,只是用精灵替换随机绘制的立方体,这些精灵根据画布接收的内容进行绘制、定位和缩放服务器。希望我等到我尝试实施这两种方法后再选择正确的方法是可以接受的,这样我就可以用解决方案更新我的帖子。 我无法实施您的解决方案。在pickhelper函数上返回的id始终为零,使用console.log,它似乎没有在拾取场景中找到对象,我检查并确保它在那里。 为我工作jsfiddle.net/greggman/74jtp2fb 【参考方案1】:

通过额外的绘制通道,您可以将场景渲染为纹理,并为每个对象使用专用材质,并在其中选取 2D 点

您可以创建一个基本材质,其颜色与this OpenGL hack 中所述的每个对象的 ID 匹配(将其转换为 WebGL)

使用Scene.overrideMaterial为所有对象分配材质,Object3D.onBeforeRender在绘制每个对象之前设置它们的颜色

这需要花费,但我认为值得一试

【讨论】:

我正在尝试您的两种解决方案,因为两者都很相似,但我至少需要一天的时间来实施,今天已经花了 3 个小时。我会在星期一之前更新这个结果。注意:我从 gman 的解决方案开始,我很抱歉。 我猜基于 raycaster 的拾取解决方案将实现更轻、运行更快、更容易使用 alpha。从它开始绝对是个好主意 对不起,@YGilk1,我不明白你的解决方案。对象已经有了颜色,我不能只在要渲染的实际场景中为它们分配平面颜色。因此,如果我希望它们在另一个场景中呈现,这与其他评论的解决方案大致相同,我无法开始工作。如果我有误解,我深表歉意。 所有对象都在一些专用的绘制通道中渲染到具有通用基本材质的纹理(渲染目标)中。渲染对象时,您可以根据文章中的说明根据对象的 UID 设置材质颜色。用户单击视口后,您将获得单击下的 2D 视口坐标并将该点拾取到纹理中。如果用户点击一个对象,你会得到一个匹配对象 UID 的 R,G,B 在这种情况下,我认为您的答案与 gman 的答案几乎完全相同,因为 gman 实际上并未使用光线投射器,而是将每个场景元素重新制作到另一个场景中。我认为这个答案是正确的,主要是因为我认为我不太了解“专用绘图通道”是什么,但如果它能够在不创建第二个场景的情况下与其他解决方案做同样的事情,它可能是在性能方面更好的答案。我会继续研究这个,看看能不能按照你说的实现。

以上是关于Three.js/webgl RayCasting Sprites 在具有透明度或替代方案的场景中的主要内容,如果未能解决你的问题,请参考以下文章

Three.js / WebGL - 透明平面隐藏在它们后面的其他平面

WebGL初探—Three.js全景图实战

解决 three.js / webGL 中的 gl_PointSize 限制

戳HTML5+Three.js+WebGL实现立方体

深入理解Three.js(WebGL)贴图(纹理映射)和UV映射

深入理解Three.js(WebGL)贴图(纹理映射)和UV映射