You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何为Poly3DCollection按顶点标量场线性渐变设置面颜色

问题概述

我有一个由四边形单元组成的网格,网格单元的节点上定义有标量场。我当前使用Poly3DCollection绘制该网格,希望根据标量场值为单元着色。但目前我只能对构成每个3D多边形的顶点标量值取平均来设置面颜色,找不到实现面颜色随各顶点标量值平滑线性渐变的方法。已有同类多边形渐变填充方案仅适用于2D路径与多边形,无法适配3D场景。

复现代码

下方是可复现当前场景的最小可运行示例(MWE)。如代码所示,当前设置3D多边形面颜色时,需要先对四个顶点定义的标量场取平均值,目标是实现面颜色根据顶点处的标量场值平滑渐变。

import matplotlib as mpl
import matplotlib.pyplot as plt
import numpy as np
from mpl_toolkits.mplot3d.art3d import Poly3DCollection

# 创建画布与3D坐标轴
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
# 定义单元顶点坐标
vertices = [np.array([[.25, 0., 0.], [.75, 0., 0.], [.75, .3, .5], [.25, .3, .5]]),
            np.array([[.25, .3, .5], [.75, .3, .5], [.75, .6, .5], [.25, .6, .5]]),
            np.array([[.25, .6, .5], [.75, .6, .5], [.75, .9, 1.], [.25, .9, 1.]])]
# 生成顶点上的随机标量场
scalar = np.random.rand(3, 4)
# 保证重合顶点的标量值一致
scalar[1, 0:2] = scalar[0, 2:]
scalar[2, 0:2] = scalar[1, 2:]
# 对面内顶点标量取平均
averaged_scalar = np.mean(scalar, axis=1)
# 创建3D多边形集合
pc = Poly3DCollection(vertices, linewidths=.1)
# 初始化色图映射
m = mpl.cm.ScalarMappable(cmap=mpl.cm.jet)
m.set_array(scalar)
m.set_clim(vmin=np.amin(averaged_scalar), vmax=np.amax(averaged_scalar))
rgba_array = m.to_rgba(averaged_scalar)
pc.set_facecolor([(i[0], i[1], i[2]) for i in rgba_array])
# 设置边颜色
pc.set_edgecolor('k')
# 将多边形添加到坐标轴
ax.add_collection3d(pc)
# 展示图像
plt.show()

当前平均着色效果示例图

解决方案

Poly3DCollection原生仅支持统一设置单个面的颜色,不支持面内逐顶点颜色插值,无法直接实现渐变效果。要实现3D网格面内随顶点标量值线性平滑渐变的着色效果,可换用Matplotlib自带的plot_trisurf接口:该接口支持传入逐顶点标量值,自动在三角单元内完成线性颜色插值,只需将原有四边形单元拆分为两个三角单元、保证共享顶点的坐标与标量值完全一致,即可得到无断层的平滑渐变着色效果。

修改后的可运行代码如下:

import matplotlib as mpl
import matplotlib.pyplot as plt
import numpy as np

# 创建画布与3D轴
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')

# 去重后的所有网格顶点坐标
unique_verts = np.array([
    [.25, 0., 0.],   # 顶点0
    [.75, 0., 0.],   # 顶点1
    [.75, .3, .5],   # 顶点2
    [.25, .3, .5],   # 顶点3
    [.75, .6, .5],   # 顶点4
    [.25, .6, .5],   # 顶点5
    [.75, .9, 1.],   # 顶点6
    [.25, .9, 1.]    # 顶点7
])

# 四边形拆分后的三角面顶点索引(每个四边形拆为2个三角形)
tri_faces = np.array([
    [0, 1, 2], [0, 2, 3],   # 第一个四边形
    [3, 2, 4], [3, 4, 5],   # 第二个四边形
    [5, 4, 6], [5, 6, 7]    # 第三个四边形
])

# 逐顶点标量场,保证共享顶点值一致
np.random.seed(42) # 固定随机种子方便复现
vert_scalar = np.zeros(len(unique_verts))
vert_scalar[0:4] = np.random.rand(4)
vert_scalar[4:6] = np.random.rand(2)
vert_scalar[6:8] = np.random.rand(2)

# 绘制三角网格,自动插值逐顶点颜色
surf = ax.plot_trisurf(
    unique_verts[:,0], unique_verts[:,1], unique_verts[:,2],
    triangles=tri_faces,
    array=vert_scalar,
    cmap=mpl.cm.jet,
    edgecolor='k',
    linewidth=0.1,
    antialiased=True
)

# 添加色条方便对照数值
fig.colorbar(surf, ax=ax, shrink=0.7)

plt.show()

渲染后的效果不存在按面平均导致的色块边界,颜色会沿网格表面随标量场值连续平滑变化。

内容的提问来源于stack exchange,提问作者fma

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.26 09:45:37