/** * Copyright (c) 2019-2023 mol* contributors, licensed under MIT, See LICENSE file for more info. * * @author Alexander Rose */ export const spheres_frag = ` precision highp float; precision highp int; #define bumpEnabled #include common #include common_frag_params #include color_frag_params #include light_frag_params #include common_clip uniform mat4 uInvView; uniform float uAlphaThickness; varying float vRadius; varying vec3 vPoint; varying vec3 vPointViewPosition; #ifdef dSolidInterior const bool solidInterior = true; #else const bool solidInterior = false; #endif bool SphereImpostor(out vec3 modelPos, out vec3 cameraPos, out vec3 cameraNormal, out bool interior, out float fragmentDepth){ vec3 cameraSpherePos = -vPointViewPosition; vec3 rayOrigin = mix(vec3(0.0, 0.0, 0.0), vPoint, uIsOrtho); vec3 rayDirection = mix(normalize(vPoint), vec3(0.0, 0.0, 1.0), uIsOrtho); vec3 cameraSphereDir = mix(cameraSpherePos, rayOrigin - cameraSpherePos, uIsOrtho); float B = dot(rayDirection, cameraSphereDir); float det = B * B + vRadius * vRadius - dot(cameraSphereDir, cameraSphereDir); if (det < 0.0) return false; float sqrtDet = sqrt(det); float posT = mix(B + sqrtDet, B - sqrtDet, uIsOrtho); float negT = mix(B - sqrtDet, B + sqrtDet, uIsOrtho); cameraPos = rayDirection * negT + rayOrigin; modelPos = (uInvView * vec4(cameraPos, 1.0)).xyz; fragmentDepth = calcDepth(cameraPos); bool objectClipped = false; #if !defined(dClipPrimitive) && defined(dClipVariant_pixel) && dClipObjectCount != 0 if (clipTest(vec4(modelPos, 0.0))) { objectClipped = true; fragmentDepth = -1.0; } #endif if (fragmentDepth > 0.0) { cameraNormal = normalize(cameraPos - cameraSpherePos); interior = false; return true; } else if (uDoubleSided || solidInterior) { cameraPos = rayDirection * posT + rayOrigin; modelPos = (uInvView * vec4(cameraPos, 1.0)).xyz; fragmentDepth = calcDepth(cameraPos); cameraNormal = -normalize(cameraPos - cameraSpherePos); interior = true; if (fragmentDepth > 0.0) { #ifdef dSolidInterior if (!objectClipped) { fragmentDepth = 0.0 + (0.0000001 / vRadius); cameraNormal = -mix(normalize(vPoint), vec3(0.0, 0.0, 1.0), uIsOrtho); } #endif return true; } } return false; } void main(void){ vec3 cameraNormal; float fragmentDepth; #ifdef dApproximate vec3 pointDir = -vPointViewPosition - vPoint; if (dot(pointDir, pointDir) > vRadius * vRadius) discard; vec3 vViewPosition = -vPointViewPosition; fragmentDepth = gl_FragCoord.z; #if !defined(dIgnoreLight) || defined(dXrayShaded) pointDir.z -= cos(length(pointDir) / vRadius); cameraNormal = -normalize(pointDir / vRadius); #endif interior = false; #else vec3 modelPos; vec3 cameraPos; bool hit = SphereImpostor(modelPos, cameraPos, cameraNormal, interior, fragmentDepth); if (!hit) discard; if (fragmentDepth < 0.0) discard; if (fragmentDepth > 1.0) discard; gl_FragDepthEXT = fragmentDepth; vec3 vModelPosition = modelPos; vec3 vViewPosition = cameraPos; #endif #if !defined(dClipPrimitive) && defined(dClipVariant_pixel) && dClipObjectCount != 0 #include clip_pixel #endif #include assign_material_color #if defined(dRenderVariant_pick) #include check_picking_alpha #ifdef requiredDrawBuffers gl_FragColor = vObject; gl_FragData[1] = vInstance; gl_FragData[2] = vGroup; gl_FragData[3] = packDepthToRGBA(fragmentDepth); #else gl_FragColor = vColor; #endif #elif defined(dRenderVariant_depth) gl_FragColor = material; #elif defined(dRenderVariant_marking) gl_FragColor = material; #elif defined(dRenderVariant_color) vec3 normal = -cameraNormal; #include apply_light_color if (uRenderMask == MaskTransparent && uAlphaThickness > 0.0) { gl_FragColor.a *= min(1.0, vRadius / uAlphaThickness); } #include apply_interior_color #include apply_marker_color #include apply_fog #include wboit_write #include dpoit_write #endif } `;