runAt method
Vector4
runAt(
- int vertexIndex,
- int instanceIndex,
- Float32List a,
- ShaderBindings bindings,
- Float32List out,
override
The same as CpuVertexShader.run, plus the vertex's and the instance's own indices.
run must still work — a caller that has no indices, or a rasteriser that has not been taught to pass them, falls back to it — so an implementation answers both and shares whatever it can.
Implementation
@override
Vector4 runAt(
int vertexIndex,
int instanceIndex,
Float32List a,
ShaderBindings bindings,
Float32List out,
) {
final mvp = bindings.mat4('FrameInfo', 'mvp');
final model = bindings.mat4('FrameInfo', 'model');
final normalMatrix = bindings.mat4('FrameInfo', 'normal_matrix');
// The rows as the buffer holds them; `Matrix4` wants columns, so each
// argument below is one row's worth of a column.
final instance = Matrix4(
a[_row0],
a[_row1],
a[_row2],
0.0, // column 0
a[_row0 + 1],
a[_row1 + 1],
a[_row2 + 1],
0.0, // column 1
a[_row0 + 2],
a[_row1 + 2],
a[_row2 + 2],
0.0, // column 2
a[_row0 + 3],
a[_row1 + 3],
a[_row2 + 3],
1.0, // column 3
);
// Morphed in the mesh's own space, before the instance transform: every
// instance of a batch shares the mesh, which is what the GLSL says at the
// same point. What they need not share is the shape — the instance index
// goes in, and a batch that gives each copy its own weights is read a row
// at a time out of a second texture.
final morphed =
vertexIndex >= 0 &&
_morphScratch.load(
vertexIndex,
a,
bindings,
positionAt: kPosition,
normalAt: kNormal,
tangentAt: kTangent,
instanceIndex: instanceIndex,
);
final Vector4 local =
instance *
(morphed
? Vector4(
_morphScratch.position.x,
_morphScratch.position.y,
_morphScratch.position.z,
1.0,
)
: Vector4(a[kPosition], a[kPosition + 1], a[kPosition + 2], 1.0));
final Vector4 world = model * local;
out[kVWorld] = world.x;
out[kVWorld + 1] = world.y;
out[kVWorld + 2] = world.z;
final rotation = instance.getRotation();
final rotated = rotation.transformed(
morphed
? _morphScratch.normal
: Vector3(a[kNormal], a[kNormal + 1], a[kNormal + 2]),
)..normalize();
final n = normalMatrix.getRotation().transformed(rotated);
out[kVNormal] = n.x;
out[kVNormal + 1] = n.y;
out[kVNormal + 2] = n.z;
out[kVUv] = a[kTexcoord];
out[kVUv + 1] = a[kTexcoord + 1];
for (var i = 0; i < 4; i++) {
out[kVColour + i] = a[kColour + i] * a[_color + i];
}
out[kVLightmap] = 0.0;
out[kVLightmap + 1] = 0.0;
for (var i = 0; i < 4; i++) {
out[kVInstance + i] = a[_data + i];
}
final Vector3 t =
model.getRotation() *
(rotation *
(morphed
? Vector3(
_morphScratch.tangent.x,
_morphScratch.tangent.y,
_morphScratch.tangent.z,
)
: Vector3(a[kTangent], a[kTangent + 1], a[kTangent + 2])));
out[kVTangent] = t.x;
out[kVTangent + 1] = t.y;
out[kVTangent + 2] = t.z;
// Mirrored by the node or by the instance, and by both is not mirrored.
final mirrored =
(model.getRotation().determinant() < 0.0) !=
(rotation.determinant() < 0.0);
out[kVTangent + 3] = mirrored ? -a[kTangent + 3] : a[kTangent + 3];
return mvp * local;
}