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');
// Morphed first and in the mesh's own space, which is the order the GLSL
// uses and the order glTF specifies.
final morphed =
vertexIndex >= 0 &&
_morphScratch.load(
vertexIndex,
a,
bindings,
positionAt: kPosition,
normalAt: kNormal,
tangentAt: kTangent,
);
final local = 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;
// `mat3(normal_matrix) * normal`: the upper-left three by three, so the
// translation does not move a direction.
final Vector3 n =
normalMatrix.getRotation() *
(morphed
? _morphScratch.normal
: Vector3(a[kNormal], a[kNormal + 1], a[kNormal + 2]));
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];
}
out[kVLightmap] = 0.0;
out[kVLightmap + 1] = 0.0;
for (var i = 0; i < 4; i++) {
out[kVInstance + i] = 0.0;
}
// The tangent transforms with the model matrix, not the normal matrix: it
// lies *in* the surface, so it stretches with the geometry rather than
// staying perpendicular to it.
final Vector3 t =
model.getRotation() *
(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;
// The bitangent sign turned round under a mirroring model, as the GLSL
// does: cross(n, t) of two transformed vectors carries the determinant.
out[kVTangent + 3] = model.getRotation().determinant() < 0.0
? -a[kTangent + 3]
: a[kTangent + 3];
return mvp * local;
}