LineMaterial.js 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294
  1. /**
  2. * @author WestLangley / http://github.com/WestLangley
  3. *
  4. * parameters = {
  5. * color: <hex>,
  6. * linewidth: <float>,
  7. * resolution: <Vector2>, // to be set by renderer
  8. * }
  9. */
  10. THREE.UniformsLib.line = {
  11. linewidth: { value: 1 },
  12. resolution: { value: new THREE.Vector2( 1, 1 ) }
  13. };
  14. THREE.ShaderLib[ 'line' ] = {
  15. uniforms: THREE.UniformsUtils.merge( [
  16. THREE.UniformsLib.common,
  17. THREE.UniformsLib.fog,
  18. THREE.UniformsLib.line
  19. ] ),
  20. vertexShader:
  21. `
  22. #include <common>
  23. #include <color_pars_vertex>
  24. #include <fog_pars_vertex>
  25. #include <logdepthbuf_pars_vertex>
  26. #include <clipping_planes_pars_vertex>
  27. uniform float linewidth;
  28. uniform vec2 resolution;
  29. attribute vec3 instanceStart;
  30. attribute vec3 instanceEnd;
  31. attribute vec3 instanceColorStart;
  32. attribute vec3 instanceColorEnd;
  33. varying vec2 vUv;
  34. void trimSegment( const in vec4 start, inout vec4 end ) {
  35. // trim end segment so it terminates between the camera plane and the near plane
  36. // conservative estimate of the near plane
  37. float a = projectionMatrix[ 2 ][ 2 ]; // 3nd entry in 3th column
  38. float b = projectionMatrix[ 3 ][ 2 ]; // 3nd entry in 4th column
  39. float nearEstimate = - 0.5 * b / a;
  40. float alpha = ( nearEstimate - start.z ) / ( end.z - start.z );
  41. end.xyz = mix( start.xyz, end.xyz, alpha );
  42. }
  43. void main() {
  44. #ifdef USE_COLOR
  45. vColor.xyz = ( position.y < 0.5 ) ? instanceColorStart : instanceColorEnd;
  46. #endif
  47. float aspect = resolution.x / resolution.y;
  48. vUv = uv;
  49. // camera space
  50. vec4 start = modelViewMatrix * vec4( instanceStart, 1.0 );
  51. vec4 end = modelViewMatrix * vec4( instanceEnd, 1.0 );
  52. // special case for perspective projection, and segments that terminate either in, or behind, the camera plane
  53. // clearly the gpu firmware has a way of addressing this issue when projecting into ndc space
  54. // but we need to perform ndc-space calculations in the shader, so we must address this issue directly
  55. // perhaps there is a more elegant solution -- WestLangley
  56. bool perspective = ( projectionMatrix[ 2 ][ 3 ] == - 1.0 ); // 4th entry in the 3rd column
  57. if ( perspective ) {
  58. if ( start.z < 0.0 && end.z >= 0.0 ) {
  59. trimSegment( start, end );
  60. } else if ( end.z < 0.0 && start.z >= 0.0 ) {
  61. trimSegment( end, start );
  62. }
  63. }
  64. // clip space
  65. vec4 clipStart = projectionMatrix * start;
  66. vec4 clipEnd = projectionMatrix * end;
  67. // ndc space
  68. vec2 ndcStart = clipStart.xy / clipStart.w;
  69. vec2 ndcEnd = clipEnd.xy / clipEnd.w;
  70. // direction
  71. vec2 dir = ndcEnd - ndcStart;
  72. // account for clip-space aspect ratio
  73. dir.x *= aspect;
  74. dir = normalize( dir );
  75. // perpendicular to dir
  76. vec2 offset = vec2( dir.y, - dir.x );
  77. // undo aspect ratio adjustment
  78. dir.x /= aspect;
  79. offset.x /= aspect;
  80. // sign flip
  81. if ( position.x < 0.0 ) offset *= - 1.0;
  82. // endcaps
  83. if ( position.y < 0.0 ) {
  84. offset += - dir;
  85. } else if ( position.y > 1.0 ) {
  86. offset += dir;
  87. }
  88. // adjust for linewidth
  89. offset *= linewidth;
  90. // adjust for clip-space to screen-space conversion // maybe resolution should be based on viewport ...
  91. offset /= resolution.y;
  92. // select end
  93. vec4 clip = ( position.y < 0.5 ) ? clipStart : clipEnd;
  94. // back to clip space
  95. offset *= clip.w;
  96. clip.xy += offset;
  97. gl_Position = clip;
  98. #include <logdepthbuf_vertex>
  99. #include <worldpos_vertex>
  100. #include <clipping_planes_vertex>
  101. #include <fog_vertex>
  102. }
  103. `,
  104. fragmentShader:
  105. `
  106. uniform vec3 diffuse;
  107. uniform float opacity;
  108. #include <common>
  109. #include <color_pars_fragment>
  110. #include <fog_pars_fragment>
  111. #include <logdepthbuf_pars_fragment>
  112. #include <clipping_planes_pars_fragment>
  113. varying vec2 vUv;
  114. void main() {
  115. #include <clipping_planes_fragment>
  116. if ( vUv.y < 0.5 || vUv.y > 0.5 ) {
  117. float a = vUv.x - 0.5;
  118. float b = vUv.y - 0.5;
  119. float len2 = a * a + b * b;
  120. if ( len2 > 0.25 ) discard;
  121. }
  122. vec4 diffuseColor = vec4( diffuse, opacity );
  123. #include <logdepthbuf_fragment>
  124. #include <color_fragment>
  125. gl_FragColor = vec4( diffuseColor.rgb, diffuseColor.a );
  126. #include <premultiplied_alpha_fragment>
  127. #include <tonemapping_fragment>
  128. #include <encodings_fragment>
  129. #include <fog_fragment>
  130. }
  131. `
  132. };
  133. THREE.LineMaterial = function ( parameters ) {
  134. THREE.ShaderMaterial.call( this, {
  135. type: 'LineMaterial',
  136. uniforms: THREE.UniformsUtils.clone( THREE.ShaderLib[ 'line' ].uniforms ),
  137. vertexShader: THREE.ShaderLib[ 'line' ].vertexShader,
  138. fragmentShader: THREE.ShaderLib[ 'line' ].fragmentShader
  139. } );
  140. Object.defineProperties( this, {
  141. color: {
  142. enumerable: true,
  143. get: function () {
  144. return this.uniforms.diffuse.value;
  145. },
  146. set: function ( value ) {
  147. this.uniforms.diffuse.value = value;
  148. }
  149. },
  150. linewidth: {
  151. enumerable: true,
  152. get: function () {
  153. return this.uniforms.linewidth.value;
  154. },
  155. set: function ( value ) {
  156. this.uniforms.linewidth.value = value;
  157. }
  158. },
  159. resolution: {
  160. enumerable: true,
  161. get: function () {
  162. return this.uniforms.resolution.value;
  163. },
  164. set: function ( value ) {
  165. this.uniforms.resolution.value.copy( value );
  166. }
  167. }
  168. } );
  169. this.setValues( parameters );
  170. };
  171. THREE.LineMaterial.prototype = Object.create( THREE.ShaderMaterial.prototype );
  172. THREE.LineMaterial.prototype.constructor = THREE.LineMaterial;
  173. THREE.LineMaterial.prototype.isLineMaterial = true;
  174. THREE.LineMaterial.prototype.copy = function ( source ) {
  175. THREE.ShaderMaterial.prototype.copy.call( this, source );
  176. this.color.copy( source.color );
  177. this.linewidth = source.linewidth;
  178. this.resolution = source.resolution;
  179. // todo
  180. return this;
  181. };