您的位置: 游戏资讯 > 游戏问答

3d曲面变形怎么用,3done曲面设计

来源:[db:H1] 浏览:0 2024-03-30 10:12:12

本文详细介绍了三次曲线、贝塞尔曲线和B 样条曲线和曲面背后的数学原理,并提供了使用Three.js 库实现它们的代码。

1. 简介从这里您可以访问上图所示的应用程序。该应用程序称为CurSur,代表曲线和曲面。原始代码可以在这里找到。几何设计包括许多不同类型的曲线和曲面,包括2D 和3D。其中,几何建模入门课程通常教授三种类型的三次曲线:贝塞尔曲线、B样条曲线和曲面。本文的目的是介绍一个使用Three.js 库在浏览器中绘制这些3D 曲线和曲面的程序。本文介绍了如何使用Three.js 在浏览器中以3D 方式绘制直线和曲面,以及如何更改这些曲线和曲面的控制点和切线(导数)等几何参数。此处显示的代码的主要要求是:

3d曲面变形怎么用,3done曲面设计

屏幕上可以显示六种类型的3D 曲线和曲面:参数三次曲线、Coons 二次曲面、Bezier 曲线、Bezier 曲面、B 样条(实际上是NURBS)曲线和NURBS 曲面。用户可以更改控制点的x、y、z 坐标和/或其相对于曲线或曲面的x、y、z(切向)导数,并查看曲线或曲面如何动态变化。屏幕。用户还需要能够在线框模式下查看表面。曲线或曲面的边界框显示为以原点为中心,尺寸为2 个单位。用户需要能够更改相机的角度,以便它围绕其正在查看的场景的垂直轴旋转。用户应该能够更改参数值(u 表示曲线,u、w 表示曲面)。您还可以看到随着这些u,w 值的变化,曲线或曲面上对应的点发生移动。单击该按钮,您将看到一些标准曲线和曲面。要在屏幕上显示3D 曲线或曲面,您需要使用Three.js 库。您应该使用Vanilla JS 而不是框架。不应该有文本框类型的用户输入,所有用户交互都应该仅通过滑块、复选框、组合框和按钮。 2.参数曲线和参数曲面简介高中和大学时我们了解到直线可以用直线、圆弧、圆锥截面等直角坐标表示,也可以用极坐标表示。然而,出于几何设计目的,出于多种原因,笛卡尔形式和极坐标形式通常不是优选的。其中两个是:(i)用笛卡尔形式表示垂直或接近垂直的线并不容易,因为斜率(导数)往往是无限的; (ii) 用这些笛卡尔形式和极坐标形式表示一般形状并不容易。因此,首选格式是参数化的。在参数形式中,3D 曲线表示为:

x=x(u)y=y(u)z=z(u) 其中x、y、z是曲线上任意点的3D坐标,u是参数,通常在0u范围内。 1. 其中,x(u)、y(u)、z(u)是三个参数u的函数。这种表示法可以很容易地表示任何形状的线,而没有笛卡尔表示法无限导数的缺点。具体来说,有三个函数:x(u)、y(u)和z(u),本文定义了三种类型的曲线:参数三次曲线、贝塞尔曲线和B样条曲线。类似地,我们也可以使用以下方程来表示曲面:

x=x(u,w)y=y(u,w)z=z(u,w) 其中x、y、z通常是表面上一点的三维坐标,u、w是表面上一点的三维坐标。参数空间中相互正交方向的两个参数,通常为0 u 1、0 w 1。这里,三个函数x(u,w)、y(u,w) 和z(u,w) 采用三种不同的形式,分别表示双三次、贝塞尔曲线和B 样条曲线。

3.用Three.js绘制曲线是通过将许多直线首尾相连来绘制的,以给出平滑曲线的外观,所以最基本的方法是在浏览器中绘制3D直线。自从WebGL 出现以来,JavaScript 3D 库就出现了,它们抽象出了实际WebGL 库的内部细节。两个流行的JavaScript 库是Three.js 和Babylon.js。本文提供了有关如何使用Three.js 库在屏幕上绘制线条和曲面的代码摘录。在Three.js 中绘制3D 对象所需的三个最重要的实体是场景、相机和渲染器。代码将如下所示。

scene=new THREE.Scene();camera=new THREE.PerspectiveCamera(45, window.innerWidth/window.innerHeight, 0.1, 1000 );renderer=new THREE.WebGLRenderer({ antialias: true });Three.js Draw 3.1 Straight直线:直线段由空间中的两个端点确定:(x1, y1, z1) 和(x2, y2, z2)。为了绘制直线段,Three.js 有一个名为BufferGeometry 的Geometry 对象。以前有一个Geometry 对象,但在Three.js 的修订版125 中已弃用,并被BufferGeometry 对象取代。此外,必须指定材料。线条和表面由不同的材料制成。要绘制直线段,请使用以下代码:

const 材质=new THREE.LineBasicmaterial({ color:0xff00ff }); const 几何=new THREE.BufferGeometry(); const 顶点=[];vertices.push(-0.75, -0.75, -0.75);vertices.push(0.75, 0.75, 0.75);geometry.setAttribute( 'position', new THREE.Float32BufferAttribute(vertices, 3));let line=new THREE.Line(geometry,material);scene.add(line);render();顶部代码在端点(-0.75, -0.75, -0.75) 和(0.75, 0.75, 0.75) 之间绘制一条直线,如下面的洋红色线所示。

3.2 用Three.js 绘制一个简单的曲面曲面被定义为一组三角形。因此,绘制的基本几何实体是三角形。 3D 三角形由三个顶点指定:(x1, y1, z1)、(x2, y2, z2) 和(x3, y3, z3)。你不能只画三条线来定义一个三角形。这是因为它显示为线框。如果您的场景仅包含一系列线段,则不需要额外的灯光来照亮场景。但是,如果场景中有曲面或3D 对象(立方体、球体等),则需要为它们分配一盏或多盏灯光。有不同类型的灯光,这些在Three.js 文档中定义。向场景添加一些灯光的代码如下所示:

scene.add(new THREE.HemisphereLight(0x606060,0x404040));//strong度为0.65 的白色定向光从顶部照射。 let DirectionLight=new THREE.DirectionalLight(0xffffff, 0.65);scene.add(directionLight);要将三角形添加为曲面,必须定义三角形的法线。三角形现在有两条法线,两者都指向相反的方向。如果材质被指定为双面,则三角形的两侧都将通过定义的灯光可见。但是,如果指定一侧,则未暴露在光线下的一侧将不太可能发光。以下是在场景中绘制三角形的代码:

函数computeCoonsBicubicSurface() { setupFourPoints(); surfacePoints.length=0; let uVal, wVal; for (let j=0; j=noDivisions; ++j) { wVal=j * step; for (let i=0; i=noDivisions; ++i) { uVal=i * 步骤; 让pt=computePointOnSurface(uVal, wVal); surfacePoints.push(pt.xVal, pt.yVal, pt.zVal); } } renderCoonsBicubicSurface(); handleUWValue() ;}函数renderCoonsBicubicSurface() { scene.remove(surfaceMesh); scene.remove(lineWire); 让材质=new THREE.MeshStandardmaterial({side: THREE.DoubleSide, color:0x00ffff, emissive:0x111111, dithering: true, flatShading: false, 粗糙度33 3 60 1 , metalness: 0.15, Skinning: true, }); letmaterialLine=new THREE.LineBasicMaterial({ color:0x00ffff, }); let Geometry=new THREE.BufferGeometry(); const索引=[]; Index.length=0; for (let i=0; i noDivisions; i++) { for (let j=0; j noDivisions; j++) { const a=i * (noDivisions + 1) + (j + 1); const b=i * (noDivisions + 1) + j; const c=(i + 1) * (noDivisions + 1) + j; const d=(i + 1) * (noDivisions + 1) + (j + 1); //2 个面(三角形)产生索引.push(a, b, d); //一个面Index.push(b, c, d); //两个面} } Geometry.setIndex(indices); Geometry.setAttribute( 'position', new THREE. Float32BufferAttribute (surfacePoints,3).onUpload(disposeArray));geometry.computeVertexNormals();surfaceMesh=new THREE.Mesh(几何,材质);scene.add(surfaceMesh);让surfaceWire=new THREE .WireframeGeometry(几何);lineWire=new THREE.LineSegments(surfaceWire,materialLine); scene.add(lineWire); render();} 其中surfacePoints 是上面定义的点数组。使用上面的代码绘制的曲面如下所示:随着三角形数量的增加,表面开始呈现光滑的外观。有关完整代码,请参阅文件script2.js。

4. 参数三次曲线参数三次曲线由以下三个方程定义。

x(u)=B0x + B1x u + B2x u2 + B3x u3y(u)=B0y + B1y u + B2y u2 + B3y u3z(u)=B0z + B1z u + B2z u2 + B3z u3这里,12个常数B0x,B1x, B2x、B3x、B0y、B1y、B2y、B3y、B0z、B1z、B2z、B3z 是根据曲线上的点确定的常数。有两种方法可以确定这些常数。

四点方程:如果已知曲线上的四个点,则这四个点的坐标指定12 个方程并确定12 个常数。 Hermitian 形式:如果两个端点的坐标已知且两个端点切线(端点处关于x、y 和z 的导数)已知,则还指定确定12 个常数的12 个方程。本文附带的应用程序描述了两种方法。这两种形式对应的方程的推导可以在Mortenson 的书Geometric Modeling 或Rogers 和Adams 的书Mathematical Elements of Computer Graphics 中找到。至于埃尔米特形式,即x、y、z方程相对于x、y、z坐标的导数,这些在上述书籍中也给出了。

4.1 四点格式这种四点格式要求您指定四个点的u 值。在此代码中,它们是0、1/3、2/3 和1。通过将这些参数u的值代入曲线的方程中,我们可以求出常数Bij的值。当你使用坐标值滚动条改变任意四个点的坐标值时,这些常量Bij会被动态计算,计算出曲线上所有点的新坐标,并将曲线显示在屏幕上。被更新。这是代码:

functioncomputePointFourPointForm(uVal) { let u2, u3; let coeff1, coeff2, coeff3, coeff4; let xCurve, yCurve, zCurve; u2=uVal * uVal; u3=u2 * uVal; //这是Mortenson 的四点公式关于几何建模的书//对于u值0, 1/3, 2/3, 1 coeff1=-4.5 * u3 + 9 * u2 - 5.5 * uVal + 1; coeff2=13.5 * u3 - 22.5 * u2 + 9 * uVal;coeff3=-13.5 * u3 + 18 * u2 - 4.5 * uVal;coeff4=4.5 * u3 - 4.5 * u2 + uVal;xCurve=p1x * coeff1 + p2x * coeff2 + p3x * coeff3 + p4x * coeff4;yCurve=p1y * coeff1 + p2y * coeff2 + p3y * coeff3 + p4y * coeff4; zCurve=p1z * coeff1 + p2z * coeff2 + p3z * coeff3 + p4z * coeff4; 返回{ xVal: xCurve, yVal: yCurve, zVal: z 曲线, };} 4.2 Hermite 格式在这种格式中,指定两个端点和这些端点处的两组导数,并用于计算常数Bij。这些也是摩顿森书中的公式。这是代码:

functioncomputePointHermiteForm(uVal) { let u2, u3; let coeff1, coeff2, coeff3, coeff4; let xCurve, yCurve, zCurve; u2=uVal * uVal; u3=u2 * uVal; //这是Mortenson 书中的Hermite 形式这是公式。几何建模//端点u 和du coeff1=2 * u3 - 3 * u2 + 1; coeff2=-2 * u3 + 3 * u2; coeff3=u3 - 2 * u2 + uVal; coeff4=u3 - u2; xCurve=p1xh * coeff1 + p2xh * coeff2 + p1dxh * coeff3 + p2dxh * coeff4; yCurve=p1yh * coeff1 + p2yh * coeff2 + p1dyh * coeff3 + p2dyh * coeff4; zCurve=p1zh * coeff1 + p2zh * coeff2 + p1dzh * coeff3 + p2dzh * coeff4 ; return { xVal: xCurve, yVal: yCurve, zVal: zCurve, };} 当用户使用屏幕滚动条改变滚动条对应的终点坐标和导数时,动态计算常数B ij 。然后重新计算整个曲线。

4.3 参数三次曲线代码曲线显示为曲线上的一系列直线段。参数范围0u1 将整体分成若干部分,并将所有直线段绘制成环。该代码位于文件script1.js 中。相应的HTML 位于文件page1.html 中。

letcurvePoints=[];curvePoints.length=0;for (let i=0; i noUPoints; ++i) { uVal=uStep * i; //uVal 和uStep 之前已定义let pt=computePointFourPointForm(uVal ); //let pt=computePointHermiteForm(uVal); CurvePoints.push(pt.xVal, pt.yVal, pt.zVal);}4.4 验证为了验证,使用一组点坐标/导数的标准值,生成的曲线形状。此外,通过改变参数u获得的曲线上的点显示在屏幕上并用于验证。这里需要注意的一个有趣的例子是非线性直线。一般来说,如果参数u的增量相等,则沿着曲线行进的距离并不相等。这向参数化三次曲线引入了非线性元素。这是一条非线性直线。即使这些点都在同一条直线上,不同的参数增量也会导致沿直线行进的距离不同。在埃尔米特形式中,对于直线,端点导数可能存在于直线段之外的方向上。在这种情况下,参数u从0增加到1后,该点延伸超出直线段,反转方向,并向第二个端点移动。这也是一条非线性直线。其中一些情况以指定有趣曲线的按钮的形式出现在屏幕上。

5. 3D 贝塞尔曲线对于上面所示的参数三次曲线,尤其是四点形式,曲线穿过所有四个点。这是一种曲线拟合。贝塞尔曲线由P Bezier 提出,他根据控制点定义了曲线方程。贝塞尔曲线由以下等式定义

在此应用中,我们考虑的是具有5 个控制点的贝塞尔曲线,因此多项式u 的最高次数为4。

5.1 贝塞尔曲线代码与参数三次曲线一样,贝塞尔曲线表示为曲线上的一系列直线段。参数范围0u1 将整体分成若干部分,并将所有直线段绘制成环。该代码位于文件script3.js 中,对应于HTML 文件page3.html。

u2=uVal * uVal;u3=u2 * uVal;u4=u3 * uVal;//这是Rogers 和Adam 的书《计算机图形学的数学原理》中的贝塞尔曲线公式//coeff1=u4 - 4 * u3 + 6 * u2 - 4 * uVal + 1;coeff2=-4 * u4 + 12 * u3 - 12 * u2 + 4 * uVal;coeff3=6 * u4 - 12 * u3 + 6 * u2;coeff4=- 4 * u4 + 4 * u3; coeff5=u4; coeff4 + p5y * coeff5;zCurve=p1z * coeff1 + p2z * coeff2 + p3z * coeff3 + p4z * coeff4 + p5z * coeff5;5.2 验证贝塞尔曲线有以下验证方面。

一般来说,曲线应通过端点而不是通过其他控制点。但是,如果所有控制点都位于一条直线上,则曲线也必须是通过这些点的直线。曲线端点处的切线必须与连接该特定端点与下一个控制点的线重合。例如,在曲线的起点处,曲线的切线必须与连接第一和第二控制点的直线重合。它也位于末端控制点。所有这些点都根据贝塞尔曲线进行验证,并绘制一组有趣的贝塞尔曲线,每条曲线在屏幕上都有自己的按钮。

6. 3D NURBS 中的NURBS 曲线表示非均匀有理B 样条曲线。这是必要的,因为参数三次曲线和贝塞尔曲线都不提供曲线的局部控制。这意味着对于参数三次曲线和贝塞尔曲线,更改一个控制点会更改整条曲线,这在许多应用中是不可取的。另一方面,B 样条曲线允许您局部控制曲线。更改控制点的坐标只会更改该控制点周围的区域;曲线的其余部分不受影响。有理B 样条曲线的一般方程为:

NURBS 曲线的阶数不取决于控制点的数量。这两个是NURBS 曲线内的独立实体。在我们的应用程序中,我们首先定义6 个控制点,用户可以添加控制点(总共最多20 个控制点)并更改每个点的坐标(x、y、z、h 值)。这样您就可以可视化由此产生的NURBS。曲线。

6.1 NURBS 曲线代码Three.js 已经有NURBS 曲线的开源代码,因此我们不会重新发明轮子。因此,我从中提取了NURBS 曲线代码的相关内容,并将其包含在名为NurbsHelper.js 的文件中。为了指定控制点,我们的代码将它们生成为以原点为中心的二维边界框中的随机数。尽管NURBS 曲线是应用程序中三个曲线中最复杂的,但其代码script5.js 却是最简单的,仅调用文件NurbsHelper.js 中的相关函数。相应的HTML 文件是page5.html。

6.2 验证如前所述,NURBS 曲线允许局部控制。也就是说,通过更改点的坐标(x, y, z, h),您只能更改局部曲线,而曲线的其余部分保持不变。这是一个可以通过肉眼轻松验证的特征。您需要验证的另一件事是更改控制点的齐次坐标h 的值。这应该将曲线拉向该控制点。这也在视觉上得到证实。另一个验证点是改变曲线的阶数。当度数等于1 时,曲线类似于控制多边形本身。随着曲线的阶数增加,曲线远离控制点(不包括端点),并且随着这些阶数的值增加,曲线距离相应的控制点最远。 7. 昆斯双三次曲面三次曲线的二维等价物是昆斯双三次曲面。该曲面的方程为:

参数空间有两个参数u 和w,在[0, 1] 范围内变化。必须为昆斯双三次曲面定义以下边界条件:

矩形面片的四个端点。这些端点处相对于参数u 的切向量。这些是关于u 的偏导数。这些端点处相对于参数w 的切向量。这些是关于w 的偏导数。在这些端点处围绕参数u、w 扭转向量。这些是关于u 和w 的偏导数。如果上述任何一项发生变化,表面就会发生变化。所有这些都在下面列出。

面片的边界是以下四条曲线:

u和w等于0时的曲线。 w 增加且u 等于0 的曲线。 u 和w 增加等于1 的曲线。 w 增加且u 增加

1 的曲线。7.1 Coons 双三次曲面代码以下 JavaScript 函数在文件 script2.js 中计算曲面上的一个点。 function computePointOnSurface(uVal, wVal) { let u2, u3, w2, w3; let f1u, f2u, f3u, f4u, f1w, f2w, f3w, f4w; let valueX, valueY, valueZ; let valx1, valx2, valx3, valx4; let valy1, valy2, valy3, valy4; let valz1, valz2, valz3, valz4; w2 = wVal * wVal; w3 = w2 * wVal; f1w = 2.0 * w3 - 3 * w2 + 1.0; f2w = -2.0 * w3 + 3.0 * w2; f3w = w3 - 2.0 * w2 + wVal; f4w = w3 - w2; u2 = uVal * uVal; u3 = u2 * uVal; f1u = 2.0 * u3 - 3 * u2 + 1.0; f2u = -2.0 * u3 + 3.0 * u2; f3u = u3 - 2.0 * u2 + uVal; f4u = u3 - u2; valx1 = f1u * (p1x * f1w + p2x * f2w + p1wx * f3w + p2wx * f4w); valx2 = f2u * (p3x * f1w + p4x * f2w + p3wx * f3w + p4wx * f4w); valx3 = f3u * (p1ux * f1w + p2ux * f2w + p1uwx * f3w + p2uwx * f4w); valx4 = f4u * (p3ux * f1w + p4ux * f2w + p3uwx * f3w + p4uwx * f4w); valueX = valx1 + valx2 + valx3 + valx4; valy1 = f1u * (p1y * f1w + p2y * f2w + p1wy * f3w + p2wy * f4w); valy2 = f2u * (p3y * f1w + p4y * f2w + p3wy * f3w + p4wy * f4w); valy3 = f3u * (p1uy * f1w + p2uy * f2w + p1uwy * f3w + p2uwy * f4w); valy4 = f4u * (p3uy * f1w + p4uy * f2w + p3uwy * f3w + p4uwy * f4w); valueY = valy1 + valy2 + valy3 + valy4; valz1 = f1u * (p1z * f1w + p2z * f2w + p1wz * f3w + p2wz * f4w); valz2 = f2u * (p3z * f1w + p4z * f2w + p3wz * f3w + p4wz * f4w); valz3 = f3u * (p1uz * f1w + p2uz * f2w + p1uwz * f3w + p2uwz * f4w); valz4 = f4u * (p3uz * f1w + p4uz * f2w + p3uwz * f3w + p4uwz * f4w); valueZ = valz1 + valz2 + valz3 + valz4; return { xVal: valueX, yVal: valueY, zVal: valueZ, };}7.2 验证以下是验证方面: 当使用它们的滑块改变边界点的坐标时,相应的边界点应该在指定的 x、y 或 z 方向上变化,并且表面应该相应地改变。当使用滑块更改 u 或 v 方向的切线矢量时,也会发生同样的情况,尽管这种变化不像更改坐标值时那样明显。类似地,当扭曲向量发生变化时,曲面也应该发生变化。还显示了一些预定义的表面,这些表面在单击左窗格底部的按钮时出现。8、贝塞尔曲面贝塞尔曲线的二维(在参数空间中)等价物是贝塞尔曲面。 这种表面的方程式如下: 8.1 贝塞尔曲面的代码以下 JavaScript 函数在文件 script4.js 中计算贝塞尔曲面上的一个点。 出于本文的目的,所提供的代码适用于 4 x 4 贝塞尔曲面,共有 16 个控制点。 对应的 HTML 文件是 page4.html。 function computeBezierSurfacePoint(uVal, wVal) { let u2, u3, w2, w3; u2 = uVal * uVal; u3 = uVal * u2; w2 = wVal * wVal; w3 = wVal * w2; // Need to note the following regarding THREE.js Matrix4. // When we set the matrix, we set it in row major order. // However, when we access the elements of this matrix, these are // returned in column major order. let matC = new THREE.Matrix4(); matC.set(-1, 3, -3, 1, 3, -6, 3, 0, -3, 3, 0, 0, 1, 0, 0, 0); let matPx = new THREE.Matrix4(); matPx.set( p00x, p10x, p20x, p30x, p01x, p11x, p21x, p31x, p02x, p12x, p22x, p32x, p03x, p13x, p23x, p33x ); let matPy = new THREE.Matrix4(); matPy.set( p00y, p10y, p20y, p30y, p01y, p11y, p21y, p31y, p02y, p12y, p22y, p32y, p03y, p13y, p23y, p33y ); let matPz = new THREE.Matrix4(); matPz.set( p00z, p10z, p20z, p30z, p01z, p11z, p21z, p31z, p02z, p12z, p22z, p32z, p03z, p13z, p23z, p33z ); let mat1x = new THREE.Matrix4(); mat1x.multiplyMatrices(matC, matPx); let mat1y = new THREE.Matrix4(); mat1y.multiplyMatrices(matC, matPy); let mat1z = new THREE.Matrix4(); mat1z.multiplyMatrices(matC, matPz); let mat2x = new THREE.Matrix4(); mat2x.multiplyMatrices(mat1x, matC); let mat2y = new THREE.Matrix4(); mat2y.multiplyMatrices(mat1y, matC); let mat2z = new THREE.Matrix4(); mat2z.multiplyMatrices(mat1z, matC); // We access the matrix elements in column major order. let ex = mat2x.elements; let w0x = ex[0] * w3 + ex[4] * w2 + ex[8] * wVal + ex[12]; let w1x = ex[1] * w3 + ex[5] * w2 + ex[9] * wVal + ex[13]; let w2x = ex[2] * w3 + ex[6] * w2 + ex[10] * wVal + ex[14]; let w3x = ex[3] * w3 + ex[7] * w2 + ex[11] * wVal + ex[15]; let ey = mat2y.elements; let w0y = ey[0] * w3 + ey[4] * w2 + ey[8] * wVal + ey[12]; let w1y = ey[1] * w3 + ey[5] * w2 + ey[9] * wVal + ey[13]; let w2y = ey[2] * w3 + ey[6] * w2 + ey[10] * wVal + ey[14]; let w3y = ey[3] * w3 + ey[7] * w2 + ey[11] * wVal + ey[15]; let ez = mat2z.elements; let w0z = ez[0] * w3 + ez[4] * w2 + ez[8] * wVal + ez[12]; let w1z = ez[1] * w3 + ez[5] * w2 + ez[9] * wVal + ez[13]; let w2z = ez[2] * w3 + ez[6] * w2 + ez[10] * wVal + ez[14]; let w3z = ez[3] * w3 + ez[7] * w2 + ez[11] * wVal + ez[15]; let qx = u3 * w0x + u2 * w1x + uVal * w2x + w3x; let qy = u3 * w0y + u2 * w1y + uVal * w2y + w3y; let qz = u3 * w0z + u2 * w1z + uVal * w2z + w3z; return { xVal: qx, yVal: qy, zVal: qz, };}8.2 验证同样,当任何控制点(坐标)发生变化时,相应的表面也应发生变化。 这可以通过查看渲染的表面来验证。显示了许多有趣的表面,可通过单击它们的按钮获得。9、NURBS曲面NURBS 曲线的二维(在参数空间中)等价物是 NURBS 曲面。 NURBS 曲面相对于其他两种曲面的优势在于 NURBS 曲面提供了对曲面的局部控制。修改控制点的坐标只会影响该控制点附近的表面,而表面的其余部分不受影响。这是因为对应于 NURBS 曲面的基函数。 9.1 NURBS 曲面代码Three.js 库的创建者再次提供了一个 JavaScript 文件来计算 NURBS 曲面上一个点的坐标,我们从那里提取了相关内容,并将其用于此应用程序。它们位于 NurbsHelper.js 文件中。与 NURBS 曲线的情况一样,定义了 u 和 w 方向的两个结向量。在此应用程序中,我们定义了一个在 u 和 w 方向各有 7 个控制点的 NURBS 曲面。因此,共有 49 个控制点可供用户修改。对于这些控制点中的每一个,用户都可以在范围内更改 x、y、z、h 值。NURBS Surface的计算代码在文件script6.js中,如下。 HTML 是 page6.html。 function computeNurbsSurface() { nurbsSurface = new NURBSSurface( degreeU, degreeW, knotVectorU, knotVectorW, points ); surfacePoints.length = 0; let uVal, wVal; for (let j = 0; j <= noDivisions; ++j) { wVal = j * step; for (let i = 0; i <= noDivisions; ++i) { uVal = i * step; let pt = new Vector3(); nurbsSurface.getPoint(uVal, wVal, pt); //let poi = new THREE.Vector3(); surfacePoints.push(pt.x, pt.y, pt.z); } } renderNurbsSurface();}10、兴趣点我的意图是将每种类型的曲线/曲面都放在自己的文件夹中,独立包含自己的 HTML 和 JS 文件。这是使它们各自的逻辑彼此分离的方式。它们都引用相同的 three.min.js 文件,即 WebGL 库文件。此外,它们都引用相同的 style.css 文件。因此,安排是有六个不同的文件夹,p01CubicCurve、p02CubicSurface、p03BezierCurve、p04BezierSurface、p05NurbsCurve和p06NurbsSurface。每个文件夹都有其 HTML 和 JS 文件。另外还有一个js文件夹,里面有三个文件,three.min.js、script.js和NurbsHelper.js。通过上面的代码安排,可能会有一些代码重复。例如,绘制边界框的那部分代码在六个 JS 文件中被复制了六次,script1.js、script2.js、script3.js、script4.js、script5.js、script6.js。我保留了它是故意这样的,因为任何想要获取这些单独文件的学习者现在都可以从它们单独的文件夹中获取它们并直接在他们的应用程序中使用它们,而无需集成代码的麻烦。这些文件夹之外唯一需要获取的代码是 three.min.js 缩小库文件和 CSS 文件。你可能会注意到,应用程序中没有文本框类型的输入。用户交互仅通过滑块、复选框、组合框和按钮发生。这是我对软件进行防错的方法。我希望你不会“崩溃”这个应用程序。如果您遇到此应用程序崩溃、屏幕变黑或出现其他形式的不当行为的情况,请随时通过下面的评论部分通知我。使用最新版本的 Three.js(版本 125),对几何图形的处理方式进行了重大更改。他们删除了 THREE.Geometry 并引入了 THREE.BufferGeometry。由于我不希望对 Three.js 库进行任何进一步的修改以影响我的代码的行为,因此我在代码中包含了该库的缩小版本。这样,代码是独立的,可以在没有 Internet 连接的情况下使用本地服务器运行。该应用程序本身有一个简单直观的用户界面,没有任何多余的装饰和花哨的东西。有一个菜单,可以在其中选择所需的曲线和曲面类型。选择菜单项后,菜单下方会出现相应的屏幕。左侧窗格中是滑块和其他控件,用于修改右侧 HTML Canvas 元素上的 3D 对象。用户不能直接与 Canvas 元素交互,只能通过左侧的控件进行交互。这里描述的数学并不新鲜,已有四十多年的历史了。有许多应用此数学来创建几何模型的软件包。然而,这里展示的打包方式,以一种在完全客户端 JavaScript 代码中运行的自包含方式,似乎是新的。下面给出了一些可以使用此应用程序设计的表面的图库: 11、结束语在本文中,我们描述并演示了使用 Three.js 库在浏览器上以 3D 方式绘制这六个几何对象的代码 - 参数立方曲线、贝塞尔曲线、NURBS 曲线、库恩斯双三次曲面、贝塞尔曲面和 NURBS 曲面.该应用程序允许您修改各个控制点的坐标(在范围内),在某些情况下,还可以修改切线(导数)的方向。用户还可以在线框中查看曲面,并更改相机角度,从不同方向查看曲线或曲面。所有这些都是用纯 Vanilla JavaScript 编码的,我已经在 Chrome、Safari 和 Edge 浏览器上对其进行了测试。我喜欢编写这段代码的每一点,尤其是第一次在 3D 屏幕上移动滑块时,当滑块移动时,我感到非常激动。我希望你喜欢使用该应用程序,并在使用滑块更改控制点时查看这些动态变化的曲线和曲面。原文链接:http://www.bimant.com/blog/3d-curves-n-surfaces-in-three-js/