如何在 Three.js 中从 3D 点创建 3D 三次贝塞尔曲线三角形?

2023-12-08

下列的这个话题,我试图生成一个 3D 弯曲三角形作为 NURBS 曲面,但我不明白如何设置 3D 点来做到这一点。

这是当前的实现:

var edges = this.getEdges(), // An edge is a line following 4 dots as a bezier curve.
    dots = self.getDotsFromEdges(edges), // Get all dots in order for building the surface.

    ctrlPoints = [ // Is generated only once before, but copy-pasted here for this sample code.
        [
            new THREE.Vector4(0, 0, 0, 1),
            new THREE.Vector4(0, 0, 0, 1),
            new THREE.Vector4(0, 0, 0, 1),
            new THREE.Vector4(0, 0, 0, 1)
        ],
        [
            new THREE.Vector4(0, 0, 0, 1),
            new THREE.Vector4(0, 0, 0, 1),
            new THREE.Vector4(0, 0, 0, 1),
            new THREE.Vector4(0, 0, 0, 1)
        ],
        [
            new THREE.Vector4(0, 0, 0, 1),
            new THREE.Vector4(0, 0, 0, 1),
            new THREE.Vector4(0, 0, 0, 1),
            new THREE.Vector4(0, 0, 0, 1)
        ]
    ],

    nc,
    deg1 = ctrlPoints.length - 1,
    knots1 = [],
    deg2 = 3,                           // Cubic bezier
    knots2 = [0, 0, 0, 0, 1, 1, 1, 1],  // <-
    cpts,
    nurbs ;

nc = ctrlPoints.length ;
while (nc-- > 0) knots1.push(0) ;
nc = ctrlPoints.length ;
while (nc-- > 0) knots1.push(1) ;


// The following seems to be the problem... :

cpts = ctrlPoints[0] ;
cpts[0].set(dots[0].x, dots[0].y, dots[0].z, 1) ;
cpts[1].set(dots[1].x, dots[1].y, dots[1].z, 1) ;
cpts[2].set(dots[2].x, dots[2].y, dots[2].z, 1) ;
cpts[3].set(dots[3].x, dots[3].y, dots[3].z, 1) ;

cpts = ctrlPoints[1] ;
cpts[0].set(dots[6].x, dots[6].y, dots[6].z, 1) ;
cpts[1].set(dots[5].x, dots[5].y, dots[5].z, 1) ;
cpts[2].set(dots[4].x, dots[4].y, dots[4].z, 1) ;
cpts[3].set(dots[3].x, dots[3].y, dots[3].z, 1) ;

cpts = ctrlPoints[2] ;
cpts[0].set(dots[6].x, dots[6].y, dots[6].z, 1) ;
cpts[1].set(dots[7].x, dots[7].y, dots[7].z, 1) ;
cpts[2].set(dots[8].x, dots[8].y, dots[8].z, 1) ;
cpts[3].set(dots[0].x, dots[0].y, dots[0].z, 1) ;



nurbs = new THREE.NURBSSurface(deg1, deg2, knots1, knots2, ctrlPoints) ;

this.mesh.geometry.dispose() ;
this.mesh.geometry = new THREE.ParametricBufferGeometry(function(u, v, target) {
    return nurbs.getPoint(u, v, target) ;
}, 10, 10) ;

这是结果:

enter image description here

我尝试了许多不同的设置,但找不到任何有效的设置。

注:白点为边缘末端;红点是贝塞尔曲线的中点。
Note 2: dots[0]指的是点0在示例图片中,等等。

这是工作片段(和小提琴版本here)

const
		PI = Math.PI,
    sin = Math.sin,
    cos = Math.cos,
		W = 480,
    H = 400,
    log = console.log,
    DISTANCE = 100 ;

let renderer = new THREE.WebGLRenderer({
      canvas : document.querySelector('canvas'),
      antialias : true,
      alpha : true
    }),
    camera = new THREE.PerspectiveCamera(25, W/H),
    scene = new THREE.Scene(),
    center = new THREE.Vector3(0, 0, 0),

		pts = [] ;

renderer.setClearColor(0x000000, 0) ;

renderer.setSize(W, H) ;
// camera.position.set(-48, 32, 80) ;
camera.position.set(0, 0, DISTANCE) ;
camera.lookAt(center) ;

function createPoint(x, y, z, color) {
		let pt = new THREE.Mesh(
      new THREE.SphereGeometry(1, 10, 10),
      new THREE.MeshBasicMaterial({ color })
    ) ;
    pt.position.set(x, y, z) ;
    pt.x = x ;
    pt.y = y ;
    pt.z = z ;
    pts.push(pt) ;
    
    scene.add(pt) ;
}

function createEdge(pt1, pt2, pt3, pt4) {
		let curve = new THREE.CubicBezierCurve3(
          pt1.position,
          pt2.position,
          pt3.position,
          pt4.position
        ),
    		mesh = new THREE.Mesh(
          new THREE.TubeGeometry(curve, 8, 0.5, 8, false),
          new THREE.MeshBasicMaterial({
            color : 0x203040
          })
        ) ;
        
    scene.add(mesh) ;
}

///////////////////////////////////////////////

// POINTS //
createPoint(-16, -8, 0, 0xcc0000) ; // RED
createPoint(-8, -12, 0, 0x999999) ;
createPoint(8, -12, 0, 0x888888) ;
createPoint(16, -8, 0, 0x00cc00) ; // GREEN
createPoint(12, -6, -8, 0x777777) ;
createPoint(8, 6, -8, 0x666666) ;
createPoint(0, 12, 0, 0x0000cc) ; // BLUE
createPoint(-8, 6, -8, 0x555555) ;
createPoint(-12, -6, -8, 0x444444) ;

// EDGES //
createEdge(pts[0], pts[1], pts[2], pts[3]) ;
createEdge(pts[3], pts[4], pts[5], pts[6]) ;
createEdge(pts[6], pts[7], pts[8], pts[0]) ;

// SURFACE //
let ctrlPoints = [
        [
            new THREE.Vector4(pts[0].x, pts[0].y, pts[0].z, 1),
            new THREE.Vector4(pts[1].x, pts[1].y, pts[1].z, 1),
            new THREE.Vector4(pts[2].x, pts[2].y, pts[2].z, 1),
            new THREE.Vector4(pts[3].x, pts[3].y, pts[3].z, 1)
        ],
        [
            new THREE.Vector4(pts[6].x, pts[6].y, pts[6].z, 1),
            new THREE.Vector4(pts[5].x, pts[5].y, pts[5].z, 1),
            new THREE.Vector4(pts[4].x, pts[4].y, pts[4].z, 1),
            new THREE.Vector4(pts[3].x, pts[3].y, pts[3].z, 1)
        ],
        [
            new THREE.Vector4(pts[6].x, pts[6].y, pts[6].z, 1),
            new THREE.Vector4(pts[7].x, pts[7].y, pts[7].z, 1),
            new THREE.Vector4(pts[8].x, pts[8].y, pts[8].z, 1),
            new THREE.Vector4(pts[0].x, pts[0].y, pts[0].z, 1)
        ]
    ],

    nc,
    deg1 = ctrlPoints.length - 1,
    knots1 = [],
    deg2 = 3,                           // Cubic bezier
    knots2 = [0, 0, 0, 0, 1, 1, 1, 1],  // <-
    cpts,
    nurbs ;

nc = ctrlPoints.length ;
while (nc-- > 0) knots1.push(0) ;
nc = ctrlPoints.length ;
while (nc-- > 0) knots1.push(1) ;

nurbs = new THREE.NURBSSurface(deg1, deg2, knots1, knots2, ctrlPoints) ;

let surfaceMesh = new THREE.Mesh(
    new THREE.ParametricBufferGeometry(function(u, v, target) {
        return nurbs.getPoint(u, v, target) ;
    }, 10, 10),
    new THREE.MeshBasicMaterial({
        side : THREE.DoubleSide,
        opacity : 0.9,
        transparent : true,
        color : 0x405060
    })
) ;

scene.add(surfaceMesh) ;



///////////////////////////////////////////////

let azimut = 0,
	  pitch = 90,
    isDown = false,
    prevEv ;

function down(de) {
		prevEv = de ;
    isDown = true ;
}

function move(me) {
		if (!isDown) return ;
    
		azimut -= (me.clientX - prevEv.clientX) * 0.5 ;
    azimut %= 360 ;
    if (azimut < 0) azimut = 360 - azimut ;
    
		pitch -= (me.clientY - prevEv.clientY) * 0.5 ;
    if (pitch < 1) pitch = 1 ;
    if (pitch > 180) pitch = 180 ;
    
    prevEv = me ;
    
    let theta = pitch / 180 * PI,
        phi = azimut / 180 * PI,
        radius = DISTANCE ;
    
    camera.position.set(
      	radius * sin(theta) * sin(phi),
      	radius * cos(theta),
      	radius * sin(theta) * cos(phi),
    ) ;
  	camera.lookAt(center) ;
    
    renderer.render(scene, camera) ;
}

function up(ue) {
		isDown = false ;
}

renderer.domElement.onmousedown = down ;
window.onmousemove = move ;
window.onmouseup = up ;

renderer.render(scene, camera) ;
body {
  display: flex;
  flex-direction: row;
  justify-content: center;
  align-items: center;
  height: 100vh;
  margin: 0;
  background: #1c2228;
  overflow: hidden;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/101/three.min.js"></script>
<script src="https://threejs.org/examples/js/curves/NURBSUtils.js"></script>
<script src="https://threejs.org/examples/js/curves/NURBSCurve.js"></script>
<script src="https://threejs.org/examples/js/curves/NURBSSurface.js"></script>

<canvas></canvas>

这是绘制贝塞尔三角形的方法(下面的片段) - 算法在Geometry班级。您设置的三角形一侧的三角形数量constructor。在代码中,我在算法/计算之间进行了硬分离(Geometry类)和绘图代码(Draw class).

对于贝塞尔三角形,我们需要使用 10 个控制点(9 个用于边缘,1 个用于“平面”),如下图所示 (srchere ):

enter image description here

在此代码中,我们不使用法线,并且b点名称更改为p (eg. b003 to p003)。我们使用以下公式(对于三次贝塞尔三角形n=3)

enter image description here

Where p_ijk是控制点(对于 n=3,上面的总和有 10 个元素,因此我们有 10 个控制点),其中 B^n_ijk(r,s,t) 是为 i,j,k>=0 和 i+j 定义的 Bernstein 多项式+k=n

enter image description here

或其他情况下为 0。重心坐标中 r,s,t 的定义域(其中 r,s,t 是 [0, 1] 中的实数,r+s+t=1),其中r=(r=1,s=t=0),s=(s=1,r=t=0),t=(t=1, r=s=0) 如下所示(黑点 - 我们将每个三角形边划分为 5 部分 - 但我们可以将其更改为任何数字)

enter image description here

我们在方法中计算黑域点的规则位置barycentricCoords(n)我们在方法中定义哪个点创建哪些三角形genTrianglesIndexes(n) in Geometry班级。但是,您可以将这些点的位置和密度更改为任何(内部三角形)以获得不同的表面三角形划分。下面是显示二维域的片段

let pp= ((s='.myCanvas',c=document.querySelector(s),ctx=c.getContext('2d'),id=ctx.createImageData(1,1)) => (x,y,r=0,g=0,b=0,a=255)=>(id.data.set([r,g,b,a]),ctx.putImageData(id, x, y),c))()


cr=[255,0,0,255];
cg=[0,255,0,255];
cb=[0,0,255,255];

w=400;
h=400;

const p1=[0,h-1];
const p2=[w-1,h-1];
const p3=[w/2,0];

mainTriangle=[p1,p2,p3];
//mainTriangle.map(p => pp(...p,...cr));

let n=5;
let points=[];

function calcPoint(p1,p2,p3,r,s,t) {
  const px=p1[0]*r + p2[0]*s + p3[0]*t;
  const py=p1[1]*r + p2[1]*s + p3[1]*t;
  return [px,py];
}

// barycentric coordinates r,s,t of point in triangle
// the points given from triangle bottom to top line by line
// first line has n+1 pojnts, second has n, third n-1
// coordinates has property r+s+t=1
function barycentricCoords(n) {
  let rst=[];
  for(let i=0; i<=n; i++) for(let j=0; j<=n-i; j++) {
    s=(j/n);
    t=(i/n);    
    r=1-s-t;
    rst.push([r,s,t]);    
  }
  return rst;
}

// Procedure calc indexes for each triangle from 
// points list (in format returned by barycentricCoords(n) )
function genTrianglesIndexes(n) {
  let st=0; 
  let m=n;  
  let triangles=[];

  for(let j=n; j>0; j--) {    
    for(let i=0; i<m; i++) {    
      triangles.push([st+i, st+i+1, st+m+i+1]);
      if(i<m-1) triangles.push([st+i+1, st+m+i+2, st+m+i+1 ]);
    }
    m--;
    st+=j+1;  
  }
  
  return triangles;
}

function drawLine(p1,p2,c) {
  let n=Math.max(Math.abs(p1[0]-p2[0]),Math.abs(p1[1]-p2[1]))/2;
	for(let i=0; i<=n; i++) {
  	let s=i/n;
    let x=p1[0]*s + p2[0]*(1-s);
    let y=p1[1]*s + p2[1]*(1-s);
    pp(x,y,...c);
  }
}

function drawTriangle(p1,p2,p3,c) {
	drawLine(p1,p2,c);
  drawLine(p2,p3,c);
  drawLine(p3,p1,c);
}

// Bernstein Polynomial, i+j+k=n
function bp(n,i,j,k, r,s,t) {
  const f=x=>x?f(x-1)*x:1 // number fractional f(4)=1*2*3*4=24
  
  return r**i * s**j * t**k * f(n) / (f(i)*f(j)*f(k));  
}

//drawTriangle(...mainTriangle,cr); // draw main triangle

let bar=barycentricCoords(n);  // each domain point barycentric coordinates

let ti=genTrianglesIndexes(n); // indexes in bar for each triangle

// triangles calculated to cartesian coordinate system
let triangles = ti.map(tr=> tr.map(x=>calcPoint(...mainTriangle,...bar[x]) ) ); 

triangles.map(t => drawTriangle(...t, cg));

// domain points calculated to cartesian coordinate system (for draw)
let dp = bar.map(x=> calcPoint(...mainTriangle,...x) );

// draw black dots (4 pixels for each dot)
dp.map(x=> pp(x[0],x[1]) )
dp.map(x=> pp(x[0],x[1]-1) )
dp.map(x=> pp(x[0]-1,x[1]) )
dp.map(x=> pp(x[0]-1,x[1]-1) )
<canvas class="myCanvas" width=400 height=400 style="background: white"></canvas>

下面是 3D 贝塞尔立方三角形的最终片段(算法从方法开始genTrianglesForCubicBezierTriangle(n, controlPoints) in Geometry班级) -(注意:这很奇怪,但是在第一次运行后的 SO 片段中,您将看不到线条,并且您需要重新加载页面并再次运行它才能看到三角形线)

///////////////////////////////////////////////////////
// THIS PART/CLASS IS FOR ALGORITHMS AND CALCULATIONS
///////////////////////////////////////////////////////
class Geometry {

  constructor() { this.init(); } 

  init(n) {
    this.pts = [
      { x:-16, y: -8, z:0,  color:0xcc0000 }, // p003 RED
      { x:8,   y:-12, z:0,  color:0x888888 }, // p201
      { x:-8,  y:-12, z:0,  color:0x999999 }, // p102    
      { x:16,  y:-8,  z:0,  color:0x00cc00 }, // p300 GREEN
      { x:12,  y:-6,  z:-8, color:0x777777 }, // p210
      { x:8,   y:6,   z:-8, color:0x666666 }, // p120
      { x:0,   y:12,  z:0,  color:0x0000cc }, // p030 BLUE
      { x:-8,  y:6,   z:-8, color:0x555555 }, // p021
      { x:-12, y:-6,  z:-8, color:0x444444 }, // p012
      { x:0,   y:0,   z:8,  color:0xffff00 }, // p111 YELLOW (plane control point)
    ];
    
    this.mainTriangle = [this.pts[0],this.pts[3],this.pts[6]];
    
    this.bezierCurvesPoints = [
    	[ this.pts[0], this.pts[2], this.pts[1], this.pts[3] ],
        [ this.pts[3], this.pts[4], this.pts[5], this.pts[6] ],
        [ this.pts[6], this.pts[7], this.pts[8], this.pts[0] ]
    ];
    
    //this.triangles = [
    // { points: [this.pts[0], this.pts[1], this.pts[2]], color: null }, // wireframe
    // { points: [this.pts[1], this.pts[2], this.pts[3]], color: 0xffff00 } // yellow
    //]
    
    this.triangles = this.genTrianglesForCubicBezierTriangle(25, this.pts);
  }
  
  // n = number of triangles per triangle side
  genTrianglesForCubicBezierTriangle(n, controlPoints) {
    let bar= this.barycentricCoords(n);     // domain in barycentric coordinats   
    let ti = this.genTrianglesIndexes(n);   // indexes of triangles (in bar array)
        
    let val= bar.map(x => this.calcCubicBezierTriangleValue(controlPoints,...x));  // Calc Bezier triangle vertex for each domain (bar) point    
    let tv= ti.map(tr=> tr.map(x=>val[x]) );         // generate triangles using their indexes (ti) and val    
    return tv.map(t=> ({ points: t, color: null}) ); // map triangles to proper format (color=null gives wireframe)
    
    
    // Generate domain triangles
    //let td= ti.map(tr=> tr.map(x=>this.calcPointFromBar(...this.mainTriangle,...bar[x]) ) );     
    //this.trianglesDomain = td.map(t=> ({ points: t, color: null}) );
  }
  
  // more: https://www.mdpi.com/2073-8994/8/3/13/pdf
  // Bézier Triangles with G2 Continuity across Boundaries
  // Chang-Ki Lee, Hae-Do Hwang and Seung-Hyun Yoon
  calcCubicBezierTriangleValue(controlPoints, r,s,t ) {
    let p = controlPoints, b=[];  
    b[0]= this.bp(0,0,3,r,s,t); // p[0]=p003
    b[1]= this.bp(2,0,1,r,s,t); // p[1]=p201 
    b[2]= this.bp(1,0,2,r,s,t); // p[2]=p102
    b[3]= this.bp(3,0,0,r,s,t); // p[3]=p300
    b[4]= this.bp(2,1,0,r,s,t); // p[4]=p210
    b[5]= this.bp(1,2,0,r,s,t); // p[5]=p120
    b[6]= this.bp(0,3,0,r,s,t); // p[6]=p030
    b[7]= this.bp(0,2,1,r,s,t); // p[7]=p021
    b[8]= this.bp(0,1,2,r,s,t); // p[8]=p012
    b[9]= this.bp(1,1,1,r,s,t); // p[9]=p111
    
    let x=0, y=0, z=0;
    for(let i=0; i<=9; i++) {
      x+=p[i].x*b[i];
      y+=p[i].y*b[i];
      z+=p[i].z*b[i];
    }
    return { x:x, y:y, z:z };
  }
  
  // Bernstein Polynomial degree n, i+j+k=n
  bp(i,j,k, r,s,t, n=3) {
    const f=x=>x?f(x-1)*x:1 // number fractional f(4)=1*2*3*4=24    
    return r**i * s**j * t**k * f(n) / (f(i)*f(j)*f(k));  
  }
  
  coordArrToObj(p) { return { x:p[0], y:p[1], z:p[2] } } 
  
  // Calc cartesian point from barycentric coords system
  calcPointFromBar(p1,p2,p3,r,s,t) {  
    const px=p1.x*r + p2.x*s + p3.x*t;
    const py=p1.y*r + p2.y*s + p3.y*t;
    const pz=p1.z*r + p2.z*s + p3.z*t;       
    return { x:px, y:py,  z:pz};
  }

  // barycentric coordinates r,s,t of point in triangle
  // the points given from triangle bottom to top line by line
  // first line has n+1 pojnts, second has n, third n-1
  // coordinates has property r+s+t=1
  barycentricCoords(n) {
    let rst=[];
    for(let i=0; i<=n; i++) for(let j=0; j<=n-i; j++) {
      let s=(j/n);
      let t=(i/n);    
      let r=1-s-t;
      rst.push([r,s,t]);    
    }
    return rst;
  }

  // Procedure calc indexes for each triangle from 
  // points list (in format returned by barycentricCoords(n) )
  genTrianglesIndexes(n) {
    let st=0; 
    let m=n;  
    let triangles=[];

    for(let j=n; j>0; j--) {    
      for(let i=0; i<m; i++) {    
        triangles.push([st+i, st+i+1, st+m+i+1]);
        if(i<m-1) triangles.push([st+i+1, st+m+i+2, st+m+i+1 ]);
      }
      m--;
      st+=j+1;  
    }

    return triangles;
  }
  
  // This procedures are interface for Draw class 
  getPoints() { return this.pts }
  getTriangles() { return this.triangles }
  getBezierCurves() { return this.bezierCurvesPoints; }
}


///////////////////////////////////////////////
// THIS PART IS FOR DRAWING
///////////////////////////////////////////////

// init tree js and draw geometry objects
class Draw {

  constructor(geometry) { this.init(geometry); }
  
  initGeom() {
  	this.geometry.getPoints().forEach(p=> this.createPoint(p));
    this.geometry.getTriangles().forEach(t=> this.createTriangle(t));
    
    this.geometry.getBezierCurves().forEach(c=> this.createEdge(...c));
  }

  init(geometry) {
    this.geometry = geometry;
    this.W = 480,
    this.H = 400,
    this.DISTANCE = 100 ;
    this.PI = Math.PI,
    
  
    this.renderer = new THREE.WebGLRenderer({
      canvas : document.querySelector('canvas'),
      antialias : true,
      alpha : true
    }),
    this.camera = new THREE.PerspectiveCamera(25, this.W/this.H),
    this.scene = new THREE.Scene(),
    this.center = new THREE.Vector3(0, 0, 0),

		this.pts = [] ;
    
    this.renderer.setClearColor(0x000000, 0) ;

    this.renderer.setSize(this.W, this.H) ;
    // camera.position.set(-48, 32, 80) ;
    this.camera.position.set(0, 0, this.DISTANCE) ;
    this.camera.lookAt(this.center) ;
    
    this.initGeom();
    
    this.azimut = 0;
    this.pitch = 90;
    this.isDown = false;
    this.prevEv = null;

    

    this.renderer.domElement.onmousedown = e => this.down(e) ;
    window.onmousemove = e => this.move(e) ;
    window.onmouseup = e => this.up(e) ;

    this.renderer.render(this.scene, this.camera) ;
    
  }
    
  createPoint(p) {
    let {x, y, z, color} = p;
		let pt = new THREE.Mesh(
      new THREE.SphereGeometry(1, 10, 10),
      new THREE.MeshBasicMaterial({ color })
    ) ;
    pt.position.set(x, y, z) ;
    pt.x = x ;
    pt.y = y ;
    pt.z = z ;
    this.pts.push(pt) ;
    
    this.scene.add(pt) ;
	}
  
  createTriangle(t) {    
    var geom = new THREE.Geometry();
    var v1 = new THREE.Vector3(t.points[0].x, t.points[0].y, t.points[0].z);
    var v2 = new THREE.Vector3(t.points[1].x, t.points[1].y, t.points[1].z);
    var v3 = new THREE.Vector3(t.points[2].x, t.points[2].y, t.points[2].z);

    geom.vertices.push(v1);
    geom.vertices.push(v2);
    geom.vertices.push(v3);
        
    let material = new THREE.MeshNormalMaterial({wireframe: true,}) 
    if(t.color != null) material = new THREE.MeshBasicMaterial( { 
    	color: t.color,
      side: THREE.DoubleSide,
      } );
    

    geom.faces.push( new THREE.Face3( 0, 1, 2 ) );
    geom.computeFaceNormals();

    var mesh= new THREE.Mesh( geom, material);
    this.scene.add(mesh) ;
  }
  
  createEdge(pt1, pt2, pt3, pt4) {
 
		let curve = new THREE.CubicBezierCurve3(
          new THREE.Vector3(pt1.x, pt1.y, pt1.z),
          new THREE.Vector3(pt2.x, pt2.y, pt2.z),
          new THREE.Vector3(pt3.x, pt3.y, pt3.z),
          new THREE.Vector3(pt4.x, pt4.y, pt4.z),
        ),
    		mesh = new THREE.Mesh(
          new THREE.TubeGeometry(curve, 8, 0.5, 8, false),
          new THREE.MeshBasicMaterial({
            color : 0x203040
          })
        ) ;
        
    this.scene.add(mesh) ;
}
  
  down(de) {
        this.prevEv = de ;
        this.isDown = true ;
    }

  move(me) {
    if (!this.isDown) return ;

    this.azimut -= (me.clientX - this.prevEv.clientX) * 0.5 ;
    this.azimut %= 360 ;
    if (this.azimut < 0) this.azimut = 360 - this.azimut ;

    this.pitch -= (me.clientY - this.prevEv.clientY) * 0.5 ;
    if (this.pitch < 1) this.pitch = 1 ;
    if (this.pitch > 180) this.pitch = 180 ;

    this.prevEv = me ;

    let theta = this.pitch / 180 * this.PI,
        phi = this.azimut / 180 * this.PI,
        radius = this.DISTANCE ;

    this.camera.position.set(
      radius * Math.sin(theta) * Math.sin(phi),
      radius * Math.cos(theta),
      radius * Math.sin(theta) * Math.cos(phi),
    ) ;
    this.camera.lookAt(this.center) ;

    this.renderer.render(this.scene, this.camera) ;
  }

  up(ue) {
    this.isDown = false ;
  }
}

// SYSTEM SET UP
let geom= new Geometry();
let draw = new Draw(geom);
body {
  display: flex;
  flex-direction: row;
  justify-content: center;
  align-items: center;
  height: 100vh;
  margin: 0;
  background: #1c2228;
  overflow: hidden;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/101/three.min.js"></script>

<canvas></canvas>

小提琴版本是here。我在评论中添加了信息,但算法很复杂,如果您有疑问 - 作为评论提问 - 我会回答。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

如何在 Three.js 中从 3D 点创建 3D 三次贝塞尔曲线三角形? 的相关文章

随机推荐