1

我正在开发一个three.js 应用程序,我必须在其中创建一个建筑结构(全部位于底层),高度、宽度、长度将由用户指定。用户可以更改墙壁和屋顶的颜色(使用纹理应用,因为我有每种颜色的图像和一些纹理)。他们还可以在选定的墙壁(如窗户或门)上添加任何配件,然后可以将其拖放到同一选定的墙壁上。在决定了他们想要放置窗口的位置(例如)之后,他们将单击一个按钮来确认位置。现在我必须在墙上创建一个窗口,以便我可以看到房间的内部。请提出您对以下方法的看法:

一旦用户确认了门的位置——

a.) 我可以在主建筑网格中添加窗户的网格mainMesh.add(windowMesh);。但问题是即使我将透明材质设置为窗口,墙壁材质仍然显示。

b.) 我可以从主建筑网格中减去窗网格(使用 CSG,threeCSG)buildingmeshcsg.subtract(windowmeshcsg),这会在建筑网格中创建一个孔,然后我将窗网格放在那个孔上。现在的问题是在任何 CSG 操作之后,原始几何体的面都混在一起了,所以在 csg 操作之后,面的颜色和 UV 消失了。

c.)我可以在小部分中创建墙, 分段墙 例如从一个角落到窗户角落,然后从另一个窗户角落到另一个墙角。但这会弄乱我在墙壁上应用的纹理,因为我已经为前后墙壁创建了 UV,因为纹理没有正确应用。

请提出您的看法。

必须做这样的事情:https ://forum.unity.com/threads/make-a-seethrough-window-without-making-hole-in-the-wall.286393/

4

1 回答 1

1

三 *(任何版本)

这听起来像是模板缓冲区的一个很好的候选者。绘制窗口并写入模板,在写入值 (0) 周围绘制墙,然后在写入值 (1) 内绘制墙。

这些是您感兴趣的方法:

https://developer.mozilla.org/en-US/docs/Web/API/WebGLRenderingContext/stencilOp https://developer.mozilla.org/en-US/docs/Web/API/WebGLRenderingContext/stencilFunc

您需要先执行此操作:

const gl = renderer.getContext() //obtain the actual webgl context, because three has no stencil functionality

然后你需要管理你的渲染逻辑,这就是Object3D.onBeforeRender回调应该帮助的地方。

所以让我们假设你有这样的东西:

const myWindow, myWall //two meshes, you loaded them, instantiated them

//for a proof of concept you can do something like this

const maskScene = new THREE.Scene()
const wallScene = new THREE.Scene()
const windowScene = new THREE.Scene()

maskScene.add(myWindow)
wallScene.add(myWall)
windowScene.add(myWindow)

render(){
  gl.enable(gl.STENCIL_TEST) //enable stencil testing

  gl.clearStencil( 0 ) //set stencil clear value

  gl.clear( _gl.STENCIL_BUFFER_BIT ) //clear the stencil buffer with set value

  gl.stencilFunc( gl.ALWAYS, 1, 1) //always pass the stencil test, with ref 1


  gl.stencilOp( gl.REPLACE , gl.REPLACE , gl.REPLACE ) //replace the stencil value with the ref 

  gl.colorMask(false, false, false, false) //do not write any color 
  gl.depthMask(false) //do not write to depth

  myRenderer.render(maskScene, myCamera) //only the stencil is drawn


  //now you have a region in the frame buffer with stencil value of 1, and the rest 0, you can draw the wall in 0 and the window back at 1

  gl.colorMask(true, true, true, true) //enable writing
  gl.depthMask(true)

  gl.stencilFunc( gl.EQUAL , 0 , 1 )  //set the stencil function to EQUAL
  gl.stencilOp( gl.KEEP, gl.KEEP, gl.KEEP ) //keep the stencil value in all three tests

  myRenderer.render( wallScene, myCamera ) //draw the wall where stencil is 0 (around the window)


  gl.stencilFunc( gl.EQUAL , 1 , 1 ) // now func is EQUAL but to value 1

  myRenderer.render( windowScene, myCamera ) //draw the window

}

这是最基本的尝试,没有经过测试。由于它直接与 WebGL API 一起工作,它应该与三个版本的任何版本一起工作。stencilOp需要另外两个参数,您可以使用它们来管理深度测试发生的情况。

于 2017-10-06T16:40:56.390 回答