#version 300 es layout(location = 0) in vec3 aPos; layout(location = 1) in vec3 aNormal; layout(location = 2) in vec4 aInstRot; layout(location = 3) in vec3 aInstPos; layout(location = 4) in vec3 aInstScale; layout(location = 5) in vec4 aInstColor; layout(location = 6) in vec4 aInstParams; // x = emissive, y = receiveShadow, z = fresnel, w = bands layout(location = 7) in vec4 aInstFx; // x = flow strength, y = noise scale, z = vertex warp (world units), w = ring band (world units) #include "_graphics_uniforms.glsl" out highp vec3 vNormal; out highp vec3 vWorldPos; out vec3 vObjPos; // unit-primitive position — stable domain for the band pattern out vec4 vColor; out float vEmissive; out float vReceiveShadow; out vec2 vMaterial; // x = fresnel, y = bands out vec2 vFlow; // x = strength, y = noise scale vec3 quatRotate(vec4 q, vec3 v) { return v + 2.0 * cross(q.xyz, cross(q.xyz, v) + q.w * v); } void main() { vec3 pos = aPos; // absolute ring band: pull a ring's inner verts (radius < 1) out to a constant world-unit width, // so a scaling shockwave front stays slim instead of thickening with its radius if (aInstFx.w > 0.0) { float r = length(pos.xy); if (r > 0.001 && r < 0.99) { float innerObj = max(1.0 - aInstFx.w / max(aInstScale.x, 0.001), 0.0); pos.xy = (pos.xy / r) * innerObj; } } vec3 world = quatRotate(aInstRot, pos * aInstScale) + aInstPos; // inverse-transpose of a diagonal scale is 1/scale — exact for axis-aligned box normals vNormal = quatRotate(aInstRot, normalize(aNormal / aInstScale)); // vertex warp: traveling waves along the surface + a fast high-frequency shiver — field energy, // not a drifting blob if (aInstFx.z > 0.0) { highp float t = u_timeParams.y; highp vec2 p = world.xy * aInstFx.y; float n = sin(p.x * 2.3 + p.y * 1.9 - t * 3.1) * 0.55 + sin(p.x * -1.4 + p.y * 2.6 + t * 2.3) * 0.35 + sin((p.x + p.y) * 3.7 - t * 7.0) * 0.25; world += vNormal * (n * aInstFx.z); } gl_Position = u_viewProjection * vec4(world, 1.0); vWorldPos = world; vObjPos = aPos; vColor = aInstColor; vEmissive = aInstParams.x; vReceiveShadow = aInstParams.y; vMaterial = aInstParams.zw; vFlow = aInstFx.xy; }