IsodiModel.vertexShader
struct IsodiModel
static immutable
auto vertexShader =
format!"
#version 330
#define PI %s
"(raylib.PI) ~ q{
in vec3 vertexPosition;
in vec2 vertexTexCoord;
in vec4 vertexVariantUV;
in float vertexBone;
uniform mat4 transform;
uniform mat4 modelview;
uniform mat4 projection;
uniform int flatten;
uniform sampler2D matrixTexture;
out vec2 fragTexCoord;
out vec4 fragVariantUV;
out vec2 fragAnchor;
flat out int angle;
/// Rotate a vector by a quaternion.
/// See: https://stackoverflow.com/questions/9037174/glsl-rotation-with-a-rotation-vector/9037454#9037454
vec4 rotate(vec4 vector, vec4 quat) {
vec3 temp = cross(quat.xyz, vector.xyz) + quat.w * vector.xyz;
return vector + vec4(2.0 * cross(quat.xyz, temp), 0.0);
}
void main() {
// Send vertex attributes to fragment shader
fragTexCoord = vertexTexCoord;
fragVariantUV = vertexVariantUV;
// Flatview: Camera transform (modelview) excluding vertex height
mat4 flatview = modelview;
flatview[0].y = 0;
flatview[1].y = 1;
flatview[2].y = 0;
// Keep [3] to let translations (such as sharpview) through
// Also correct Z result, required for proper angle checking
flatview[1].z = 0;
flatview[2].z /= modelview[1].y;
// Note: I achieved this correction by experimenting. It might not be mathematically accurate, but
// it looks good enough.
// Set transform matrix, angle quaternion and angle index for this bone
mat4 boneMatrix = mat4(1.0);
vec4 boneQuat = vec4(0, 0, 0, 1);
angle = 0;
// If we do have bone data
if (!isnan(vertexBone)) {
// Load the matrix
boneMatrix = mat4(
texture2D(matrixTexture, vec2(0.0/4, vertexBone)),
texture2D(matrixTexture, vec2(1.0/4, vertexBone)),
texture2D(matrixTexture, vec2(2.0/4, vertexBone)),
texture2D(matrixTexture, vec2(3.0/4, vertexBone))
);
// Get the normal in camera view, only as seen from top in 2D
vec2 normal = normalize(
(flatview * boneMatrix * vec4(0, 0, 1, 0)).xz
);
// Get the bone's orientation in the 2D plane (around Z axis)
float orientation = atan(normal.y, normal.x) + PI / 2;
// Snap the angle to texture angles
// TODO Use the bone's angle property
float snapped = round(orientation * 2 / PI);
// Revert the rotation for textures
angle = (4-int(snapped)) % 4;
// Convert angle index to radians
orientation = snapped * PI / 2 / 2;
// Create a quaternion to counter the orientation
boneQuat = vec4(0, sin(orientation), 0, cos(orientation));
}
// Transform the vertex according to bone properties
vec4 position = boneMatrix * rotate(vec4(vertexPosition, 1), boneQuat);
// Set the anchor
fragAnchor = position.xz;
// Regular shape
if (flatten == 0) {
// Calculate final vertex position
gl_Position = projection * modelview * transform * position;
}
// Flattened shape
else {
// Sharp: Camera transform only affecting height
mat4 sharpview = mat4(
1, modelview[0].y, 0, 0,
0, modelview[1].y, 0, 0,
0, modelview[2].y, 1, 0,
0, modelview[3].y, 0, 1
);
// Calculate the final position in flat mode
gl_Position = projection * flatview * (
// Get the regular position
position
// Apply transform
+ sharpview * (transform * vec4(1, 1, 1, 1) - vec4(1, 1, 1, 1))
);
// TODO Fix transform to work properly with rotations.
}
}
} ~ '\0';
isodi isodi_model IsodiModel
functionsstatic functionsstatic variablesvariables
Default fragment shader used to render the model.
The data is null-terminated for C compatibility.