molstar
Version:
A comprehensive macromolecular library.
315 lines (282 loc) • 11.5 kB
JavaScript
/**
* Copyright (c) 2020-2025 mol* contributors, licensed under MIT, See LICENSE file for more info.
*
* @author Alexander Rose <alexander.rose@weirdbyte.de>
* @author Gianluca Tomasello <giagitom@gmail.com>
*/
export const cylinders_frag = `
precision highp float;
precision highp int;
uniform mat4 uView;
varying mat4 vTransform;
varying vec3 vStart;
varying vec3 vEnd;
varying float vSize;
varying float vCap;
uniform vec3 uCameraDir;
uniform vec3 uCameraPosition;
uniform mat4 uInvView;
uniform vec4 uInteriorColor;
uniform vec4 uInteriorSubstance;
const bool solidInterior = true;
const bool solidInterior = false;
// adapted from https://www.shadertoy.com/view/4lcSRn
// The MIT License, Copyright 2016 Inigo Quilez
bool CylinderImpostor(
in vec3 rayOrigin, in vec3 rayDir,
in vec3 start, in vec3 end, in float radius,
out vec3 cameraNormal, out bool interior,
out vec3 modelPosition, out vec3 viewPosition, out float fragmentDepth
){
vec3 ba = end - start;
vec3 oc = rayOrigin - start;
float baba = dot(ba, ba);
float bard = dot(ba, rayDir);
float baoc = dot(ba, oc);
float k2 = baba - bard * bard;
float k1 = baba * dot(oc, rayDir) - baoc * bard;
float k0 = baba * dot(oc, oc) - baoc * baoc - radius * radius * baba;
float h = k1 * k1 - k2 * k0;
if (h < 0.0) return false;
bool topCap = (vCap > 0.9 && vCap < 1.1) || vCap >= 2.9;
bool bottomCap = (vCap > 1.9 && vCap < 2.1) || vCap >= 2.9;
bool topInterior = !topCap;
bool bottomInterior = !bottomCap;
topCap = true;
bottomCap = true;
bool topInterior = false;
bool bottomInterior = false;
bool clipped = false;
bool objectClipped = false;
// body outside
h = sqrt(h);
float t = (-k1 - h) / k2;
float y = baoc + t * bard;
if (y > 0.0 && y < baba) {
interior = false;
cameraNormal = (oc + t * rayDir - ba * y / baba) / radius;
modelPosition = rayOrigin + t * rayDir;
viewPosition = (uView * vec4(modelPosition, 1.0)).xyz;
fragmentDepth = calcDepth(viewPosition);
if (clipTest(modelPosition)) {
objectClipped = true;
fragmentDepth = -1.0;
topCap = !topInterior;
bottomCap = !bottomInterior;
}
if (fragmentDepth > 0.0) return true;
clipped = true;
}
if (!clipped) {
if (topCap && y < 0.0) {
// top cap
t = -baoc / bard;
if (abs(k1 + k2 * t) < h) {
interior = topInterior;
cameraNormal = -ba / baba;
modelPosition = rayOrigin + t * rayDir;
viewPosition = (uView * vec4(modelPosition, 1.0)).xyz;
fragmentDepth = calcDepth(viewPosition);
if (clipTest(modelPosition)) {
objectClipped = true;
fragmentDepth = -1.0;
topCap = !topInterior;
bottomCap = !bottomInterior;
}
if (fragmentDepth > 0.0) {
if (interior) cameraNormal = -rayDir;
return true;
return !interior;
}
}
} else if (bottomCap && y >= 0.0) {
// bottom cap
t = (baba - baoc) / bard;
if (abs(k1 + k2 * t) < h) {
interior = bottomInterior;
cameraNormal = ba / baba;
modelPosition = rayOrigin + t * rayDir;
viewPosition = (uView * vec4(modelPosition, 1.0)).xyz;
fragmentDepth = calcDepth(viewPosition);
if (clipTest(modelPosition)) {
objectClipped = true;
fragmentDepth = -1.0;
topCap = !topInterior;
bottomCap = !bottomInterior;
}
if (fragmentDepth > 0.0) {
if (interior) cameraNormal = -rayDir;
return true;
return !interior;
}
}
}
}
if (uDoubleSided || solidInterior) {
// body inside
h = -h;
t = (-k1 - h) / k2;
y = baoc + t * bard;
if (y > 0.0 && y < baba) {
interior = true;
cameraNormal = -(oc + t * rayDir - ba * y / baba) / radius;
modelPosition = rayOrigin + t * rayDir;
viewPosition = (uView * vec4(modelPosition, 1.0)).xyz;
fragmentDepth = calcDepth(viewPosition);
if (fragmentDepth > 0.0) {
if (!objectClipped) {
fragmentDepth = 0.0 + (0.0000002 / vSize);
cameraNormal = -rayDir;
// intersection of ray in model space with near plane in camera space
vec3 cameraRayOrigin = (uView * vec4(rayOrigin, 1.0)).xyz;
vec3 cameraRayDir = (uView * vec4(rayDir, 0.0)).xyz;
float nearT = - (uNear + cameraRayOrigin.z) / cameraRayDir.z;
viewPosition = cameraRayOrigin + nearT * cameraRayDir;
modelPosition = (uInvView * vec4(viewPosition, 1.0)).xyz;
}
return true;
}
}
if (topCap && y < 0.0) {
// top cap
t = -baoc / bard;
if (abs(k1 + k2 * t) < -h) {
interior = true;
cameraNormal = ba / baba;
modelPosition = rayOrigin + t * rayDir;
viewPosition = (uView * vec4(modelPosition, 1.0)).xyz;
fragmentDepth = calcDepth(viewPosition);
if (fragmentDepth > 0.0) {
if (!objectClipped) {
fragmentDepth = 0.0 + (0.0000002 / vSize);
cameraNormal = -rayDir;
// intersection of ray in model space with near plane in camera space
vec3 cameraRayOrigin = (uView * vec4(rayOrigin, 1.0)).xyz;
vec3 cameraRayDir = (uView * vec4(rayDir, 0.0)).xyz;
float nearT = - (uNear + cameraRayOrigin.z) / cameraRayDir.z;
viewPosition = cameraRayOrigin + nearT * cameraRayDir;
modelPosition = (uInvView * vec4(viewPosition, 1.0)).xyz;
}
return true;
}
}
} else if (bottomCap && y >= 0.0) {
// bottom cap
t = (baba - baoc) / bard;
if (abs(k1 + k2 * t) < -h) {
interior = true;
cameraNormal = -ba / baba;
modelPosition = rayOrigin + t * rayDir;
viewPosition = (uView * vec4(modelPosition, 1.0)).xyz;
fragmentDepth = calcDepth(viewPosition);
if (fragmentDepth > 0.0) {
if (!objectClipped) {
fragmentDepth = 0.0 + (0.0000002 / vSize);
cameraNormal = -rayDir;
// intersection of ray in model space with near plane in camera space
vec3 cameraRayOrigin = (uView * vec4(rayOrigin, 1.0)).xyz;
vec3 cameraRayDir = (uView * vec4(rayDir, 0.0)).xyz;
float nearT = - (uNear + cameraRayOrigin.z) / cameraRayDir.z;
viewPosition = cameraRayOrigin + nearT * cameraRayDir;
modelPosition = (uInvView * vec4(viewPosition, 1.0)).xyz;
}
return true;
}
}
}
}
return false;
}
void main() {
vec3 rayOrigin = vModelPosition;
vec3 rayDir = mix(normalize(vModelPosition - uCameraPosition), uCameraDir, uIsOrtho);
vec3 cameraNormal;
vec3 modelPosition;
vec3 viewPosition;
float fragmentDepth;
bool hit = CylinderImpostor(rayOrigin, rayDir, vStart, vEnd, vSize, cameraNormal, interior, modelPosition, viewPosition, fragmentDepth);
if (!hit) discard;
if (fragmentDepth < 0.0) discard;
if (fragmentDepth > 1.0) discard;
gl_FragDepthEXT = fragmentDepth;
vec3 vViewPosition = viewPosition;
vec3 vModelPosition = modelPosition;
mat3 normalMatrix = adjoint(uView);
vec3 normal = normalize(normalMatrix * -normalize(cameraNormal));
gl_FragColor = vObject;
gl_FragData[1] = vInstance;
gl_FragData[2] = vGroup;
gl_FragData[3] = packDepthToRGBA(fragmentDepth);
gl_FragColor = vColor;
gl_FragColor = material;
gl_FragColor = material;
gl_FragColor = material;
gl_FragData[1] = vec4(normal, emissive);
gl_FragData[2] = vec4(material.rgb, uDensity);
}
`;