构造型实体几何体(CSG)是一种可以组合原始对象以创建更复杂的对象的手段或者说方式,在上一篇介绍黄金链就已经用到了CSG方法。
回到上一篇 POV-RAY基础教程 - 基本SDL(2)
什么是CSG?
POV-Ray的CSG(Constructive Solid Geometry)允许我们通过以四种不同的方式组合原始形状来构造复杂的实体。它们是:
- 使用
union
声明,将两个或多个形状合并在一起; - 使用
intersection
声明,将两个或多个形状组合在一起以形成由两个形状共有的区域组成新形状; - 使用
difference
声明,初始的形状具有从中减去所有后续的形状; - 使用
merge
声明,它就像一个联合体,其中联合体内的表面被移除(在透明CSG对象中很有用)。
我们接下来细讨论这些细节
CSG Union
让我们试着做一个简单的联合。创建一个名为的文件 csgdemo.pov
并按如下方式编辑它:
#include "colors.inc"
camera {
location <0, 1, -10>
look_at 0
angle 36
}
light_source { <500, 500, -1000> White }
plane { y, -1.5
pigment { checker Green White }
}
让我们添加两个球体,每个球体沿x轴在每个方向上平移0.5个单位。我们将一个蓝色和另一个红色染色。
sphere { <0, 0, 0>, 1
pigment { Blue }
translate -0.5*x
}
sphere { <0, 0, 0>, 1
pigment { Red }
translate 0.5*x
}
我们跟踪此文件并记下结果。现在我们在两个球体周围放置一个联合块。这将从两个对象中创建单个CSG联合。
union{
sphere { <0, 0, 0>, 1
pigment { Blue }
translate -0.5*x
}
sphere { <0, 0, 0>, 1
pigment { Red }
translate 0.5*x
}
}
我们再次追踪文件。联合将看起来与每个球体本身的外观没有什么不同,但现在我们可以给整个联合提供单个纹理并将其整体转换。我们现在就这样做。
union{
sphere { <0, 0, 0>, 1
translate -0.5*x
}
sphere { <0, 0, 0>, 1
translate 0.5*x
}
pigment { Red }
scale <1, .25, 1>
rotate <30, 0, 45>
}
我们再次追踪文件。我们可以看到,该对象发生了巨大变化。我们尝试不同的比例值并旋转并尝试一些不同的纹理。
将一个纹理分配给CSG对象而不是将纹理分配给每个单独的组件有许多优点。首先,如果我们的CSG对象具有大量组件,则使用一个纹理要容易得多,因为更改对象外观只涉及更改一个单一纹理。其次,文件解析得更快,因为纹理只需要解析一次。在进行大型场景或动画时,这可能是一个很重要的因素。第三,仅使用一个纹理可以节省内存,因为纹理只存储一次并由CSG对象的所有组件引用。将纹理分配给所有n个组件意味着它被存储n次。
CSG intersection
顾名思义,取物体的交集,现在让我们使用这些相同的球体来说明intersection
声明的CSG对象。我们将单词更改union
为intersection
并删除scale
和rotate
语句:
intersection {
sphere { <0, 0, 0>, 1
translate -0.5*x
}
sphere { <0, 0, 0>, 1
translate 0.5*x
}
pigment { Red }
}
图片
我们追踪文件并将看到一个镜头形状的物体而不是两个球体。这是因为交叉点由两个形状共享的区域组成,在这种情况下是两个球体重叠的透镜形区域。我们喜欢这个镜片形物体,所以我们将用它来展示差异。
CSG Difference
我们围绕y轴旋转镜头形状的交叉点,使得宽边朝向相机。
intersection{
sphere { <0, 0, 0>, 1
translate -0.5*x
}
sphere { <0, 0, 0>, 1
translate 0.5*x
}
pigment { Red }
rotate 90*y
}
让我们创建一个圆柱体并将其粘在镜头中间。
cylinder { <0, 0, -1> <0, 0, 1>, .35
pigment { Blue }
}
我们渲染场景以查看圆柱体的位置。我们将围绕镜头形状的交叉点和圆柱体放置一个difference块,如下所示:
difference {
intersection {
sphere { <0, 0, 0>, 1
translate -0.5*x
}
sphere { <0, 0, 0>, 1
translate 0.5*x
}
pigment { Red }
rotate 90*y
}
cylinder { <0, 0, -1> <0, 0, 1>, .35
pigment { Blue }
}
}
渲染的图形如下:
我们再次渲染文件,看到镜头形状的交叉点,在它的中间有一个整齐的洞。圆筒已经从交叉区域subtracted。注意,圆柱体的颜料使孔的表面着蓝色。如果我们消除这种颜料,孔的表面将是黑色的,因为如果没有指定颜色,这是默认颜色。好吧,让我们现在变得有点狂野。让我们宣布我们的穿孔镜片对象给它一个名字。让我们也消除声明对象中的所有纹理,因为我们希望它们在最终的联合中。
#declare Lens_With_Hole = difference {
intersection {
sphere { <0, 0, 0>, 1
translate -0.5*x
}
sphere { <0, 0, 0>, 1
translate 0.5*x
}
rotate 90*y
}
cylinder { <0, 0, -1> <0, 0, 1>, .35 }
}
让我们使用一个联合来构建一个由这个对象的副本组成的复杂形状。
union {
object { Lens_With_Hole translate <-.65, .65, 0> }
object { Lens_With_Hole translate <.65, .65, 0> }
object { Lens_With_Hole translate <-.65, -.65, 0> }
object { Lens_With_Hole translate <.65, -.65, 0> }
pigment { Red }
}
让我们通过在颜料块中添加一些过滤器使其成为部分透明的物体。
union {
object { Lens_With_Hole translate <-.65, .65, 0> }
object { Lens_With_Hole translate <.65, .65, 0> }
object { Lens_With_Hole translate <-.65, -.65, 0> }
object { Lens_With_Hole translate <.65, -.65, 0> }
pigment { Red filter .6 }
}
图片如下
可以看到,透过红色部分可以看到地面纹路,说明有一定的透明度
CSG Merge
这将我们带到第四种CSG对象,即merge
。合并与联合相同,但不跟踪合并内的CSG中对象的几何。这应该消除我们的对象的问题。我们来试试吧。
merge {
object { Lens_With_Hole translate <-.65, .65, 0> }
object { Lens_With_Hole translate <.65, .65, 0> }
object { Lens_With_Hole translate <-.65, -.65, 0> }
object { Lens_With_Hole translate <.65, -.65, 0> }
pigment { Red filter .6 }
}
图片如下
果然,确实如此!
CSG问题
我们必须注意CSG代码中存在严重缺陷。POV-Ray使用内部/外部测试来确定光线与CSG对象相交的点。当两个不同形状的表面重合时会出现问题,因为没有办法(由于计算机的浮点精度)来判断重合表面上的点是属于一种形状还是另一种形状。请看下面的示例,其中使用圆柱体在较大的盒子中切割孔。
difference {
box { -1, 1 pigment { Red } }
cylinder { -z, z, 0.5 pigment { Green } }
}
注意:框定义中的向量-1和1分别扩展为<-1,-1,-1>;和<1,1,1>。
图片如下
从图片中,我们可以看到,在两个物体相交的表面,产生了红绿斑点,这是因为,坐标相同的两个相交表面,POV-Ray不知道具体渲染哪一个,可能一会渲染这个,一会渲染那个,就会产生这种现象。
既然,是因为坐标完全一样,导致的这种问题,如果想解决这种问题,我们只需将其移动一点位置就可以了
difference {
box { -1, 1 pigment { Red } }
cylinder { -1.001*z, 1.001*z, 0.5 pigment { Green } }
}
图片如下
继续阅读下一篇 POV-RAY基础教程 - 光源(4)