#version 330 core layout(location = 0) in vec2 qQuadPos; // 单位 quad 的局部顶点坐标(范围 [-1,1]) layout(location = 1) in vec2 aUV; // UV(用于 fragment shader 把 quad 变成圆形) layout(location = 2) in vec2 iOffsetXZ; // 每个点的偏移(世界坐标 XZ) layout(location = 3) in float iValue; // 每个点的数值(用于颜色映射) out vec2 vUV; out float vValue; out vec3 vWorldPos; uniform mat4 uMVP; // Projection * View * Model(这里 Model 约等于单位矩阵) uniform float uDotRadius; // dot 半径(世界坐标单位) uniform float uBaseY; // dot 的高度(通常 = panel 顶面 y + 一点点偏移) void main() { vUV = aUV; vValue = iValue; // 先确定 dot 的中心点(世界坐标) vec3 world = vec3(iOffsetXZ.x, uBaseY, iOffsetXZ.y); // 再把单位 quad 按半径缩放并加到中心点上(让 quad 落在 XZ 平面) world.x += qQuadPos.x * uDotRadius; world.z += qQuadPos.y * uDotRadius; // 输出裁剪空间坐标(最终会进行透视除法与视口映射,变成屏幕上的像素) vWorldPos = world; gl_Position = uMVP * vec4(world, 1.0); }