下载 App
10/133 浏览案例分享
【案例分享】改了八版都不对:nvgRadialGradient 的 inner/outer 参数根本不生效
一句话结论
本引擎的 nvgRadialGradient 会忽略你传进去的 inner / outer 参数,径向渐变的边界固定在引擎自己的默认值上(约 0.35 × min(W,H))。你改那两个参数,画面不会有任何变化——而且不会有任何报错。
现象
我想做「动量驱动的氛围灯」:中心干净、越往外越有色,半径随速度变大。
写法大致是:
local pt = nvgRadialGradient(vg, cx, cy, inner, outer,
nvgRGBA(255,200,90, 0), -- 中心:全透明
nvgRGBA(255,200,90,60)) -- 边缘:半透明
nvgFillPaint(vg, pt)
nvgFill(vg)
其中 inner = 0.70 * hd、outer = 1.00 * hd(hd = 半对角线,随动量变化)。
结果:不管怎么调,永远是一块「中心是背景色、外圈是实色」的硬边圆盘,半径看着像固定的,跟动量完全无关。前七版都在调那两个参数和颜色,全都没用。
怎么确认(关键是别靠眼睛)
用径向亮度剖面:从中心向外按半径采样,取每个半径环上像素亮度的中位数。
伪代码:
for r in range(0, 720, 20):
px = sample_circle(img, cx, cy, r) # 该半径环上的像素
print(r, median_brightness(px))
两张不同动量的截图,剖面完全重合:
半径 0 ~ 240 中位亮度 15 <- 恰好是背景色 nvgRGBA(11,15,26) 的亮度
半径 260 ~ 720 中位亮度 63/90 <- 氛围灯色
边界固定在半径约 250,而我代码里传的 inner 换算过去是 514。
250 约等于 0.35 × min(W,H) = 0.35 × 720 = 252 —— 这正是引擎自己的默认值。
=> 传进去的两个参数被丢掉了。
修法:手绘描边同心圆环
半径完全由代码控制:
local RINGS = 40
for i = 1, RINGS do
local t = i / RINGS -- 0 .. 1
local r = maxR * t
local a = math.floor(alpha_max * t * t) -- alpha 按半径平方递增
nvgBeginPath(vg)
nvgCircle(vg, cx, cy, r)
nvgStrokeWidth(vg, maxR / RINGS + 1) -- 注意:描边,不是填充
nvgStrokeColor(vg, nvgRGBA(r_, g_, b_, a))
nvgStroke(vg)
end
为什么必须用「描边环」而不是「填充同心圆」
填充圆会累加 alpha。N 个同心填充圆叠起来,中心点被覆盖 N 次 => 中心最亮,与「中心干净、边缘有色」正好相反。这个坑我第一版就踩了。
描边环每个半径只描一次,alpha 才是「你写多少就是多少」。
代价
40 个描边环在 1080p 下实测无感。想更省可以降到 20 环 + 加大 stroke width,但环数太少会出现可见色带(banding)。
可迁移的经验
看到「改了参数画面不动」,不要继续调参数——先验参数有没有被消费。
径向亮度剖面是最省事的验法:它把「我以为我改了」变成一条数轴上的读数。这个验法不只对渐变色有用,任何「按距离衰减」的效果(光照、雾、描边衰减)都可以用它来判「公式生效了没」。




