molstar
Version:
A comprehensive macromolecular library.
130 lines (104 loc) • 3.83 kB
JavaScript
"use strict";
/**
* Copyright (c) 2018-2025 mol* contributors, licensed under MIT, See LICENSE file for more info.
*
* @author Alexander Rose <alexander.rose@weirdbyte.de>
*
* heavily based on code by WestLangley from https://github.com/WestLangley/three.js/blob/af28b2fb706ac109771ecad0a7447fad90ab3210/examples/js/lines/LineMaterial.js
*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.lines_vert = void 0;
exports.lines_vert = `
precision highp float;
precision highp int;
uniform float uPixelRatio;
uniform vec4 uViewport;
attribute mat4 aTransform;
attribute float aInstance;
attribute float aGroup;
attribute vec2 aMapping;
attribute vec3 aStart;
attribute vec3 aEnd;
void trimSegment(const in vec4 start, inout vec4 end) {
// trim end segment so it terminates between the camera plane and the near plane
// conservative estimate of the near plane
float a = uProjection[2][2]; // 3rd entry in 3rd column
float b = uProjection[3][2]; // 3rd entry in 4th column
float nearEstimate = -0.5 * b / a;
float alpha = (nearEstimate - start.z) / (end.z - start.z);
end.xyz = mix(start.xyz, end.xyz, alpha);
}
void main(){
float aspect = uViewport.z / uViewport.w;
int vertexId = VertexID;
mat4 modelView = uView * uModel * aTransform;
// camera space
vec4 start = modelView * vec4(aStart, 1.0);
vec4 end = modelView * vec4(aEnd, 1.0);
// assign position
vec4 position4 = vec4((aMapping.y < 0.5) ? aStart : aEnd, 1.0);
vec4 mvPosition = modelView * position4;
vViewPosition = mvPosition.xyz;
vModelPosition = (uModel * aTransform * position4).xyz; // for clipping in frag shader
// special case for perspective projection, and segments that terminate either in, or behind, the camera plane
// clearly the gpu firmware has a way of addressing this issue when projecting into ndc space
// but we need to perform ndc-space calculations in the shader, so we must address this issue directly
// perhaps there is a more elegant solution -- WestLangley
bool perspective = (uProjection[2][3] == -1.0); // 4th entry in the 3rd column
if (perspective) {
if (start.z < 0.0 && end.z >= 0.0) {
trimSegment(start, end);
} else if (end.z < 0.0 && start.z >= 0.0) {
trimSegment(end, start);
}
}
// clip space
vec4 clipStart = uProjection * start;
vec4 clipEnd = uProjection * end;
// ndc space
vec2 ndcStart = clipStart.xy / clipStart.w;
vec2 ndcEnd = clipEnd.xy / clipEnd.w;
// direction
vec2 dir = ndcEnd - ndcStart;
// account for clip-space aspect ratio
dir.x *= aspect;
dir = normalize(dir);
// perpendicular to dir
vec2 offset = vec2(dir.y, - dir.x);
// undo aspect ratio adjustment
dir.x /= aspect;
offset.x /= aspect;
// sign flip
if (aMapping.x < 0.0) offset *= -1.0;
// calculate linewidth
float linewidth;
linewidth = size * uPixelRatio * ((uViewport.w / 2.0) / -start.z) * 5.0;
linewidth = size * uPixelRatio;
linewidth = max(1.0, linewidth);
// adjust for linewidth
offset *= linewidth;
// adjust for clip-space to screen-space conversion
offset /= uViewport.w;
// select end
vec4 clip = (aMapping.y < 0.5) ? clipStart : clipEnd;
// back to clip space
offset *= clip.w;
clip.xy += offset;
gl_Position = clip;
}
`;