`UniformsSetter.setColor` sends every color to the shader as black
维护者通常 1 天内回复
评估
这个 Issue 还没有评估数据。
描述
What happened?
UniformsSetter.setColor (and therefore setColors) sends every color to the shader as black. It divides each channel by 255 (fragment_shader.dart#L91-L93):
setFloat(color.r / 255 * multiplier);
setFloat(color.g / 255 * multiplier);
setFloat(color.b / 255 * multiplier);
setFloat(color.a);
Color.r, Color.g and Color.b are already doubles between 0 and 1, so the shader receives values between 0 and about 0.004. For example, Colors.red arrives as vec4(0.0037, 0.0010, 0.0008, 1.0) instead of vec4(0.957, 0.263, 0.212, 1.0). Alpha isn't divided, so the result is an opaque black and not a transparent color. With premultiply: true the channels are also multiplied by alpha, but they are still divided by 255 first.
The code was added in #3578, which copied the extension from flutter_shaders. There it uses color.red / 255, which is correct because the deprecated Color.red getter is an int between 0 and 255. While copying, .red/.green/.blue/.opacity were replaced with .r/.g/.b/.a, but the / 255 was kept. Nothing in the repository calls setColor, and it has no tests, so this went unnoticed. The basic shader tutorial passes its color with setVector(color.toVector4()), which is why it isn't affected.
The bug is in the released versions, including flame-v1.38.2 and flame-v2.0.0-dev.1.
What do you expect?
setColor sends the channels of the color unchanged, so setColor(Colors.red) sets the uniform to vec4(0.957, 0.263, 0.212, 1.0), as the dartdoc of setFloatUniforms describes. With premultiply: true, the red, green and blue channels are multiplied by alpha.
How can we reproduce this?
- Create a fragment shader that outputs a
uniform vec4 uColor. - Set that uniform with
shader.setFloatUniforms((u) => u.setColor(Colors.red)). - Draw a rect with
Paint()..shader = shader. - The rect is black. Setting the same uniform with
u.setFloats([color.r, color.g, color.b, color.a])draws it red.
The example below renders the same shader twice for each color: the left column uses setColor and the right column uses setFloats.
What steps should take to fix this?
Remove the / 255 from the three channels in setColor:
setFloat(color.r * multiplier);
setFloat(color.g * multiplier);
setFloat(color.b * multiplier);
setFloat(color.a);
With that change, both columns in the example below are identical.
Do have an example of where the bug occurs?
shaders/swatch.frag:
#version 460 core
uniform vec4 uColor;
out vec4 fragColor;
void main() {
fragColor = vec4(uColor.rgb * uColor.a, uColor.a);
}
pubspec.yaml:
flutter:
shaders:
- shaders/swatch.frag
lib/main.dart:
import 'dart:ui';
import 'package:flame/components.dart';
import 'package:flame/extensions.dart';
import 'package:flame/game.dart';
import 'package:flutter/material.dart' hide Image;
void main() {
runApp(GameWidget(game: SetColorBugGame()));
}
/// Renders the same shader twice per color: the left column uses
/// `setColor`, the right column passes the channels with `setFloats`.
class SetColorBugGame extends FlameGame {
static const colors = <(String, Color)>[
('Colors.red', Colors.red),
('Colors.purpleAccent', Colors.purpleAccent),
('Colors.amber', Colors.amber),
('Colors.white', Colors.white),
];
@override
Color backgroundColor() => const Color(0xFF2B3340);
@override
Future<void> onLoad() async {
final program = await FragmentProgram.fromAsset('shaders/swatch.frag');
final header = TextPaint(
style: const TextStyle(fontSize: 20, color: Colors.white),
);
final label = TextPaint(
style: const TextStyle(fontSize: 14, color: Color(0xFFB8C2D0)),
);
const swatch = 110.0;
const colX = [220.0, 420.0];
const top = 70.0;
add(TextComponent(text: 'setColor(color)', textRenderer: header)
..position = Vector2(colX[0] + swatch / 2, 24)
..anchor = Anchor.topCenter);
add(TextComponent(text: 'setFloats([r, g, b, a])', textRenderer: header)
..position = Vector2(colX[1] + swatch / 2, 24)
..anchor = Anchor.topCenter);
for (var i = 0; i < colors.length; i++) {
final (name, color) = colors[i];
final y = top + i * (swatch + 16);
add(TextComponent(text: name, textRenderer: label)
..position = Vector2(colX[0] - 16, y + swatch / 2)
..anchor = Anchor.centerRight);
add(ShaderSwatch(program, color, useSetColor: true)
..position = Vector2(colX[0], y)
..size = Vector2.all(swatch));
add(ShaderSwatch(program, color, useSetColor: false)
..position = Vector2(colX[1], y)
..size = Vector2.all(swatch));
}
}
}
class ShaderSwatch extends PositionComponent {
ShaderSwatch(FragmentProgram program, this.color, {required this.useSetColor})
: shader = program.fragmentShader();
final FragmentShader shader;
final Color color;
final bool useSetColor;
late final Paint _paint = Paint()..shader = shader;
@override
void render(Canvas canvas) {
shader.setFloatUniforms((u) {
if (useSetColor) {
u.setColor(color);
} else {
u.setFloats([color.r, color.g, color.b, color.a]);
}
});
canvas.drawRect(size.toRect(), _paint);
}
}
Relevant log output
# Nothing is logged or thrown, the colors are only rendered as black.
Execute in a terminal and put output into the code block below
[✓] Flutter (Channel stable, 3.47.9, on Linux Mint 22.3 7.0.0-42-generic, locale en_IN)
• Flutter version 3.47.9 on channel stable
• Framework revision c197ca5199 (7 days ago), 2026-10-29 10:10:20 -0400
• Engine revision 89c39edfdf
• Dart version 3.13.7
• DevTools version 2.60.0
[✗] Chrome - develop for the web (Cannot find Chrome executable at google-chrome)
! Cannot find Chrome. Try setting CHROME_EXECUTABLE to a Chrome executable.
[✓] Linux toolchain - develop for Linux desktop
• Ubuntu clang version 18.1.3 (1ubuntu1)
• cmake version 3.28.3
• ninja version 1.11.1
• pkg-config version 1.8.1
• OpenGL core renderer: Mesa Intel(R) HD Graphics 4000 (IVB GT2) (X11)
• OpenGL ES renderer: Mesa Intel(R) HD Graphics 4000 (IVB GT2) (X11)
[✓] Connected device (1 available)
[✓] Network resources
! Doctor found issues in 1 category.
Affected platforms
All
Other information
The bug is in Dart code that runs before anything reaches the GPU, so it doesn't depend on the platform or renderer. The screenshots are from Linux with Impeller (OpenGLES).
Are you interested in working on a PR for this?
- I want to work on this
- 主要语言
- Dart
- 星标
- 10.8k
- 派生
- 1.1k
- 平均合并
- 1 天 19 小时
- 30 天内合并 PR
- 54
环境准备
- 没有 Dockerfile 或 Docker Compose 文件
- 有 Pull Request 模板
- 阅读贡献指南
从这里开始
- 先读完整个 Issue,再读项目的贡献指南。
- 在 Issue 下留言说明你要接手 —— 这能避免两个人做同样的事。
- Fork 仓库,在一个分支上完成修改。
- 提交 Pull Request,并在描述里引用这个 Issue 编号。
flame-engine/flame 的其他 Issue
-
难度 1/5 1-3 小时 新手友好度 91/100
flame-engine/flame#4219 ·
维护者通常 1 天内回复
-
Add support to share the polygons of a Path among PathComponent and PathHitbox可能已有人在做 @adario 于 1 天前认领。 未关闭enhancement
难度 4/5 1-2 天 新手友好度 15/100
flame-engine/flame#4217 ·
维护者通常 1 天内回复
-
`Viewfinder.visibleGameSize` is not reapplied when the viewport changes size可能已有人在做 @ufrshubham 于 6 天前认领。 未关闭bug
flame-engine/flame#4204 · 已指派 1 人 ·
维护者通常 1 天内回复
-
`Viewfinder.visibleGameSize` zooms in too far with a `FixedResolutionViewport`可能已有人在做 @ufrshubham 于 6 天前认领。 未关闭bug
flame-engine/flame#4203 · 已指派 1 人 ·
维护者通常 1 天内回复
-
Camera bounds with `considerViewport: true` are not updated when the viewport is resized可能已有人在做 @ufrshubham 于 6 天前认领。 未关闭bug
flame-engine/flame#4202 · 已指派 1 人 ·
维护者通常 1 天内回复
查看 flame-engine/flame 的全部 Issue
相似的 Issue
-
type:feature
难度 2/5 1-3 小时 新手友好度 65/100
维护者通常 2 天内回复
-
难度 1/5 1-3 小时 新手友好度 60/100
维护者通常 1 天内回复
-
bug
难度 2/5 1-3 小时 新手友好度 65/100
TomBursch/kitchenowl#1211 ·
维护者通常 2 天内回复
-
难度 2/5 1-3 小时 新手友好度 75/100
ccch1mneyyy/dsh-Go#767 ·
维护者通常 1 天内回复
-
android bug need_attention
难度 2/5 1-3 小时 新手友好度 79/100
hiddify/hiddify-app#2472 · 1 条评论 ·
维护者通常 1 天内回复