|
|
@@ -0,0 +1,982 @@
|
|
|
+/**
|
|
|
+ * parameters = {
|
|
|
+ * color: <hex>,
|
|
|
+ * lineWidth: <float>,
|
|
|
+ * dashed: <boolean>,
|
|
|
+ * dashScale: <float>,
|
|
|
+ * dashSize: <float>,
|
|
|
+ * dashOffset: <float>,
|
|
|
+ * gapSize: <float>,
|
|
|
+ * resolution: <Vector2>, // to be set by renderer
|
|
|
+ * }
|
|
|
+ */
|
|
|
+
|
|
|
+import {
|
|
|
+ ShaderLib,
|
|
|
+ ShaderMaterial,
|
|
|
+ UniformsLib,
|
|
|
+ UniformsUtils,
|
|
|
+ Vector2,
|
|
|
+ Color
|
|
|
+} from 'three';
|
|
|
+
|
|
|
+let viewer
|
|
|
+UniformsLib.line = {
|
|
|
+/*
|
|
|
+ worldUnits: { value: 1 },
|
|
|
+ lineWidth: { value: 1 },
|
|
|
+ resolution: { value: new Vector2( 1, 1 ) },
|
|
|
+ dashOffset: { value: 0 },
|
|
|
+ dashScale: { value: 1 },
|
|
|
+ dashSize: { value: 1 },
|
|
|
+ gapSize: { value: 1 } // todo FIX - maybe change to totalSize
|
|
|
+ */
|
|
|
+ worldUnits: { value: 1 },
|
|
|
+ lineWidth: { value: 1 },
|
|
|
+ resolution: { value: new Vector2( 1, 1 ) },
|
|
|
+ viewportOffset: { value: new Vector2(0, 0 ) }, //left, top
|
|
|
+ devicePixelRatio:{ value:window.devicePixelRatio},
|
|
|
+ dashScale: { value: 1 },
|
|
|
+ dashSize: { value: 1 },
|
|
|
+ dashOffset: { value: 0 },
|
|
|
+ gapSize: { value: 1 },
|
|
|
+ opacity: { value: 1 },
|
|
|
+
|
|
|
+ backColor: {type:'v3', value: new Color("#ddd")},
|
|
|
+ clipDistance : { type: 'f', value: 4}, //消失距离
|
|
|
+ occlusionDistance : { type: 'f', value: 1 }, //变为backColor距离
|
|
|
+ maxClipFactor : { type: 'f', value: 1 }, //0-1
|
|
|
+ maxOcclusionFactor : { type: 'f', value: 1 }, //0-1
|
|
|
+ startClipDis: { type: 'f', value: 0 }, //开始逐渐消失的距离
|
|
|
+ startOcclusDis: { type: 'f', value: 0 }, //开始逐渐褪色的距离
|
|
|
+
|
|
|
+ depthTexture:{ value: null },
|
|
|
+ nearPlane:{value: 0.1},
|
|
|
+ farPlane:{value: 100000},
|
|
|
+ //uUseOrthographicCamera:{ type: "b", value: false },
|
|
|
+
|
|
|
+
|
|
|
+ fadeFar:{value:10},//渐变消失
|
|
|
+
|
|
|
+};
|
|
|
+
|
|
|
+ShaderLib[ 'line' ] = {
|
|
|
+
|
|
|
+ uniforms: UniformsUtils.merge( [
|
|
|
+ UniformsLib.common,
|
|
|
+ UniformsLib.fog,
|
|
|
+ UniformsLib.line
|
|
|
+ ] ),
|
|
|
+
|
|
|
+ vertexShader:
|
|
|
+ /* glsl */`
|
|
|
+ #include <common>
|
|
|
+ #include <color_pars_vertex>
|
|
|
+ #include <fog_pars_vertex>
|
|
|
+ #include <logdepthbuf_pars_vertex>
|
|
|
+ #include <clipping_planes_pars_vertex>
|
|
|
+
|
|
|
+ uniform float lineWidth;
|
|
|
+ uniform vec2 resolution;
|
|
|
+ uniform float devicePixelRatio; //add
|
|
|
+
|
|
|
+
|
|
|
+ attribute vec3 instanceStart;
|
|
|
+ attribute vec3 instanceEnd;
|
|
|
+
|
|
|
+ attribute vec3 instanceColorStart;
|
|
|
+ attribute vec3 instanceColorEnd;
|
|
|
+
|
|
|
+ #ifdef WORLD_UNITS
|
|
|
+
|
|
|
+ varying vec4 worldPos;
|
|
|
+ varying vec3 worldStart;
|
|
|
+ varying vec3 worldEnd;
|
|
|
+
|
|
|
+ #ifdef USE_DASH
|
|
|
+
|
|
|
+ varying vec2 vUv;
|
|
|
+
|
|
|
+ #endif
|
|
|
+
|
|
|
+ #else
|
|
|
+
|
|
|
+ varying vec2 vUv;
|
|
|
+
|
|
|
+ #endif
|
|
|
+
|
|
|
+ #ifdef USE_DASH
|
|
|
+
|
|
|
+ uniform float dashScale;
|
|
|
+ attribute float instanceDistanceStart;
|
|
|
+ attribute float instanceDistanceEnd;
|
|
|
+ varying float vLineDistance;
|
|
|
+
|
|
|
+ #endif
|
|
|
+
|
|
|
+ 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 = projectionMatrix[ 2 ][ 2 ]; // 3nd entry in 3th column
|
|
|
+ float b = projectionMatrix[ 3 ][ 2 ]; // 3nd 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() {
|
|
|
+
|
|
|
+ #ifdef USE_COLOR
|
|
|
+
|
|
|
+ vColor.xyz = ( position.y < 0.5 ) ? instanceColorStart : instanceColorEnd;
|
|
|
+
|
|
|
+ #endif
|
|
|
+
|
|
|
+ #ifdef USE_DASH
|
|
|
+
|
|
|
+ vLineDistance = ( position.y < 0.5 ) ? dashScale * instanceDistanceStart : dashScale * instanceDistanceEnd;
|
|
|
+ vUv = uv;
|
|
|
+
|
|
|
+ #endif
|
|
|
+
|
|
|
+ float aspect = resolution.x / resolution.y;
|
|
|
+
|
|
|
+ // camera space
|
|
|
+ vec4 start = modelViewMatrix * vec4( instanceStart, 1.0 );
|
|
|
+ vec4 end = modelViewMatrix * vec4( instanceEnd, 1.0 );
|
|
|
+
|
|
|
+ #ifdef WORLD_UNITS
|
|
|
+
|
|
|
+ worldStart = start.xyz;
|
|
|
+ worldEnd = end.xyz;
|
|
|
+
|
|
|
+ #else
|
|
|
+
|
|
|
+ vUv = uv;
|
|
|
+
|
|
|
+ #endif
|
|
|
+
|
|
|
+ // 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 = ( projectionMatrix[ 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 = projectionMatrix * start;
|
|
|
+ vec4 clipEnd = projectionMatrix * end;
|
|
|
+
|
|
|
+ // ndc space
|
|
|
+ vec3 ndcStart = clipStart.xyz / clipStart.w;
|
|
|
+ vec3 ndcEnd = clipEnd.xyz / clipEnd.w;
|
|
|
+
|
|
|
+ // direction
|
|
|
+ vec2 dir = ndcEnd.xy - ndcStart.xy;
|
|
|
+
|
|
|
+ // account for clip-space aspect ratio
|
|
|
+ dir.x *= aspect;
|
|
|
+ dir = normalize( dir );
|
|
|
+
|
|
|
+ #ifdef WORLD_UNITS
|
|
|
+
|
|
|
+ // get the offset direction as perpendicular to the view vector
|
|
|
+ vec3 worldDir = normalize( end.xyz - start.xyz );
|
|
|
+ vec3 offset;
|
|
|
+ if ( position.y < 0.5 ) {
|
|
|
+
|
|
|
+ offset = normalize( cross( start.xyz, worldDir ) );
|
|
|
+
|
|
|
+ } else {
|
|
|
+
|
|
|
+ offset = normalize( cross( end.xyz, worldDir ) );
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ // sign flip
|
|
|
+ if ( position.x < 0.0 ) offset *= - 1.0;
|
|
|
+
|
|
|
+ float forwardOffset = dot( worldDir, vec3( 0.0, 0.0, 1.0 ) );
|
|
|
+
|
|
|
+ // don't extend the line if we're rendering dashes because we
|
|
|
+ // won't be rendering the endcaps
|
|
|
+ #ifndef USE_DASH
|
|
|
+
|
|
|
+ // extend the line bounds to encompass endcaps
|
|
|
+ start.xyz += - worldDir * lineWidth * 0.5;
|
|
|
+ end.xyz += worldDir * lineWidth * 0.5;
|
|
|
+
|
|
|
+ // shift the position of the quad so it hugs the forward edge of the line
|
|
|
+ offset.xy -= dir * forwardOffset;
|
|
|
+ offset.z += 0.5;
|
|
|
+
|
|
|
+ #endif
|
|
|
+
|
|
|
+ // endcaps
|
|
|
+ if ( position.y > 1.0 || position.y < 0.0 ) {
|
|
|
+
|
|
|
+ offset.xy += dir * 2.0 * forwardOffset;
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ // 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
|
|
|
+ // segments overlap neatly
|
|
|
+ vec3 clipPose = ( position.y < 0.5 ) ? ndcStart : ndcEnd;
|
|
|
+ clip.z = clipPose.z * clip.w;
|
|
|
+
|
|
|
+ #else
|
|
|
+
|
|
|
+ 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;
|
|
|
+
|
|
|
+ // endcaps
|
|
|
+ if ( position.y < 0.0 ) {
|
|
|
+
|
|
|
+ offset += - dir;
|
|
|
+
|
|
|
+ } else if ( position.y > 1.0 ) {
|
|
|
+
|
|
|
+ offset += dir;
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ // adjust for lineWidth
|
|
|
+ offset *= lineWidth;
|
|
|
+
|
|
|
+ // adjust for clip-space to screen-space conversion // maybe resolution should be based on viewport ...
|
|
|
+ offset /= resolution.y; //* devicePixelRatio;
|
|
|
+
|
|
|
+ // select end
|
|
|
+ vec4 clip = ( position.y < 0.5 ) ? clipStart : clipEnd;
|
|
|
+
|
|
|
+ // back to clip space
|
|
|
+ offset *= clip.w;
|
|
|
+
|
|
|
+ clip.xy += offset;
|
|
|
+
|
|
|
+ #endif
|
|
|
+
|
|
|
+ gl_Position = clip;
|
|
|
+
|
|
|
+ vec4 mvPosition = ( position.y < 0.5 ) ? start : end; // this is an approximation
|
|
|
+
|
|
|
+ #include <logdepthbuf_vertex>
|
|
|
+ #include <clipping_planes_vertex>
|
|
|
+ #include <fog_vertex>
|
|
|
+
|
|
|
+ }
|
|
|
+ `,
|
|
|
+
|
|
|
+ fragmentShader:
|
|
|
+ /* glsl */`
|
|
|
+ uniform vec3 diffuse;
|
|
|
+ uniform float opacity;
|
|
|
+ uniform float lineWidth;
|
|
|
+ uniform bool uUseOrthographicCamera;
|
|
|
+ #ifdef USE_DASH
|
|
|
+
|
|
|
+ uniform float dashOffset;
|
|
|
+ uniform float dashSize;
|
|
|
+ uniform float gapSize;
|
|
|
+ #endif
|
|
|
+
|
|
|
+ //加
|
|
|
+ #if /* defined(GL_EXT_frag_depth) && */ defined(useDepth)
|
|
|
+ uniform sampler2D depthTexture;
|
|
|
+
|
|
|
+ uniform vec2 resolution;
|
|
|
+ uniform vec2 viewportOffset;
|
|
|
+ uniform vec3 backColor;
|
|
|
+ uniform float occlusionDistance;
|
|
|
+ uniform float clipDistance;
|
|
|
+ uniform float startClipDis;
|
|
|
+ uniform float startOcclusDis;
|
|
|
+ uniform float maxClipFactor;
|
|
|
+ uniform float maxOcclusionFactor;
|
|
|
+ #endif
|
|
|
+ #if defined(FadeFar)
|
|
|
+ uniform float fadeFar;
|
|
|
+ #endif
|
|
|
+
|
|
|
+
|
|
|
+ varying float vLineDistance;
|
|
|
+
|
|
|
+ #ifdef WORLD_UNITS
|
|
|
+
|
|
|
+ varying vec4 worldPos;
|
|
|
+ varying vec3 worldStart;
|
|
|
+ varying vec3 worldEnd;
|
|
|
+
|
|
|
+ #ifdef USE_DASH
|
|
|
+
|
|
|
+ varying vec2 vUv;
|
|
|
+
|
|
|
+ #endif
|
|
|
+
|
|
|
+ #else
|
|
|
+
|
|
|
+ varying vec2 vUv;
|
|
|
+
|
|
|
+ #endif
|
|
|
+
|
|
|
+ #include <common>
|
|
|
+ #include <color_pars_fragment>
|
|
|
+ #include <fog_pars_fragment>
|
|
|
+ #include <logdepthbuf_pars_fragment>
|
|
|
+ #include <clipping_planes_pars_fragment>
|
|
|
+
|
|
|
+
|
|
|
+ #if/* defined(GL_EXT_frag_depth) && */defined(useDepth) || defined(FadeFar)
|
|
|
+ uniform float nearPlane;
|
|
|
+ uniform float farPlane;
|
|
|
+ float convertToLinear(float zValue)
|
|
|
+ {
|
|
|
+ //if(uUseOrthographicCamera){
|
|
|
+ // return zValue*(farPlane-nearPlane)+nearPlane;
|
|
|
+ //}else{
|
|
|
+ float z = zValue * 2.0 - 1.0;
|
|
|
+ return (2.0 * nearPlane * farPlane) / (farPlane + nearPlane - z * (farPlane - nearPlane));
|
|
|
+ //}
|
|
|
+ }
|
|
|
+ #endif
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ 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>
|
|
|
+
|
|
|
+ #ifdef USE_DASH
|
|
|
+
|
|
|
+ if ( vUv.y < - 1.0 || vUv.y > 1.0 ) discard; // discard endcaps
|
|
|
+
|
|
|
+
|
|
|
+ bool unvisible = mod( vLineDistance + dashOffset, dashSize + gapSize ) > dashSize;
|
|
|
+ //加
|
|
|
+ #ifdef DASH_with_depth
|
|
|
+
|
|
|
+ #else
|
|
|
+ if (unvisible) discard; // todo - FIX
|
|
|
+
|
|
|
+ #endif
|
|
|
+ #endif
|
|
|
+
|
|
|
+
|
|
|
+ float alpha = opacity;
|
|
|
+
|
|
|
+ #ifdef WORLD_UNITS
|
|
|
+
|
|
|
+ // 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 );
|
|
|
+
|
|
|
+ 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
|
|
|
+
|
|
|
+ #ifdef USE_ALPHA_TO_COVERAGE
|
|
|
+
|
|
|
+ float dnorm = fwidth( norm );
|
|
|
+ alpha = 1.0 - smoothstep( 0.5 - dnorm, 0.5 + dnorm, norm );
|
|
|
+
|
|
|
+ #else
|
|
|
+
|
|
|
+ if ( norm > 0.5 ) {
|
|
|
+
|
|
|
+ discard;
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ #endif
|
|
|
+
|
|
|
+ #endif
|
|
|
+
|
|
|
+ #else
|
|
|
+
|
|
|
+ #ifdef USE_ALPHA_TO_COVERAGE
|
|
|
+
|
|
|
+ // artifacts appear on some hardware if a derivative is taken within a conditional
|
|
|
+ float a = vUv.x;
|
|
|
+ float b = ( vUv.y > 0.0 ) ? vUv.y - 1.0 : vUv.y + 1.0;
|
|
|
+ float len2 = a * a + b * b;
|
|
|
+ float dlen = fwidth( len2 );
|
|
|
+
|
|
|
+ if ( abs( vUv.y ) > 1.0 ) {
|
|
|
+
|
|
|
+ alpha = 1.0 - smoothstep( 1.0 - dlen, 1.0 + dlen, len2 );
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ #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
|
|
|
+
|
|
|
+ #endif
|
|
|
+
|
|
|
+ vec4 diffuseColor = vec4( diffuse, alpha );
|
|
|
+
|
|
|
+ //加
|
|
|
+ #if /* defined(GL_EXT_frag_depth) && */ defined(useDepth) || defined(FadeFar)
|
|
|
+
|
|
|
+ float fragDepth = convertToLinear(gl_FragCoord.z);
|
|
|
+ #if defined(FadeFar)
|
|
|
+ float fadeOutFar = fadeFar * 1.3; //完全消失距离
|
|
|
+ if(fragDepth > fadeOutFar){
|
|
|
+ discard;
|
|
|
+ }else if(fragDepth > fadeFar){
|
|
|
+ alpha *= (fadeOutFar - fragDepth) / (fadeOutFar - fadeFar);
|
|
|
+ diffuseColor.a = alpha;
|
|
|
+ }
|
|
|
+ #endif
|
|
|
+
|
|
|
+ #if /* defined(GL_EXT_frag_depth) && */defined(useDepth)
|
|
|
+
|
|
|
+ float mixFactor = 0.0;
|
|
|
+ float clipFactor = 0.0;
|
|
|
+ //gl_FragCoord大小为 viewport client大小
|
|
|
+ vec2 depthTxtCoords = vec2(gl_FragCoord.x - viewportOffset.x, gl_FragCoord.y - viewportOffset.y) / resolution;
|
|
|
+
|
|
|
+ float textureDepth = convertToLinear(texture2D(depthTexture, depthTxtCoords).r);
|
|
|
+
|
|
|
+ float delta = fragDepth - textureDepth;
|
|
|
+
|
|
|
+ if (delta > 0.0)
|
|
|
+ {
|
|
|
+
|
|
|
+ /* mixFactor = clamp(delta / occlusionDistance, 0.0, maxOcclusionFactor);
|
|
|
+ clipFactor = clamp(delta / clipDistance, 0.0, maxClipFactor); */
|
|
|
+ mixFactor = clamp((delta - startOcclusDis) / (occlusionDistance - startOcclusDis), 0.0, maxOcclusionFactor);
|
|
|
+ clipFactor = clamp((delta - startClipDis) / (clipDistance - startClipDis), 0.0, maxClipFactor);
|
|
|
+ }
|
|
|
+
|
|
|
+ if (clipFactor == 1.0)
|
|
|
+ {
|
|
|
+ discard;
|
|
|
+ }
|
|
|
+
|
|
|
+ vec4 backColor_ = vec4(backColor, alpha /* opacity */); //vec4(0.8,0.8,0.8, 0.8*opacity);
|
|
|
+
|
|
|
+ #ifdef DASH_with_depth
|
|
|
+ // 只在被遮住的部分显示虚线, 所以若同时是虚线不可见部分和被遮住时, a为0
|
|
|
+ if(unvisible) backColor_.a = 0.0;
|
|
|
+ #endif
|
|
|
+
|
|
|
+ //vec4 diffuseColor = vec4(mix(diffuse, backColor_, mixFactor), opacity*(1.0 - clipFactor));
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ diffuseColor = mix(diffuseColor, backColor_ , mixFactor);
|
|
|
+
|
|
|
+
|
|
|
+ diffuseColor.a *= (1.0 - clipFactor);
|
|
|
+
|
|
|
+ #endif
|
|
|
+ #endif
|
|
|
+
|
|
|
+ #include <logdepthbuf_fragment>
|
|
|
+ #include <color_fragment>
|
|
|
+
|
|
|
+ //gl_FragColor = vec4( diffuseColor.rgb, alpha );
|
|
|
+ gl_FragColor = diffuseColor;
|
|
|
+
|
|
|
+ #include <tonemapping_fragment>
|
|
|
+ #include <colorspace_fragment>
|
|
|
+ #include <fog_fragment>
|
|
|
+ #include <premultiplied_alpha_fragment>
|
|
|
+
|
|
|
+
|
|
|
+ }
|
|
|
+ `
|
|
|
+};
|
|
|
+
|
|
|
+class LineMaterial extends ShaderMaterial {
|
|
|
+
|
|
|
+ constructor( parameters ) {
|
|
|
+
|
|
|
+ let [vs,fs] = [ShaderLib[ 'line' ].vertexShader, ShaderLib[ 'line' ].fragmentShader]
|
|
|
+
|
|
|
+ super( {
|
|
|
+
|
|
|
+ type: 'LineMaterial',
|
|
|
+
|
|
|
+ uniforms: UniformsUtils.clone( ShaderLib[ 'line' ].uniforms ),
|
|
|
+
|
|
|
+ vertexShader: vs,
|
|
|
+ fragmentShader: fs,
|
|
|
+
|
|
|
+ clipping: true // required for clipping support
|
|
|
+
|
|
|
+ } );
|
|
|
+
|
|
|
+ this.isLineMaterial = true;
|
|
|
+ this.lineWidth_ = 0
|
|
|
+ this.supportExtDepth = parameters.supportExtDepth
|
|
|
+ this.depthTestWhenPick = false //pick时是否识别点云等
|
|
|
+
|
|
|
+
|
|
|
+ if(parameters.color){
|
|
|
+ this.color = new Color(parameters.color)
|
|
|
+ }
|
|
|
+ if(parameters.backColor){
|
|
|
+ this.uniforms.backColor.value = new Color(parameters.backColor)
|
|
|
+ }
|
|
|
+ if(parameters.clipDistance){
|
|
|
+ this.uniforms.clipDistance.value = parameters.clipDistance
|
|
|
+ }
|
|
|
+ if(parameters.occlusionDistance){
|
|
|
+ this.uniforms.occlusionDistance.value = parameters.occlusionDistance
|
|
|
+ }
|
|
|
+ if(parameters.maxClipFactor){
|
|
|
+ this.uniforms.maxClipFactor.value = parameters.maxClipFactor
|
|
|
+ }
|
|
|
+
|
|
|
+ Object.defineProperties( this, {
|
|
|
+
|
|
|
+ color: {
|
|
|
+
|
|
|
+ enumerable: true,
|
|
|
+
|
|
|
+ get: function () {
|
|
|
+
|
|
|
+ return this.uniforms.diffuse.value;
|
|
|
+
|
|
|
+ },
|
|
|
+
|
|
|
+ set: function ( value ) {
|
|
|
+
|
|
|
+ this.uniforms.diffuse.value = value;
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ },
|
|
|
+
|
|
|
+ worldUnits: {
|
|
|
+
|
|
|
+ enumerable: true,
|
|
|
+
|
|
|
+ get: function () {
|
|
|
+
|
|
|
+ return 'WORLD_UNITS' in this.defines;
|
|
|
+
|
|
|
+ },
|
|
|
+
|
|
|
+ set: function ( value ) {
|
|
|
+
|
|
|
+ if ( value === true ) {
|
|
|
+
|
|
|
+ this.defines.WORLD_UNITS = '';
|
|
|
+
|
|
|
+ } else {
|
|
|
+
|
|
|
+ delete this.defines.WORLD_UNITS;
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ },
|
|
|
+
|
|
|
+ lineWidth: {
|
|
|
+
|
|
|
+ enumerable: true,
|
|
|
+
|
|
|
+ get: function () {
|
|
|
+
|
|
|
+ return this.lineWidth_; //this.uniforms.lineWidth.value;
|
|
|
+
|
|
|
+ },
|
|
|
+
|
|
|
+ set: function ( value ) {
|
|
|
+
|
|
|
+ this.uniforms.lineWidth.value = value //* pixelRatio_; //pixelRatio_暂时都是1,就不写了
|
|
|
+ this.lineWidth_ = value
|
|
|
+ }
|
|
|
+
|
|
|
+ },
|
|
|
+
|
|
|
+ dashed: {
|
|
|
+
|
|
|
+ enumerable: true,
|
|
|
+
|
|
|
+ get: function () {
|
|
|
+
|
|
|
+ return Boolean( 'USE_DASH' in this.defines );
|
|
|
+
|
|
|
+ },
|
|
|
+
|
|
|
+ set( value ) {
|
|
|
+
|
|
|
+ if ( Boolean( value ) !== Boolean( 'USE_DASH' in this.defines ) ) {
|
|
|
+
|
|
|
+ this.needsUpdate = true;
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ if ( value === true ) {
|
|
|
+
|
|
|
+ this.defines.USE_DASH = '';
|
|
|
+
|
|
|
+ } else {
|
|
|
+
|
|
|
+ delete this.defines.USE_DASH;
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ },
|
|
|
+
|
|
|
+ dashScale: {
|
|
|
+
|
|
|
+ enumerable: true,
|
|
|
+
|
|
|
+ get: function () {
|
|
|
+
|
|
|
+ return this.uniforms.dashScale.value;
|
|
|
+
|
|
|
+ },
|
|
|
+
|
|
|
+ set: function ( value ) {
|
|
|
+
|
|
|
+ this.uniforms.dashScale.value = value;
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ },
|
|
|
+
|
|
|
+ dashSize: {
|
|
|
+
|
|
|
+ enumerable: true,
|
|
|
+
|
|
|
+ get: function () {
|
|
|
+
|
|
|
+ return this.uniforms.dashSize.value;
|
|
|
+
|
|
|
+ },
|
|
|
+
|
|
|
+ set: function ( value ) {
|
|
|
+
|
|
|
+ this.uniforms.dashSize.value = value;
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ },
|
|
|
+
|
|
|
+ dashOffset: {
|
|
|
+
|
|
|
+ enumerable: true,
|
|
|
+
|
|
|
+ get: function () {
|
|
|
+
|
|
|
+ return this.uniforms.dashOffset.value;
|
|
|
+
|
|
|
+ },
|
|
|
+
|
|
|
+ set: function ( value ) {
|
|
|
+
|
|
|
+ this.uniforms.dashOffset.value = value;
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ },
|
|
|
+
|
|
|
+ gapSize: {
|
|
|
+
|
|
|
+ enumerable: true,
|
|
|
+
|
|
|
+ get: function () {
|
|
|
+
|
|
|
+ return this.uniforms.gapSize.value;
|
|
|
+
|
|
|
+ },
|
|
|
+
|
|
|
+ set: function ( value ) {
|
|
|
+
|
|
|
+ this.uniforms.gapSize.value = value;
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ },
|
|
|
+
|
|
|
+ opacity: {
|
|
|
+
|
|
|
+ enumerable: true,
|
|
|
+
|
|
|
+ get: function () {
|
|
|
+
|
|
|
+ return this.uniforms.opacity.value;
|
|
|
+
|
|
|
+ },
|
|
|
+
|
|
|
+ set: function ( value ) {
|
|
|
+
|
|
|
+ this.uniforms.opacity.value = value;
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ },
|
|
|
+
|
|
|
+ resolution: {
|
|
|
+
|
|
|
+ enumerable: true,
|
|
|
+
|
|
|
+ get: function () {
|
|
|
+
|
|
|
+ return this.uniforms.resolution.value;
|
|
|
+
|
|
|
+ },
|
|
|
+
|
|
|
+ set: function ( value ) {
|
|
|
+
|
|
|
+ this.uniforms.resolution.value.copy( value );
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ },
|
|
|
+
|
|
|
+ alphaToCoverage: {
|
|
|
+
|
|
|
+ enumerable: true,
|
|
|
+
|
|
|
+ get: function () {
|
|
|
+
|
|
|
+ return Boolean( 'USE_ALPHA_TO_COVERAGE' in this.defines );
|
|
|
+
|
|
|
+ },
|
|
|
+
|
|
|
+ set: function ( value ) {
|
|
|
+
|
|
|
+ if ( Boolean( value ) !== Boolean( 'USE_ALPHA_TO_COVERAGE' in this.defines ) ) {
|
|
|
+
|
|
|
+ this.needsUpdate = true;
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ if ( value === true ) {
|
|
|
+
|
|
|
+ this.defines.USE_ALPHA_TO_COVERAGE = '';
|
|
|
+ this.extensions.derivatives = true;
|
|
|
+
|
|
|
+ } else {
|
|
|
+
|
|
|
+ delete this.defines.USE_ALPHA_TO_COVERAGE;
|
|
|
+ this.extensions.derivatives = false;
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ },
|
|
|
+
|
|
|
+
|
|
|
+ dashWithDepth:{//add
|
|
|
+ enumerable: true,
|
|
|
+
|
|
|
+ get: function () {
|
|
|
+
|
|
|
+ return 'DASH_with_depth' in this.defines
|
|
|
+
|
|
|
+ },
|
|
|
+
|
|
|
+ set: function ( value ) {
|
|
|
+
|
|
|
+ value = value && !!this.supportExtDepth
|
|
|
+
|
|
|
+ if(value != this.dashWithDepth){
|
|
|
+ if(value){
|
|
|
+ this.defines.DASH_with_depth = ''
|
|
|
+ }else{
|
|
|
+ delete this.defines.DASH_with_depth
|
|
|
+ }
|
|
|
+ this.needsUpdate = true
|
|
|
+ }
|
|
|
+ }
|
|
|
+ },
|
|
|
+
|
|
|
+ } );
|
|
|
+
|
|
|
+
|
|
|
+ this.events = {
|
|
|
+ setSize:(e)=>{//如果出现横条状的异常,往往是viewportOffset出错 //地图不需要
|
|
|
+ let viewport = e.viewport
|
|
|
+ //console.log(viewport.name, viewport.resolution2)
|
|
|
+ this.uniforms.resolution.value.copy(viewport.resolution2)
|
|
|
+ //this.uniforms.devicePixelRatio.value = window.devicePixelRatio
|
|
|
+ //this.lineWidth = this.lineWidth_ //update
|
|
|
+ if(!this.realUseDepth || !e.viewport)return
|
|
|
+ let viewportOffset = viewport.offset || new THREE.Vector2()
|
|
|
+ this.uniforms.viewportOffset.value.copy(viewportOffset)
|
|
|
+
|
|
|
+ },
|
|
|
+ render:(e)=>{//before render 如果有大于两个viewport的话,不同viewport用不同的depthTex
|
|
|
+ this.useDepth && this.updateDepthParams(e)
|
|
|
+
|
|
|
+ var viewport = e.viewport || viewer.mainViewport;
|
|
|
+ if(viewport != this.lastViewport){ //当mapViewer要渲染测量线后,就需要变viewport
|
|
|
+ this.events.setSize({viewport})
|
|
|
+ }
|
|
|
+ this.lastViewport = viewport
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ this.setValues( parameters );
|
|
|
+
|
|
|
+ let viewport = viewer.mainViewport;
|
|
|
+ this.events.setSize({viewport})
|
|
|
+
|
|
|
+ viewer.addEventListener('resize', this.events.setSize)
|
|
|
+ viewer.addEventListener("render.begin", this.events.render)
|
|
|
+
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ get useDepth(){
|
|
|
+ return this.useDepth_
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ set useDepth(value){
|
|
|
+ value = value && this.supportExtDepth //如果不支持 EXT_DEPTH 的话会失效
|
|
|
+
|
|
|
+ if(this.useDepth_ != value){
|
|
|
+
|
|
|
+ this.setRealDepth(value)
|
|
|
+ this.useDepth_ = value
|
|
|
+
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ setRealDepth(useDepth, viewport){//确实使用到depthTex
|
|
|
+ if(!this.realUseDepth != !useDepth){
|
|
|
+ if(useDepth ){
|
|
|
+ this.defines.useDepth = ''
|
|
|
+ }else{
|
|
|
+ delete this.defines.useDepth
|
|
|
+ }
|
|
|
+ this.realUseDepth = useDepth
|
|
|
+ //if(this.autoDepthTest)this.depthWrite = this.depthTest = !useDepth //如果useDepth = false,使用原始的depthTest
|
|
|
+ this.needsUpdate = true
|
|
|
+ if(!viewport)viewport = viewer.mainViewport //暂时这么设置
|
|
|
+ useDepth && this.events.setSize({viewport})
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ set fadeFar(far){
|
|
|
+ let needsUpdate = (!this.fadeFar ) != (!far) //null为全部范围可见
|
|
|
+ //console.log('fadeFar needsUpdate', needsUpdate)
|
|
|
+ if(far){
|
|
|
+ this.defines.FadeFar = true
|
|
|
+ this.uniforms.fadeFar.value = far
|
|
|
+ }else{
|
|
|
+ delete this.defines.FadeFar
|
|
|
+ }
|
|
|
+ needsUpdate && (this.needsUpdate = true)
|
|
|
+ }
|
|
|
+
|
|
|
+ get fadeFar(){
|
|
|
+ return 'FadeFar' in this.defines && this.uniforms.fadeFar.value
|
|
|
+ }
|
|
|
+ updateDepthParams(e={}){//主要用于点云遮住mesh
|
|
|
+ var viewport = e.viewport || viewer.mainViewport;
|
|
|
+ var camera = viewport.camera;
|
|
|
+
|
|
|
+ let hasDepth = this.useDepth && camera.isPerspectiveCamera && viewer.collider.depthTarget
|
|
|
+
|
|
|
+ this.setRealDepth(hasDepth, viewport)
|
|
|
+
|
|
|
+ if(hasDepth){
|
|
|
+ this.uniforms.depthTexture.value = viewer.collider.depthTarget.depthTexture //其实只赋值一次就行
|
|
|
+ }
|
|
|
+ //hasDepth or FadeFar:
|
|
|
+ this.uniforms.nearPlane.value = camera.near;
|
|
|
+ this.uniforms.farPlane.value = camera.far;
|
|
|
+ //this.uniforms.uUseOrthographicCamera.value = !camera.isPerspectiveCamera
|
|
|
+ }
|
|
|
+
|
|
|
+}
|
|
|
+LineMaterial.registerViewer = function(viewer_){viewer = viewer_}
|
|
|
+export { LineMaterial };
|