ParametricGeometry.js 2.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135
  1. /**
  2. * Parametric Surfaces Geometry
  3. * based on the brilliant article by @prideout https://prideout.net/blog/old/blog/index.html@p=44.html
  4. */
  5. import {
  6. BufferGeometry,
  7. Float32BufferAttribute,
  8. Vector3
  9. } from '../../../build/three.module.js';
  10. class ParametricGeometry extends BufferGeometry {
  11. constructor( func = ( u, v, target ) => target.set( u, v, Math.cos( u ) * Math.sin( v ) ), slices = 8, stacks = 8 ) {
  12. super();
  13. this.type = 'ParametricGeometry';
  14. this.parameters = {
  15. func: func,
  16. slices: slices,
  17. stacks: stacks
  18. };
  19. // buffers
  20. const indices = [];
  21. const vertices = [];
  22. const normals = [];
  23. const uvs = [];
  24. const EPS = 0.00001;
  25. const normal = new Vector3();
  26. const p0 = new Vector3(), p1 = new Vector3();
  27. const pu = new Vector3(), pv = new Vector3();
  28. if ( func.length < 3 ) {
  29. console.error( 'THREE.ParametricGeometry: Function must now modify a Vector3 as third parameter.' );
  30. }
  31. // generate vertices, normals and uvs
  32. const sliceCount = slices + 1;
  33. for ( let i = 0; i <= stacks; i ++ ) {
  34. const v = i / stacks;
  35. for ( let j = 0; j <= slices; j ++ ) {
  36. const u = j / slices;
  37. // vertex
  38. func( u, v, p0 );
  39. vertices.push( p0.x, p0.y, p0.z );
  40. // normal
  41. // approximate tangent vectors via finite differences
  42. if ( u - EPS >= 0 ) {
  43. func( u - EPS, v, p1 );
  44. pu.subVectors( p0, p1 );
  45. } else {
  46. func( u + EPS, v, p1 );
  47. pu.subVectors( p1, p0 );
  48. }
  49. if ( v - EPS >= 0 ) {
  50. func( u, v - EPS, p1 );
  51. pv.subVectors( p0, p1 );
  52. } else {
  53. func( u, v + EPS, p1 );
  54. pv.subVectors( p1, p0 );
  55. }
  56. // cross product of tangent vectors returns surface normal
  57. normal.crossVectors( pu, pv ).normalize();
  58. normals.push( normal.x, normal.y, normal.z );
  59. // uv
  60. uvs.push( u, v );
  61. }
  62. }
  63. // generate indices
  64. for ( let i = 0; i < stacks; i ++ ) {
  65. for ( let j = 0; j < slices; j ++ ) {
  66. const a = i * sliceCount + j;
  67. const b = i * sliceCount + j + 1;
  68. const c = ( i + 1 ) * sliceCount + j + 1;
  69. const d = ( i + 1 ) * sliceCount + j;
  70. // faces one and two
  71. indices.push( a, b, d );
  72. indices.push( b, c, d );
  73. }
  74. }
  75. // build geometry
  76. this.setIndex( indices );
  77. this.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) );
  78. this.setAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) );
  79. this.setAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) );
  80. }
  81. }
  82. export { ParametricGeometry };