Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
182 changes: 135 additions & 47 deletions examples/jsm/lines/LineMaterial.js
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,6 @@ ShaderLib[ 'line' ] = {
#include <logdepthbuf_pars_vertex>
#include <clipping_planes_pars_vertex>

uniform float worldUnits;
uniform float linewidth;
uniform vec2 resolution;

Expand All @@ -58,6 +57,9 @@ ShaderLib[ 'line' ] = {
attribute vec3 instanceColorEnd;

varying vec2 vUv;
varying vec4 worldPos;
varying vec3 worldStart;
varying vec3 worldEnd;

#ifdef USE_DASH

Expand Down Expand Up @@ -105,6 +107,9 @@ ShaderLib[ 'line' ] = {
vec4 start = modelViewMatrix * vec4( instanceStart, 1.0 );
vec4 end = modelViewMatrix * vec4( instanceEnd, 1.0 );

worldStart = start.xyz;
worldEnd = end.xyz;

// 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
Expand All @@ -131,78 +136,105 @@ ShaderLib[ 'line' ] = {
vec4 clipEnd = projectionMatrix * end;

// ndc space
vec2 ndcStart = clipStart.xy / clipStart.w;
vec2 ndcEnd = clipEnd.xy / clipEnd.w;
vec3 ndcStart = clipStart.xyz / clipStart.w;
vec3 ndcEnd = clipEnd.xyz / clipEnd.w;

// direction
vec2 dir = ndcEnd - ndcStart;
vec2 dir = ndcEnd.xy - ndcStart.xy;

// account for clip-space aspect ratio
dir.x *= aspect;
dir = normalize( dir );

// perpendicular to dir
vec2 offset = vec2( dir.y, - dir.x );

#ifdef WORLD_UNITS

// sign flip
if ( position.x < 0.0 ) offset *= - 1.0;
// perpendicular to dir
vec3 worldDir = normalize( end.xyz - start.xyz );
vec3 offset;
if ( position.y < 0.5 ) {

offset = normalize( cross( start.xyz, worldDir ) );

// endcaps
if ( position.y < 0.0 ) {
} else {

offset += - dir;
offset = normalize( cross( end.xyz, worldDir ) );

} else if ( position.y > 1.0 ) {
}

offset += dir;
// sign flip
if ( position.x < 0.0 ) offset *= - 1.0;

}
#ifndef USE_DASH

// adjust for linewidth
offset *= linewidth * 0.5;
// extend the line bounds to encompass endcaps
start.xyz += - worldDir * linewidth * 0.5;
end.xyz += worldDir * linewidth * 0.5;

// select end
vec4 clip = ( position.y < 0.5 ) ? start : end;
// shift the position of the quad so it hugs the forward edge of the line
offset.xy -= dir * dot( worldDir, vec3( 0.0, 0.0, 1.0 ) );

clip.xy += offset;
#endif

clip = projectionMatrix * clip;
// endcaps
if ( position.y > 1.0 ) {

offset.xy += dir * 2.0;

} else if ( position.y < 0.0 ) {

offset.xy -= dir * 2.0;

}

// adjust for linewidth
offset *= linewidth * 0.5;

// set the world position
worldPos = ( position.y < 0.5 ) ? start : end;
worldPos.xyz += offset;

// project the worldpos
vec4 clip = projectionMatrix * worldPos;

// shift the depth of the projected points so the line
// segements overlap neatly
vec3 clipPose = ( position.y < 0.5 ) ? ndcStart : ndcEnd;
clip.z = clipPose.z * clip.w;

#else

// undo aspect ratio adjustment
dir.x /= aspect;
offset.x /= aspect;
vec2 offset = vec2( dir.y, - dir.x );
// undo aspect ratio adjustment
dir.x /= aspect;
offset.x /= aspect;

// sign flip
if ( position.x < 0.0 ) offset *= - 1.0;
// sign flip
if ( position.x < 0.0 ) offset *= - 1.0;

// endcaps
if ( position.y < 0.0 ) {
// endcaps
if ( position.y < 0.0 ) {

offset += - dir;
offset += - dir;

} else if ( position.y > 1.0 ) {
} else if ( position.y > 1.0 ) {

offset += dir;
offset += dir;

}
}

// adjust for linewidth
offset *= linewidth;
// adjust for linewidth
offset *= linewidth;

// adjust for clip-space to screen-space conversion // maybe resolution should be based on viewport ...
offset /= resolution.y;
// adjust for clip-space to screen-space conversion // maybe resolution should be based on viewport ...
offset /= resolution.y;

// select end
vec4 clip = ( position.y < 0.5 ) ? clipStart : clipEnd;
// select end
vec4 clip = ( position.y < 0.5 ) ? clipStart : clipEnd;

// back to clip space
offset *= clip.w;
// back to clip space
offset *= clip.w;

clip.xy += offset;
clip.xy += offset;

#endif

Expand All @@ -221,6 +253,7 @@ ShaderLib[ 'line' ] = {
`
uniform vec3 diffuse;
uniform float opacity;
uniform float linewidth;

#ifdef USE_DASH

Expand All @@ -230,6 +263,9 @@ ShaderLib[ 'line' ] = {
#endif

varying float vLineDistance;
varying vec4 worldPos;
varying vec3 worldStart;
varying vec3 worldEnd;

#include <common>
#include <color_pars_fragment>
Expand All @@ -239,6 +275,35 @@ ShaderLib[ 'line' ] = {

varying vec2 vUv;

vec2 closestLineToLine(vec3 p1, vec3 p2, vec3 p3, vec3 p4) {

float mua;
float mub;

vec3 p13 = p1 - p3;
vec3 p43 = p4 - p3;

vec3 p21 = p2 - p1;

float d1343 = dot( p13, p43 );
float d4321 = dot( p43, p21 );
float d1321 = dot( p13, p21 );
float d4343 = dot( p43, p43 );
float d2121 = dot( p21, p21 );

float denom = d2121 * d4343 - d4321 * d4321;

float numer = d1343 * d4321 - d1321 * d4343;

mua = numer / denom;
mua = clamp( mua, 0.0, 1.0 );
mub = ( d1343 + d4321 * ( mua ) ) / d4343;
mub = clamp( mub, 0.0, 1.0 );

return vec2( mua, mub );

}

void main() {

#include <clipping_planes_fragment>
Expand All @@ -251,15 +316,38 @@ ShaderLib[ 'line' ] = {

#endif

if ( abs( vUv.y ) > 1.0 ) {
#ifdef WORLD_UNITS

float a = vUv.x;
float b = ( vUv.y > 0.0 ) ? vUv.y - 1.0 : vUv.y + 1.0;
float len2 = a * a + b * b;
// Find the closest points on the view ray and the line segment
vec3 rayEnd = normalize( worldPos.xyz ) * 1e5;
vec3 lineDir = worldEnd - worldStart;
vec2 params = closestLineToLine( worldStart, worldEnd, vec3( 0.0, 0.0, 0.0 ), rayEnd );

if ( len2 > 1.0 ) discard;
vec3 p1 = worldStart + lineDir * params.x;
vec3 p2 = rayEnd * params.y;
vec3 delta = p1 - p2;
float len = length( delta );
float norm = len / linewidth;

}
#ifndef USE_DASH

if (norm > 0.5) discard;

#endif

#else

if ( abs( vUv.y ) > 1.0 ) {

float a = vUv.x;
float b = ( vUv.y > 0.0 ) ? vUv.y - 1.0 : vUv.y + 1.0;
float len2 = a * a + b * b;

if ( len2 > 1.0 ) discard;

}

#endif

vec4 diffuseColor = vec4( diffuse, opacity );

Expand Down