JavaScript How can I create a 3D cubic-bezier curved triangle from 3D points in Three.js?

Following this topic, I am trying to generate a 3D curved triangle as a NURBS surface, but I don't understand how to set up my 3D points to do that.

Here is the current implementation :

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) ;

And here is the result:

enter image description here

I tried many different settings but can't find any working well.

Note: The white points are the edges ends ; The red points are the bezier curve middle points.
Note 2: dots[0] refers to the point 0 in the sample picture, and so on.

Here is working snippet (and fiddle version 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>
Answer:1

I must be missing something obvious. Turning to SO after a day of frustrated headbanging ;-) : Given that I have created a time domain axis using d3.time.scale and d3.svg.axis, how can I later modify ...

I must be missing something obvious. Turning to SO after a day of frustrated headbanging ;-) : Given that I have created a time domain axis using d3.time.scale and d3.svg.axis, how can I later modify ...

  1. d3 resize axis
  2. d3 responsive axis

I am trying to translate my application using react-i18next. I know how to use it with simple const components, but not within a class. I'm working with the I18nextProvider. This is my App.js file. ...

I am trying to translate my application using react-i18next. I know how to use it with simple const components, but not within a class. I'm working with the I18nextProvider. This is my App.js file. ...

  1. using react-i18next
  2. react in i18next
  3. use translation react i18next

I'm trying to efficiently make a key-value tour in an array in reactjs. However, I do not know how to display the "key" array without creating another map function. const equipos = [ { key: [ ...

I'm trying to efficiently make a key-value tour in an array in reactjs. However, I do not know how to display the "key" array without creating another map function. const equipos = [ { key: [ ...

Here is the code: function fil(val) { console.log('fil'); // never written to console when run in greasemonkey return true; } var temp = unsafeWindow.someobject; console.log(temp); // looks fine ...

Here is the code: function fil(val) { console.log('fil'); // never written to console when run in greasemonkey return true; } var temp = unsafeWindow.someobject; console.log(temp); // looks fine ...

  1. what could stop you from getting a passport
  2. what could stop you from getting pregnant
  3. what could stop the ocean currents
  4. what could stop my period
  5. what could stop a car from starting
  6. what would stop diarrhea
  7. what would stop you from being drafted
  8. what could stop your car from starting
  9. what could stop me from getting pregnant
  10. what would stop you from getting drafted
  11. what could stop implantation
  12. what could stop global warming
  13. what could stop climate change
  14. what could stop your period from coming
  15. what could stop your period
  16. what could stop menstruation
  17. what could stop brexit
  18. what could stop periods
  19. what could stop ovulation
  20. what could stop me getting a mortgage