UNPKG

molstar

Version:

A comprehensive macromolecular library.

193 lines (164 loc) 6.28 kB
/** * Copyright (c) 2019-2025 mol* contributors, licensed under MIT, See LICENSE file for more info. * * @author Alexander Rose <alexander.rose@weirdbyte.de> */ export const spheres_vert = ` precision highp float; precision highp int; #include common #include read_from_texture #include common_vert_params #include color_vert_params #include size_vert_params #include common_clip uniform mat4 uModelView; uniform mat4 uInvProjection; uniform float uIsOrtho; uniform bool uIsAsymmetricProjection; uniform vec2 uTexDim; uniform sampler2D tPositionGroup; attribute mat4 aTransform; attribute float aInstance; varying float vRadius; varying vec3 vPoint; varying vec3 vPointViewPosition; /** * Bounding rectangle of a clipped, perspective-projected 3D Sphere. * Michael Mara, Morgan McGuire. 2013 * * Specialization by Arseny Kapoulkine, MIT License Copyright (c) 2018 * https://github.com/zeux/niagara * * Only works for for symmetric projections. */ void sphereProjection(const in vec3 p, const in float r, const in vec2 mapping) { vec3 pr = p * r; float pzr2 = p.z * p.z - r * r; float vx = sqrt(p.x * p.x + pzr2); float minx = ((vx * p.x - pr.z) / (vx * p.z + pr.x)) * uProjection[0][0]; float maxx = ((vx * p.x + pr.z) / (vx * p.z - pr.x)) * uProjection[0][0]; float vy = sqrt(p.y * p.y + pzr2); float miny = ((vy * p.y - pr.z) / (vy * p.z + pr.y)) * uProjection[1][1]; float maxy = ((vy * p.y + pr.z) / (vy * p.z - pr.y)) * uProjection[1][1]; gl_Position.xy = vec2(maxx + minx, maxy + miny) * -0.5; gl_Position.xy -= mapping * vec2(maxx - minx, maxy - miny) * 0.5; gl_Position.xy *= gl_Position.w; } const mat4 D = mat4( 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, -1.0 ); /** * Compute point size and center using the technique described in: * "GPU-Based Ray-Casting of Quadratic Surfaces" http://dl.acm.org/citation.cfm?id=2386396 * by Christian Sigg, Tim Weyrich, Mario Botsch, Markus Gross. */ void quadraticProjection(const in vec3 position, const in float radius, const in vec2 mapping) { vec2 xbc, ybc; mat4 T = mat4( radius, 0.0, 0.0, 0.0, 0.0, radius, 0.0, 0.0, 0.0, 0.0, radius, 0.0, position.x, position.y, position.z, 1.0 ); mat4 R = transpose4(uProjection * uModelView * aTransform * T); float A = dot(R[3], D * R[3]); float B = -2.0 * dot(R[0], D * R[3]); float C = dot(R[0], D * R[0]); xbc[0] = (-B - sqrt(B * B - 4.0 * A * C)) / (2.0 * A); xbc[1] = (-B + sqrt(B * B - 4.0 * A * C)) / (2.0 * A); float sx = abs(xbc[0] - xbc[1]) * 0.5; A = dot(R[3], D * R[3]); B = -2.0 * dot(R[1], D * R[3]); C = dot(R[1], D * R[1]); ybc[0] = (-B - sqrt(B * B - 4.0 * A * C)) / (2.0 * A); ybc[1] = (-B + sqrt(B * B - 4.0 * A * C)) / (2.0 * A); float sy = abs(ybc[0] - ybc[1]) * 0.5; gl_Position.xy = vec2(0.5 * (xbc.x + xbc.y), 0.5 * (ybc.x + ybc.y)); gl_Position.xy -= mapping * vec2(sx, sy); gl_Position.xy *= gl_Position.w; } void main(void){ vec2 mapping = vec2(1.0, 1.0); // vertices 2 and 5 #if __VERSION__ == 100 int m = imod(VertexID, 6); #else int m = VertexID % 6; #endif if (m == 0) { mapping = vec2(-1.0, 1.0); } else if (m == 1 || m == 3) { mapping = vec2(-1.0, -1.0); } else if (m == 4) { mapping = vec2(1.0, -1.0); } int vertexId = VertexID / 6; vec4 positionGroup = readFromTexture(tPositionGroup, vertexId, uTexDim); vec3 position = positionGroup.rgb; float group = positionGroup.a; #include assign_color_varying #include assign_marker_varying #include assign_clipping_varying #include assign_size vRadius = size * uModelScale; vec4 position4 = vec4(position, 1.0); vModelPosition = (uModel * aTransform * position4).xyz; // for clipping in frag shader float d; if (uLod.w != 0.0 && (uLod.x != 0.0 || uLod.y != 0.0)) { if (uModelScale != 1.0) { vRadius *= uLod.w; } else { d = (dot(uCameraPlane.xyz, vModelPosition) + uCameraPlane.w) / uModelScale; float f = min( smoothstep(uLod.x, uLod.x + uLod.z, d), 1.0 - smoothstep(uLod.y - uLod.z, uLod.y, d) ) * uLod.w; vRadius *= f; } } vec4 mvPosition = uModelView * aTransform * position4; #ifdef dApproximate vec4 mvCorner = vec4(mvPosition.xyz, 1.0); mvCorner.xy += mapping * vRadius; gl_Position = uProjection * mvCorner; #else if (uIsOrtho == 1.0) { vec4 mvCorner = vec4(mvPosition.xyz, 1.0); mvCorner.xy += mapping * vRadius; gl_Position = uProjection * mvCorner; } else if (uIsAsymmetricProjection) { gl_Position = uProjection * vec4(mvPosition.xyz, 1.0); quadraticProjection(position, vRadius / uModelScale, mapping); } else { gl_Position = uProjection * vec4(mvPosition.xyz, 1.0); sphereProjection(mvPosition.xyz, vRadius, mapping); } #endif vec4 vPoint4 = uInvProjection * gl_Position; vPoint = vPoint4.xyz / vPoint4.w; vPointViewPosition = -mvPosition.xyz / mvPosition.w; if (gl_Position.z < -gl_Position.w) { mvPosition.z -= 2.0 * vRadius; // avoid clipping gl_Position.z = (uProjection * vec4(mvPosition.xyz, 1.0)).z; } if (uModelScale == 1.0) { if (uLod.w != 0.0 && (uLod.x != 0.0 || uLod.y != 0.0)) { if (d < uLod.x || d > uLod.y) { // move out of [ -w, +w ] to 'discard' in vert shader gl_Position.z = 2.0 * gl_Position.w; } } } #if defined(dClipPrimitive) && !defined(dClipVariant_instance) && dClipObjectCount != 0 if (clipTest(vModelPosition / uModelScale)) { // move out of [ -w, +w ] to 'discard' in vert shader gl_Position.z = 2.0 * gl_Position.w; } #else #include clip_instance #endif } `;