#version 450 layout(points) in; layout(triangle_strip, max_vertices = 4) out; layout(set = 0, binding = 0) uniform NodeData { mat4 world; } node; layout(set = 1, binding = 0) uniform CameraData { mat4 viewProjection; mat4 view; mat4 projection; vec4 camPos; float nearPlane; float farPlane; float width; float height; float fov; float aspect; float scaleFactor; float pixelScaleFactor; } cam; layout(set = 3, binding = 0) uniform BillboardData { vec2 size; bool isFixedSize; } billboardInfo; layout(location = 0) out vec4 color; layout(location = 1) out vec2 tex; layout(location = 0) in VS_OUT { vec4 color; } gs_in[]; void main() { // The desired point for the billboard vec3 pos = gl_in[0].gl_Position.xyz; if(!billboardInfo.isFixedSize) { vec3 cameraRight = normalize(vec3(cam.view[0][0], cam.view[1][0], cam.view[2][0])); vec3 cameraUp = normalize(vec3(cam.view[0][1], cam.view[1][1], cam.view[2][1])); const vec2 offsets[4] = { vec2(0.5, -0.5), vec2(0.5, 0.5), vec2(-0.5, -0.5), vec2(-0.5, 0.5) }; const vec2 texCoords[4] = { vec2(1, 0), vec2(1, 1), vec2(0, 0), vec2(0, 1) }; for (int i = 0; i < 4; i++) { vec2 scaledSize = billboardInfo.size / length(billboardInfo.size); gl_Position = cam.viewProjection * vec4(pos + cameraRight * offsets[i].x * scaledSize.x + cameraUp * offsets[i].y * scaledSize.y, 1.0); color = gs_in[0].color; tex = texCoords[i].xy; EmitVertex(); } EndPrimitive(); } else { const vec2 offsets[4] = { vec2(-0.5, -0.5), vec2(-0.5, 0.5), vec2(0.5, -0.5), vec2(0.5, 0.5) }; const vec2 texCoords[4] = { vec2(0, 0), vec2(0, 1), vec2(1, 0), vec2(1, 1) }; for (int i = 0; i < 4; i++) { gl_Position = cam.viewProjection * vec4(pos, 1); gl_Position /= gl_Position.w; gl_Position.xy += offsets[i] * vec2(billboardInfo.size.x/cam.width, billboardInfo.size.x/cam.height); color = gs_in[0].color; tex = texCoords[i].xy; EmitVertex(); } EndPrimitive(); } }