ParametricGeometry.js 2.5 KB

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