Created
February 19, 2020 14:31
-
-
Save mattdesl/36e0f8e9b6f7bdf7182ebc2482dba7c7 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
attribute float direction; | |
attribute vec2 distances; | |
attribute float vertexThickness; | |
attribute vec3 nextPosition; | |
attribute vec3 previousPosition; | |
varying vec2 vUv; | |
const bool miter = false; | |
const float miterLimit = 8.0; | |
uniform float thickness; | |
uniform float totalDistance; | |
uniform float aspect; | |
vec4 screenSpaceLine (vec3 offset, float computedThickness) { | |
vec2 aspectVec = vec2(aspect, 1.0); | |
mat4 projViewModel = projectionMatrix * modelViewMatrix; | |
vec4 previousProjected = projViewModel * vec4(vec3(previousPosition.xyz) + offset, 1.0); | |
vec4 currentProjected = projViewModel * vec4(vec3(position.xyz) + offset, 1.0); | |
vec4 nextProjected = projViewModel * vec4(vec3(nextPosition.xyz) + offset, 1.0); | |
//get 2D screen space with W divide and aspect correction | |
vec2 currentScreen = currentProjected.xy / currentProjected.w * aspectVec; | |
vec2 previousScreen = previousProjected.xy / previousProjected.w * aspectVec; | |
vec2 nextScreen = nextProjected.xy / nextProjected.w * aspectVec; | |
float len = computedThickness; | |
float orientation = direction; | |
vec2 dirA = normalize(currentScreen - previousScreen); | |
//starting point uses (next - current) | |
vec2 dir = vec2(0.0); | |
if (currentScreen == previousScreen) { | |
dir = normalize(nextScreen - currentScreen); | |
} | |
//ending point uses (current - previous) | |
else if (currentScreen == nextScreen) { | |
dir = normalize(currentScreen - previousScreen); | |
} | |
//somewhere in middle, needs a join | |
else { | |
//get directions from (C - B) and (B - A) | |
vec2 dirB = normalize(nextScreen - currentScreen); | |
if (miter) { | |
//now compute the miter join normal and length | |
vec2 tangent = normalize(dirA + dirB); | |
vec2 perp = vec2(-dirA.y, dirA.x); | |
vec2 miter = vec2(-tangent.y, tangent.x); | |
float miterDot = dot(miter, perp); | |
len = miterDot == 0.0 ? 0.0 : (computedThickness / miterDot); | |
len = clamp(len, 0.0, computedThickness * miterLimit); | |
dir = tangent; | |
} else { | |
dir = normalize(dirA + dirB); | |
} | |
} | |
vec2 normal = vec2(-dir.y, dir.x); | |
// convert pixel thickness to NDC space | |
vec2 normalLength = vec2(len / 2.0); | |
normalLength = normalLength * 2.0; | |
// scale normal to line thickness | |
normal *= normalLength; | |
vec4 finalOffset = vec4(normal * orientation, 0.0, 0.0); | |
return currentProjected + finalOffset; | |
} | |
void main () { | |
float computedThickness = 1.0; | |
vec3 offset = vec3(0.0); | |
gl_Position = screenSpaceLine(offset, computedThickness); | |
vUv = vec2(distances.x, direction * 0.5 + 0.5); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment