drawDistortedImage method
void
drawDistortedImage(})
Warps a rendered offline Image onto the target canvas using the pre-computed distortion mesh.
Supports atwTransform matrix for Asynchronous Time Warp and enableChromaticAberration
for correcting lens chromatic dispersion via multi-pass RGB blend.
Implementation
void drawDistortedImage(
Canvas canvas,
Image image,
Size viewportSize, {
Matrix4? atwTransform,
bool enableChromaticAberration = false,
}) {
final w = viewportSize.width;
final h = viewportSize.height;
final imgW = image.width.toDouble();
final imgH = image.height.toDouble();
// Map distorted points [-1, 1] to output viewport coordinates [0, w/h]
final positions = distortedPoints.map((p) => _toScreen(p, w, h)).toList();
final shaderMatrix = atwTransform ?? Matrix4.identity();
final shader = ImageShader(
image,
TileMode.clamp,
TileMode.clamp,
Float64List.fromList(shaderMatrix.storage),
);
if (enableChromaticAberration) {
// Map Green (neutral), Red (expanded 1.008), and Blue (contracted 0.992) texture coords
final greenCoords = originalPoints.map((p) => _toScreen(p, imgW, imgH)).toList();
final redCoords = originalPoints.map((p) {
final shifted = Offset(p.dx * 1.008, p.dy * 1.008);
return _toScreen(shifted, imgW, imgH);
}).toList();
final blueCoords = originalPoints.map((p) {
final shifted = Offset(p.dx * 0.992, p.dy * 0.992);
return _toScreen(shifted, imgW, imgH);
}).toList();
// Draw Red channel
final redVertices = Vertices(
VertexMode.triangles,
positions,
textureCoordinates: redCoords,
indices: indices,
);
final redPaint = Paint()
..shader = shader
..colorFilter = const ColorFilter.matrix([
1, 0, 0, 0, 0,
0, 0, 0, 0, 0,
0, 0, 0, 0, 0,
0, 0, 0, 1, 0,
]);
canvas.drawVertices(redVertices, BlendMode.srcOver, redPaint);
// Draw Green channel (BlendMode.plus)
final greenVertices = Vertices(
VertexMode.triangles,
positions,
textureCoordinates: greenCoords,
indices: indices,
);
final greenPaint = Paint()
..shader = shader
..blendMode = BlendMode.plus
..colorFilter = const ColorFilter.matrix([
0, 0, 0, 0, 0,
0, 1, 0, 0, 0,
0, 0, 0, 0, 0,
0, 0, 0, 1, 0,
]);
canvas.drawVertices(greenVertices, BlendMode.srcOver, greenPaint);
// Draw Blue channel (BlendMode.plus)
final blueVertices = Vertices(
VertexMode.triangles,
positions,
textureCoordinates: blueCoords,
indices: indices,
);
final bluePaint = Paint()
..shader = shader
..blendMode = BlendMode.plus
..colorFilter = const ColorFilter.matrix([
0, 0, 0, 0, 0,
0, 0, 0, 0, 0,
0, 0, 1, 0, 0,
0, 0, 0, 1, 0,
]);
canvas.drawVertices(blueVertices, BlendMode.srcOver, bluePaint);
} else {
// Standard single-pass render without aberration correction
final textureCoords = originalPoints.map((p) => _toScreen(p, imgW, imgH)).toList();
final vertices = Vertices(
VertexMode.triangles,
positions,
textureCoordinates: textureCoords,
indices: indices,
);
canvas.drawVertices(
vertices,
BlendMode.srcOver,
Paint()..shader = shader,
);
}
}