#pragma once inline const char* vertPart = R"( #version 330 core #ifndef USE_2D_BILLBOARD #define USE_2D_BILLBOARD 1 //2D mesh => 1 ; 3D mesh => 0 #endif // Mesh-Positions-Stream (per-vertex) #if USE_2D_BILLBOARD layout(location = 0) in vec2 meshPos; // z.B. Quad-Ecken (-0.5..0.5) #else layout(location = 0) in vec3 meshPos; // echte 3D-Mesh-Position #endif // Instanz-Attribute layout(location = 1) in vec3 inPosition; // Partikelzentrum (Welt) layout(location = 2) in float inSize; // Uniform-Scale layout(location = 3) in float inRotation; // Rotation (nur im Billboard-Modus genutzt) layout(location = 4) in vec4 inColor; // RGBA uniform mat4 prMatrix; uniform mat4 camMatrix; out VS_OUT { vec4 color; #if USE_2D_BILLBOARD vec2 uv; // optional: für runde Maske im FS #endif } vs; // Kameraachsen aus View-Matrix (Spalten 0/1) vec3 CameraRight(mat4 view) { return vec3(view[0][0], view[1][0], view[2][0]); } vec3 CameraUp (mat4 view) { return vec3(view[0][1], view[1][1], view[2][1]); } void main() { vs.color = inColor; #if USE_2D_BILLBOARD // 2D-Rotation im Billboard-Raum float c = cos(inRotation); float s = sin(inRotation); vec2 q = vec2(c * meshPos.x - s * meshPos.y, s * meshPos.x + c * meshPos.y); vec3 right = CameraRight(camMatrix); vec3 up = CameraUp(camMatrix); // Uniform-Scaling über inSize vec3 worldPos = inPosition + (q.x * inSize) * right + (q.y * inSize) * up; // optionales UV für Kreis-Maske vs.uv = meshPos * 0.5 + 0.5; // falls meshPos in -1..1: nimm (meshPos*0.5+0.5) #else // echtes 3D-Mesh: nur uniform Scale + Translation vec3 worldPos = inPosition + meshPos * inSize; #endif gl_Position = prMatrix * camMatrix * vec4(worldPos, 1.0); } )"; inline const char* fragPart = R"( #version 330 core #ifndef USE_2D_BILLBOARD #define USE_2D_BILLBOARD 1 #endif // Optional runde Maske an/aus (nur sinnvoll im Billboard-Modus mit z.B. Quad) #ifndef USE_ROUND_MASK #define USE_ROUND_MASK 0 #endif in VS_OUT { vec4 color; #if USE_2D_BILLBOARD vec2 uv; #endif } fs; layout(location = 0) out vec4 outColor; void main() { #if USE_2D_BILLBOARD && USE_ROUND_MASK // weiche Kreis-Maske (aus uv ~ 0..1) vec2 c = fs.uv * 2.0 - 1.0; // nach [-1..1] float r = length(c); if (r > 1.0) discard; float alpha = 1.0 - smoothstep(0.95, 1.0, r); outColor = vec4(fs.color.rgb, fs.color.a * alpha); #else outColor = fs.color; #endif } )";