const char *volume_fs =
  "#version 400\n"
  "precision highp float;\n"
  "\n"
  "// The ray entry/exit attachments from bounding-box passes:\n"
  "uniform sampler2D inFrontPosTex;\n"
  "uniform sampler2D inBackPosTex;\n"
  "uniform vec3 positiveColor;\n"
  "uniform vec3 negativeColor;\n"
  "\n"
  "// Our 3D volume (wavefunction):\n"
  "uniform sampler3D uVolumeData;\n"
  "\n"
  "// Cube bounds in world space:\n"
  "uniform vec3 uBoxMin;\n"
  "uniform vec3 uBoxMax;\n"
  "\n"
  "// Camera position for ray computation when back faces are clipped\n"
  "uniform vec3 uCameraPos;\n"
  "\n"
  "// View direction for orthographic projection (all rays parallel)\n"
  "uniform vec3 uViewDir;\n"
  "\n"
  "// Projection type: 0 = perspective, 1 = orthographic\n"
  "uniform int uProjectionType;\n"
  "\n"
  "// Screen size:\n"
  "uniform float width;\n"
  "uniform float height;\n"
  "\n"
  "// Ray-march parameters:\n"
  "uniform int   numSteps;    // e.g. 256\n"
  "uniform float alphaScale;  // overall alpha multiplier\n"
  "\n"
  "out vec4 colorOut;\n"
  "\n"
  "// Ray-box intersection: returns exit t value for ray origin + t * dir\n"
  "float rayBoxExit(vec3 origin, vec3 dir, vec3 boxMin, vec3 boxMax)\n"
  "{\n"
  "    vec3 invDir = 1.0 / dir;\n"
  "    vec3 t1 = (boxMin - origin) * invDir;\n"
  "    vec3 t2 = (boxMax - origin) * invDir;\n"
  "    vec3 tMax = max(t1, t2);\n"
  "    return min(min(tMax.x, tMax.y), tMax.z);\n"
  "}\n"
  "\n"
  "// Ray-box intersection: returns entry t value for ray origin + t * dir\n"
  "float rayBoxEntry(vec3 origin, vec3 dir, vec3 boxMin, vec3 boxMax)\n"
  "{\n"
  "    vec3 invDir = 1.0 / dir;\n"
  "    vec3 t1 = (boxMin - origin) * invDir;\n"
  "    vec3 t2 = (boxMax - origin) * invDir;\n"
  "    vec3 tMin = min(t1, t2);\n"
  "    return max(max(tMin.x, tMin.y), tMin.z);\n"
  "}\n"
  "\n"
  "void main()\n"
  "{\n"
  "    vec2 UV = gl_FragCoord.xy / vec2(width, height);\n"
  "\n"
  "    vec3 entryPos = texture(inFrontPosTex, UV).xyz;\n"
  "    vec3 exitPos  = texture(inBackPosTex,  UV).xyz;\n"
  "\n"
  "    // Get the expected diagonal length of the box\n"
  "    vec3 boxSize = uBoxMax - uBoxMin;\n"
  "    float boxDiagonal = length(boxSize);\n"
  "\n"
  "    // Check for sentinel values (positions set to -1e6 when no hit)\n"
  "    bool entryIsSentinel = entryPos.x < -1e5;\n"
  "    bool exitIsSentinel = exitPos.x < -1e5;\n"
  "\n"
  "    // Compute ray direction\n"
  "    vec3 rayDir;\n"
  "    if (uProjectionType == 1) {\n"
  "        // Orthographic: all rays are parallel to view direction\n"
  "        rayDir = uViewDir;\n"
  "    } else {\n"
  "        // Perspective: rays diverge from camera position\n"
  "        if (!entryIsSentinel) {\n"
  "            rayDir = normalize(entryPos - uCameraPos);\n"
  "        } else if (!exitIsSentinel) {\n"
  "            rayDir = normalize(exitPos - uCameraPos);\n"
  "        } else {\n"
  "            // Both sentinel - no valid ray\n"
  "            discard;\n"
  "        }\n"
  "    }\n"
  "\n"
  "    // When either position is sentinel (clipped), compute analytically\n"
  "    if (entryIsSentinel || exitIsSentinel) {\n"
  "        if (uProjectionType == 1) {\n"
  "            // Orthographic: use the valid position as reference point\n"
  "            vec3 refPoint;\n"
  "            if (!entryIsSentinel) {\n"
  "                refPoint = entryPos;\n"
  "            } else {\n"
  "                refPoint = exitPos;\n"
  "            }\n"
  "            // Trace ray through reference point to find both entry and exit\n"
  "            // Move reference point back along ray to ensure we're outside the box\n"
  "            vec3 rayOrigin = refPoint - rayDir * boxDiagonal * 2.0;\n"
  "            float tEntry = rayBoxEntry(rayOrigin, rayDir, uBoxMin, uBoxMax);\n"
  "            float tExit = rayBoxExit(rayOrigin, rayDir, uBoxMin, uBoxMax);\n"
  "\n"
  "            if (tExit <= tEntry) {\n"
  "                discard; // Ray misses box\n"
  "            }\n"
  "\n"
  "            entryPos = rayOrigin + rayDir * tEntry;\n"
  "            exitPos = rayOrigin + rayDir * tExit;\n"
  "        } else {\n"
  "            // Perspective: use camera position as ray origin\n"
  "            float tEntry = rayBoxEntry(uCameraPos, rayDir, uBoxMin, uBoxMax);\n"
  "            float tExit = rayBoxExit(uCameraPos, rayDir, uBoxMin, uBoxMax);\n"
  "\n"
  "            if (tExit <= tEntry || tExit <= 0.0) {\n"
  "                discard; // Ray misses box or is behind camera\n"
  "            }\n"
  "\n"
  "            if (tEntry > 0.0) {\n"
  "                entryPos = uCameraPos + rayDir * tEntry;\n"
  "            } else {\n"
  "                // Camera is inside the box\n"
  "                entryPos = uCameraPos;\n"
  "            }\n"
  "            exitPos = uCameraPos + rayDir * tExit;\n"
  "        }\n"
  "        entryIsSentinel = false;\n"
  "        exitIsSentinel = false;\n"
  "    }\n"
  "\n"
  "    vec3 dir = exitPos - entryPos;\n"
  "    float rayLength = length(dir);\n"
  "\n"
  "    // Discard if ray length is invalid:\n"
  "    // - Too short (no real volume to traverse)\n"
  "    // - Too long (positions are garbage/sentinel values)\n"
  "    if (rayLength < 0.0001 || rayLength > boxDiagonal * 2.0) {\n"
  "        discard;\n"
  "    }\n"
  "\n"
  "    vec3 stepDir = normalize(dir);\n"
  "    float stepSize = rayLength / float(numSteps);\n"
  "    vec3 step = stepDir * stepSize;\n"
  "\n"
  "    vec3 accumulatedColor = vec3(0.0);\n"
  "    float accumulatedAlpha = 0.0;\n"
  "    vec3 currentPosition = entryPos;\n"
  "\n"
  "    for (int i = 0; i < numSteps; i++)\n"
  "    {\n"
  "        if (accumulatedAlpha > 0.95)\n"
  "            break;\n"
  "\n"
  "        // Map world position to texture coordinates [0, 1]\n"
  "        vec3 volumeUV = (currentPosition - uBoxMin) / boxSize;\n"
  "\n"
  "        // Skip samples that are clearly outside (with small tolerance for edge precision)\n"
  "        if (any(lessThan(volumeUV, vec3(-0.01))) ||\n"
  "            any(greaterThan(volumeUV, vec3(1.01))))\n"
  "        {\n"
  "            currentPosition += step;\n"
  "            continue;\n"
  "        }\n"
  "\n"
  "        // Clamp to valid range for texture sampling (handles edge precision issues)\n"
  "        volumeUV = clamp(volumeUV, vec3(0.0), vec3(1.0));\n"
  "\n"
  "        float psi = texture(uVolumeData, volumeUV).r;\n"
  "\n"
  "        float amplitude = abs(psi);\n"
  "        vec3 color = (psi >= 0.0) ? positiveColor : negativeColor;\n"
  "\n"
  "        float alphaSample = amplitude * alphaScale;\n"
  "\n"
  "        // Front-to-back compositing with premultiplied alpha\n"
  "        accumulatedColor += (1.0 - accumulatedAlpha) * color * alphaSample;\n"
  "        accumulatedAlpha += (1.0 - accumulatedAlpha) * alphaSample;\n"
  "\n"
  "        currentPosition += step;\n"
  "    }\n"
  "\n"
  "    // Output premultiplied color and alpha - let GL blending composite over scene\n"
  "    colorOut = vec4(accumulatedColor, accumulatedAlpha);\n"
  "}\n"
  "\n";
