透明度
|
该页面正在翻译中。 |
using CairoMakie
using FileIO
# color
fig, ax, p = image(0..11, -1..11, rotr90(FileIO.load(Makie.assetpath("cow.png"))))
scatter!(ax, 1:10,fill(10, 10), markersize = 40, color = :red)
scatter!(ax, 1:10, fill(9, 10), markersize = 40, color = (:red, 0.5))
scatter!(ax, 1:10, fill(8, 10), markersize = 40, color = RGBf(0.8, 0.6, 0.1))
scatter!(ax, 1:10, fill(7, 10), markersize = 40, color = RGBAf(0.8, 0.6, 0.1, 0.5))
# colormap
scatter!(ax, 1:10, fill(5, 10), markersize = 40, color = 1:10, colormap = :viridis)
scatter!(ax, 1:10, fill(4, 10), markersize = 40, color = 1:10, colormap = (:viridis, 0.5),)
scatter!(ax, 1:10, fill(3, 10), markersize = 40, color = 1:10, colormap = [:red, :orange],)
scatter!(ax, 1:10, fill(2, 10), markersize = 40, color = 1:10, colormap = [(:red, 0.5), (:orange, 0.5)])
cm = [RGBf(x^2, 1 - x^2, 0.2) for x in range(0, 1, length=100)]
scatter!(ax, 1:10, fill(1, 10), markersize = 40, color = 1:10, colormap = cm)
cm = [RGBAf(x^2, 1 - x^2, 0.2, 0.5) for x in range(0, 1, length=100)]
scatter!(ax, 1:10, fill(0, 10), markersize = 40, color = 1:10, colormap = cm)
fig
透明度问题
从两个重叠的透明对象生成的颜色取决于它们的顺序。 例如,考虑具有相同透明度的红色和蓝色标记。 如果蓝色标记在前面,我们期望在它们重叠的地方有更多的蓝色。 如果红色的在前面,我们期望更多的红色。 </无翻译>
using CairoMakie
scene = Scene(size = (400, 275))
campixel!(scene)
scatter!(
scene, [100, 200, 300], [100, 100, 100],
color = [RGBAf(1,0,0,0.5), RGBAf(0,0,1,0.5), RGBAf(1,0,0,0.5)],
markersize=200
)
scatter!(scene, Point2f(150, 175), color = (:green, 0.5), markersize=200)
p = scatter!(scene, Point2f(250, 175), color = (:green, 0.5), markersize=200)
translate!(p, 0, 0, -1)
scene
上图在透明度方面遵循三个规则:
-
如果两个图处于不同的z水平,则具有较高水平的图将位于较低z水平的前面。 (右边的绿色圆圈在所有其他地块的后面。)
-
同一z级绘图的绘制顺序与其创建顺序相匹配。 (红色和蓝色圆圈在左绿色圆圈后面。)
-
绘图元素按顺序绘制。 (左边的红圈在中间的蓝圈后面,在右边的红圈后面。)
第一条规则遵循图的显式排序。 它只能在2D中完成,因为绘图可以在3D中具有可变的深度。第二和第三条规则适用于这两种情况。 然而,它们会经常在3D中生成错误的结果。例如,两个平面旋转以具有不同的深度值: </无翻译>
using CairoMakie
fig = Figure()
ax = LScene(fig[1, 1], show_axis=false)
p1 = mesh!(ax, Rect2f(-1.5, -1, 3, 3), color = (:red, 0.5), shading = NoShading)
p2 = mesh!(ax, Rect2f(-1.5, -2, 3, 3), color = (:blue, 0.5), shading = NoShading)
rotate!(p1, Vec3f(0, 1, 0), 0.1)
rotate!(p2, Vec3f(0, 1, 0), -0.1)
fig
using GLMakie
fig = Figure()
ax = LScene(fig[1, 1], show_axis=false)
p1 = mesh!(ax, Rect2f(-1.5, -1, 3, 3), color = (:red, 0.5), shading = NoShading)
p2 = mesh!(ax, Rect2f(-1.5, -2, 3, 3), color = (:blue, 0.5), shading = NoShading)
rotate!(p1, Vec3f(0, 1, 0), 0.1)
rotate!(p2, Vec3f(0, 1, 0), -0.1)
fig
两个后端处理这个错误。 CairoMakie似乎忽略了深度,只是按照绘图顺序绘制平面。 这并不完全正确-CairoMakie确实在每个情节上考虑深度,在某些情况下在每个元素的基础上考虑深度(例如3d网格中的三角形)。 但它不能处理每像素级别的深度。
另一方面,GLMakie可以处理每像素级别的深度,如上所示的正确顺序所示。 这里透明度的问题是,应用于像素的颜色顺序不是先验已知的。 GLMakie将首先绘制红色平面,并记录每个像素的深度值。 然后它会绘制蓝色平面,如果它在另一个前面。 准确解决这个问题需要收集每个像素的颜色和深度值,对它们进行排序,然后按顺序混合它们。 这将是非常昂贵的,因此很少做。
订单独立透明度
GLMakie实现了混合透明颜色的近似方案-https://jcgt.org/published/0002/02/09/[订单独立透明度](OIT)。 而不是使用通常的顺序依赖混合 alpha*color+(1-alpha)*background_color 它使用基于深度和alpha的权重的加权和。 您可以通过设置打开OIT 透明度=真 对于给定的情节。
</无翻译>
using GLMakie
fig = Figure()
ax = LScene(fig[1, 1], show_axis=false)
p1 = mesh!(ax, Rect2f(-2, -2, 4, 4), color = (:red, 0.5), shading = NoShading, transparency = true)
p2 = mesh!(ax, Rect2f(-2, -2, 4, 4), color = (:blue, 0.5), shading = NoShading, transparency = true)
p3 = mesh!(ax, Rect2f(-2, -2, 4, 4), color = (:red, 0.5), shading = NoShading, transparency = true)
for (dz, p) in zip((-1, 0, 1), (p1, p2, p3))
translate!(p, 0, 0, dz)
end
fig
作为一个近似的方案,OIT有一些优点和缺点。 OIT有两个显着的缺点:
-
混合总是发生-即使完全不透明的颜色(alpha=1)应该隐藏另一个。
-
混合不是尖锐的-当具有相同alpha值的两种颜色以相似的深度值混合时,它们的输出颜色将相似。
using GLMakie
fig = Figure(size = (800, 400))
ax1 = LScene(fig[1, 1], show_axis=false)
p1 = mesh!(ax1, Rect2f(-2, -2, 4, 4), color = :red, shading = NoShading, transparency = true)
p2 = mesh!(ax1, Rect2f(-2, -2, 4, 4), color = :blue, shading = NoShading, transparency = true)
p3 = mesh!(ax1, Rect2f(-2, -2, 4, 4), color = :red, shading = NoShading, transparency = true)
for (dz, p) in zip((-1, 0, 1), (p1, p2, p3))
translate!(p, 0, 0, dz)
end
ax2 = LScene(fig[1, 2], show_axis=false)
p1 = mesh!(ax2, Rect2f(-1.5, -1, 3, 3), color = (:red, 0.5), shading = NoShading, transparency=true)
p2 = mesh!(ax2, Rect2f(-1.5, -2, 3, 3), color = (:blue, 0.5), shading = NoShading, transparency=true)
rotate!(p1, Vec3f(0, 1, 0), 0.1)
rotate!(p2, Vec3f(0, 1, 0), -0.1)
fig
请注意,您可以混合不透明 透明度=错误 具有透明OIT图的图没有问题。 因此,第一个问题并不是真正不透明的地块的问题,而是接近不透明的地块。
你可能遇到的另一个问题是你的情节的一部分变成黑色或白色。 这是在OIT计算期间浮点数变为无限的结果,因为在相机附近添加了大量透明颜色。 你可以用两种方式解决这个问题:
-
移动
附近裁剪平面更接近相机。 对于一个ax::LScene这可以通过调整来完成斧头场景。camera_controls.近[]接近0和调用update_cam!(斧头。场景,斧头。场景。camera_controls). -
减少开支
格玛基。透明_weight_scale[]其控制赋予透明颜色的最大权重。 默认值为1000f0.
调整后者也可能有助于清晰度。