ThreeJS - 创建表面透明的立方体而不是立方体体积
我使用以下代码来创建这个 3D 透明立方体。
// Create the cube itself
const cubeGeom = new THREE.BoxGeometry( 1, 1, 1 );
const material = new THREE.MeshBasicMaterial( {color: 0x00ff00, opacity:0.4, transparent:true});
const cube = new THREE.Mesh( cubeGeom, material );
// Also add a wireframe to the cube to better see the depth
const _wireframe = new THREE.EdgesGeometry( cubeGeom ); // or WireframeGeometry( geometry )
const wireframe = new THREE.LineSegments( _wireframe);
// Rotate it a little for a better vantage point
cube.rotation.set(0.2, -0.2, -0.1)
wireframe.rotation.set(0.2, -0.2, -0.1)
// add to scene
scene.add( cube )
scene.add( wireframe );
正如所见,立方体显示为透明的单个体积。相反,我想创建一个具有 6 个透明面的空心立方体。想象一个由 6 个透明且彩色的窗玻璃制成的立方体。请参阅此示例:对于 6 个面中的每一个,我想要的结果都是示例 1,但现在它就像示例 2。
更新 我尝试创建单独的“窗格”。然而,这种行为并不像我预期的那样。
我像这样创建单独的窗格:
geometry = new THREE.PlaneGeometry( 1, 1 );
material = new THREE.MeshBasicMaterial( {color: 0x00ff00, side: THREE.DoubleSide, transparent:true, opacity:0.2});
planeX = new THREE.Mesh( geometry, material);
planeY = new THREE.Mesh( geometry, material);
planeZ = new THREE.Mesh( geometry, material);
然后将所有三个平面添加到线框。
然后我稍微旋转它们,使它们以不同的方向相交。
const RAD_TO_DEG = Math.PI * 2 / 360;
planeX.rotation.y = RAD_TO_DEG * 90
planeY.rotation.x = RAD_TO_DEG * 90
现在我可以看到将窗格“堆叠”在彼此之上的效果,但它并不是应有的样子。
相反,我会期待这样的基于真实物理的东西(用糟糕的绘画技巧制作)。也就是说,颜色取决于重叠窗格的数量。
编辑
当透明窗格从观看方向重叠时,透明度似乎可以完美发挥作用。然而,当玻璃相交时,它就会破裂。
在这里,我复制了@Anye提供的片段并添加了 one.rotation.y = Math.PI * 0.5
并注释掉了 two.position.set(0.5, 0.5, 0.5);< /code> 使窗格相交。
var scene = new THREE.Scene();
var camera = new THREE.PerspectiveCamera( 75, window.innerWidth/window.innerHeight, 0.1, 1000 );
var renderer = new THREE.WebGLRenderer();
renderer.setSize( window.innerWidth, window.innerHeight );
document.body.appendChild( renderer.domElement );
var cube = new THREE.Group();
one = new Pane();
two = new Pane();
one.rotation.y = Math.PI * 0.5
one.position.z = 0.2;
// two.position.set(0.5, 0.5, 0.5);
cube.add(one);
cube.add(two);
cube.rotation.set(Math.PI / 4, Math.PI / 4, Math.PI / 4);
scene.add(cube);
function Pane() {
let geometry = new THREE.PlaneGeometry(1, 1);
let material = new THREE.MeshBasicMaterial({color:0x00ff00, transparent: true, opacity: 0.4});
let mesh = new THREE.Mesh(geometry, material);
return mesh;
}
camera.position.z = 2;
var animate = function () {
requestAnimationFrame( animate );
renderer.render(scene, camera);
};
animate();
body {
margin: 0;
overflow: hidden;
}
canvas {
width: 640px;
height: 360px;
}
<html>
<head>
<title>Demo</title>
</head>
<body>
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/87/three.min.js"></script>
</body>
</html>
编辑
剪下来的看起来相当不错;它清楚地显示了窗格重叠处的不同颜色。然而,它并没有到处显示这一点。请参阅此图片。左边是代码片段生成的内容,右边是它应有的样子。只有交叉点前面的重叠部分显示变色,而交叉点后面的部分应该显示变色,但不会显示变色。
I am using the following code to create this 3D transparent cube.
// Create the cube itself
const cubeGeom = new THREE.BoxGeometry( 1, 1, 1 );
const material = new THREE.MeshBasicMaterial( {color: 0x00ff00, opacity:0.4, transparent:true});
const cube = new THREE.Mesh( cubeGeom, material );
// Also add a wireframe to the cube to better see the depth
const _wireframe = new THREE.EdgesGeometry( cubeGeom ); // or WireframeGeometry( geometry )
const wireframe = new THREE.LineSegments( _wireframe);
// Rotate it a little for a better vantage point
cube.rotation.set(0.2, -0.2, -0.1)
wireframe.rotation.set(0.2, -0.2, -0.1)
// add to scene
scene.add( cube )
scene.add( wireframe );
As can been seen, the cube appears as a single volume that is transparent. Instead, I would want to create a hollow cube with 6 transparent faces. Think of a cube made out of 6 transparent and colored window-panes. See this example: my desired result would be example 1 for each of the 6 faces, but now it is like example 2.
Update
I tried to create individual 'window panes'. However the behavior is not as I would expect.
I create individual panes like so:
geometry = new THREE.PlaneGeometry( 1, 1 );
material = new THREE.MeshBasicMaterial( {color: 0x00ff00, side: THREE.DoubleSide, transparent:true, opacity:0.2});
planeX = new THREE.Mesh( geometry, material);
planeY = new THREE.Mesh( geometry, material);
planeZ = new THREE.Mesh( geometry, material);
And then I add all three planes to wireframe
.
Then I rotate them a little, so they intersect at different orientations.
const RAD_TO_DEG = Math.PI * 2 / 360;
planeX.rotation.y = RAD_TO_DEG * 90
planeY.rotation.x = RAD_TO_DEG * 90
Now I can see the effect of 'stacking' the panes on top of each other, however it is not as it should be.
I would instead expect something like this based on real physics (made with terrible paint-skills). That is, the color depends on the number of overlapping panes.
EDIT
When transparent panes overlap from the viewing direciton, transparancy appears to work perfectly. However, when the panes intersect it breaks.
Here I have copied the snipped provided by @Anye and added one.rotation.y = Math.PI * 0.5
and commented out two.position.set(0.5, 0.5, 0.5);
so that the panes intersect.
var scene = new THREE.Scene();
var camera = new THREE.PerspectiveCamera( 75, window.innerWidth/window.innerHeight, 0.1, 1000 );
var renderer = new THREE.WebGLRenderer();
renderer.setSize( window.innerWidth, window.innerHeight );
document.body.appendChild( renderer.domElement );
var cube = new THREE.Group();
one = new Pane();
two = new Pane();
one.rotation.y = Math.PI * 0.5
one.position.z = 0.2;
// two.position.set(0.5, 0.5, 0.5);
cube.add(one);
cube.add(two);
cube.rotation.set(Math.PI / 4, Math.PI / 4, Math.PI / 4);
scene.add(cube);
function Pane() {
let geometry = new THREE.PlaneGeometry(1, 1);
let material = new THREE.MeshBasicMaterial({color:0x00ff00, transparent: true, opacity: 0.4});
let mesh = new THREE.Mesh(geometry, material);
return mesh;
}
camera.position.z = 2;
var animate = function () {
requestAnimationFrame( animate );
renderer.render(scene, camera);
};
animate();
body {
margin: 0;
overflow: hidden;
}
canvas {
width: 640px;
height: 360px;
}
<html>
<head>
<title>Demo</title>
</head>
<body>
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/87/three.min.js"></script>
</body>
</html>
EDIT
The snipped looks pretty good; it clearly shows a different color where the panes overlap. However, it does not show this everywhere. See this image. The left is what the snippet generates, the right is what it should look like. Only the portion of overlap that is in front of the intersection shows the discoloration, while the section behind the intersection should, but does not show discoloration.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
您可能想看看CSG,构造实体几何。使用 CSG,您可以使用布尔值在原始立方体中创建一个洞。首先,您可以查看 这个快速教程。以下是您可以使用 CSG 执行哪些操作的一些示例。
=>
不过,CSG 有一些限制,因为它不是专门为 Three.js 制作的。一种廉价的替代方案是创建六个单独的半透明窗格,并将它们格式化以创建一个立方体。然后你可以将它们分组:
更新
你的代码可能有问题,这就是为什么它没有为你相应地着色。请参阅这个最小的示例,它显示了窗格如何根据重叠适当地着色。
更新 2
我更新了代码片段,因此 2 个窗格根本没有接触...我仍然能够看到阴影。也许您想尝试重现这个例子?
更新 3
下面是我在您的代码片段中看到的屏幕截图...似乎工作正常...
You might want to take a look at CSG, Constructive Solid Geometry. With CSG, you can create a hole in your original cube using a boolean. To start, you could take a look at this quick tutorial. Below are some examples of what you can do with CSG.
=>
CSG, though, has some limitations, since it isn't made specifically for three.js. A cheap alternative would be to create six individual translucent panes, and format them to create a cube. Then you could group them:
Update
Something may be wrong with your code, which is why it isn't shading accordingly for you. See this minimal example, which shows how the panes shade appropriately based on overlaps.
Update 2
I updated the snippet so the 2 panes aren't touching at all... I am still able to see the shading. Maybe if you were to try to reproduce this example?
Update 3
Below is a screenshot of what I see in your snippet... Seems to be working fine...
你正在经历我第一个令人头疼的事情:
ShaderMaterial 透明度
正如该问题的答案所示, Three.js 透明度系统执行依赖于顺序的透明度。通常,它将采用最接近相机的物体(通过网格位置),但由于所有平面都以同一点为中心,因此没有赢家,因此您会得到一些奇怪的透明效果。
如果您将平面网格移出以形成盒子的实际侧面,那么您应该会看到您正在寻找的效果。但这不会是奇怪的透明效果的结束,您需要实现自己的 Order - 独立透明度(或找到一个可以为您完成此操作的扩展库)以实现更物理精确的透明度效果。
You're experiencing one of my first head-scratchers:
ShaderMaterial transparency
As the answer to that question states, the three.js transparency system performs order-dependent transparency. Normally, it will take whichever object is closest to the camera (by mesh position), but because all of your planes are centered at the same point, there is no winner, so you get some strange transparency effects.
If you move the plane meshes out to form the actual sides of the box, then you should see the effect you're looking for. But that won't be the end of strange transparency effects, And you would need to implement your own Order-Independent Transparency (or find an extension library that does it for you) to achieve more physically-accurate transparency effects.