美文网首页W3C
TWaver3D直线、曲线、曲面的绘制

TWaver3D直线、曲线、曲面的绘制

作者: Cesium4Unreal | 来源:发表于2017-08-05 10:25 被阅读64次

    1. WebGL原生线

    WebGL支持绘制点、线、三角;绘制线的方法比较简单,给定顶点,设置绘制方式即可;

    image.png image.png

    假设给定顶点信息为:

    var vertices = new Float32Array([
         0.0, 0.5, -0.5, -0.5, 0.25, -0.5
    ]);
    

    调用gl.drawArrays(gl.LINE_STRIP, 0, 3);后效果如下:
    Chrome:

    image.png

    Safari:

    image.png
    另外还有个兼容性问题,在Windows上,绘制线的时候无法指定线宽。OpenGL本身有glLineWidth这个方法,而且在WebGL中也有这个方法。但是在Windows虽然调用不会失败,但是也不会生效,无论是在Chrome还是在FireFox上测试都无效。但是Linux上有效,应该是操作系统的限制问题。这个问题之前就有人提出过,如果有兴趣可以看看https://bugs.chromium.org/p/chromium/issues/detail?id=60124。也许在以后的WebGL版本中会修复这个问题吧。测试网站http://alteredqualia.com/tmp/webgl-linewidth-test/
    设置lineWidth为10后,Chrome效果不变,Safari线条加粗了. image.png

    测试网站测试:
    Chrome不正常

    image.png

    Safari正常

    image.png

    FireFox正常:

    image.png
    是Chrome长期存在的一个Bug: https://bugs.chromium.org/p/chromium/issues/detail?id=60124 image.png
    可以参考WebGL大咖彪叔的文章:WebGL 绘制Line的bug

    2. mono.Line类

    构造函数:

    image.png

    实线:

    var line = new mono.Line({
            vertices:[
            new mono.Vec3( -100, 0, 0 ),
            new mono.Vec3( 100, 100, 0 ),
            ],
            type:'mono.LinePieces',
            styles:{
              'm.color':'red',
            },
          });
    box.add(line);
    
    image.png

    虚线
    原来的参数是通过segments来计算出更多的顶点信息;其实可以通过配置line的style属性,如line.pattern = [10,2]来计算出顶点信息;
    封装了mono.Line.createDottedLine方法,用于根据pattern创建虚线;

    var line = new mono.Line({
            type:TGL.LinePieces,
            styles:{
              'm.color':'green',
              'm.type': 'phong',
              'm.ambient': 'red',
            }
          });
     
          line = mono.Line.createDottedLine(line,[
            new mono.Vec3( -200, 100, -100 ),
            new mono.Vec3( 160, 100, 0 ),
            new mono.Vec3( 300, -100, 100 ),
            new mono.Vec3( -300, -100, 200 ),
            new mono.Vec3( -200, 100, 0 ),
            new mono.Vec3( -200, 100, -100 ),
            ],[6,12]);
    
    image.png

    改变pattern后的效果:实线长一点,虚线短些;

    image.png

    创建矩形:

    mono.Line.createRectangle = function(width, height, segments) {
    // width:宽度, height:高度, segments:分片数
     
    var line = mono.Line.createRectangle(200,200,10);
          line.setType(TGL.LineStrip);
          line.setPositionY(-30);
          line.setPositionX(20);
          line.setStyle('m.color','red');
    box.add(line);
    
    image.png

    创建椭圆,并分段设置颜色

    var line = mono.Line.createEllipse(120,80,100,Math.PI * 2,0,true);
         line.setPositionY(0);
         line.setPositionX(0);
         line.setMaterialStyle('vertexColors',true);
         line.setMaterialStyle('linewidth',10);
         line.setMaterialStyle('linejoin','miter');
         line.setType(TGL.LinePieces);
         var vertices = line.getVertices();
         var colors = [], color;
         for(var i = 0;i<vertices.length;i++){
           var vertex = vertices[i];
           if(vertex.x > 0 && vertex.y > 0){
             color = new mono.Color('red');
           }else if(vertex.x > 0 && vertex.y < 0){
             color = new mono.Color('green');
           }else if(vertex.x < 0 && vertex.y < 0){
             color = new mono.Color('orange');
           }else{
             color = new mono.Color('yellow');
           }
           colors.push(color);
         }
         line.setColors(colors);
         box.add(line);
    
    image.png image.png
    //创建Helix螺旋状线条
    //mono.Line.createHelix = function(line,startRadius, endRadius, height, turns, segments)
    // startRadius:起始半径, endRadius:结束半径, height:高度, turns:转数, segments:分片数
    var line = mono.Line.createHelix(-100,250,200,10,400);
          line.setPositionY(30);
          line.setPositionX(20);
          line.setMaterialStyle('linewidth',10);
          line.setStyle('m.color','red');
          box.add(line);
    
    image.png
    //创建Ellipse椭圆线条
     // mono.Line.createEllipse(xRadius, yRadius, segments, aStartAngle, aEndAngle, aClockwise)
    // xRadius,yRadius:椭圆的半径,segments:分片数量,aStartAngle:起始角度,aEndAngle:结束角度,aClockwise:是否逆时针
          var line = mono.Line.createEllipse(120,80,100,0,Math.PI/2,true); //
          line.setType(TGL.LinePieces);
          line.setPositionY(30);
          line.setPositionX(20);
          line.setStyle('m.color','red');
          line.setMaterialStyle('linewidth',10);
    box.add(line);
    
    image.png

    3. mono.LineX类

    正如上文所说,Chrome不支持设置线宽,只能自己模拟;于是创建了mono.LineX;
    如图,蓝色的为LineX效果。可用于绘制管线等效果;

    var lineX = new mono.LineX([
            {x:-180, y:100,z: -100},
            {x:120, y:100, z:0},
            {x:280, y:-100, z:100},
            {x:-280, y:-100, z:200},
            {x:-180, y:100, z:0},
            {x:-180, y:100, z:-100},
            ], ['red', 'red', 'red', 'red'], 10);
          lineX.setStyle('m.color','blue');
    
    
    image.png

    4. mono.PathNode、mono.PathLine、mono.PathCube

    路径体(mono.PathNode)这是一种复杂的形状体,由两个任意形状进行控制:切面形状,以及前进走向。最终形状是该切面形状沿着前进走向进行移动而形成的物体。例如,一个圆形切面沿着一个多边形移动,就会形成一个复杂的管线物体。这种形状还可以控制两个端头是否封闭、封闭的形状和尺寸,横切方向是否闭合、闭合角度、闭合样式等。通过控制这些参数,可以创建例如管线、弯管、香肠体、切开的管线等。

    image.png image.png
    详细参考TWaver官方文档,本文不再累述。http://doc.servasoft.com/twaver-document-center/recommended/twaver-html5-3d-v2/using-elements/elements/#monoPathNode

    5. mono.NurbsCurve类

    image.png

    权威书籍:《非均匀有理B样条(第2版)》
    非均匀有理B样条,通常简称为NURBS(Non-Uniform Rational B-Splines),实际上已经成为利用计算机处理集合信息时用于形状的表示、设计和数据交换的工业标准。许多国内和国际标准,如IGES,STEP和PHIGS都把NURBS作为集合设计的一个强有力的工具。NURBS取得的巨大成功主要由于以下事实[1]:
    NURBS为解析曲线曲面(如圆锥截线和二次曲面)和自由型曲线曲面(如汽车车身和船体外形)的表示提供一种统一的数学方法;
    利用NURBS进行设计非常直观,几乎每个工具和算法都有一个易于理解的几何解释;
    NURBS的算法执行速度很快,并且数值稳定;
    NURBS曲线曲面在通常的几何变换(如平移、旋转、平行和透视投影)下是不变的;
    NURBS是非有理B样条、有理以及非有理Bezier曲线曲面的推广;

    对于大部分人来说,B样条、有理B样条和NURBS有点神秘,有人成NURBS为无人能理解的有理B样条曲线(NoBody Understand Relation B-Splines);
    研究NURBS的当前首要目的在于呈现三维数据场的可视化,可参考书籍《三维数据场可视化》[2];
    NURBS曲线,貌似比较神秘,其实也非常的容易理解;制作模型的曲线一定要逼真,曲线越逼真,模型就会越真实。而一般的直线,曲线是很难达到这样效果的,所以引入了NURBS曲线。

    /**
     * {[TGL.Line]}  line  
     * {[Array of vector(3|4)]]}  ctrlPoints  曲线的控制点
     * {[Number]}  degree 曲线的最高指数
     * {[Number]} count  曲线每段需要插入点的个数
     * {[Object]} ctrlCond 线条控制条件
     */
     
    TGL.Line.createNurbs = function(line, ctrlPoints, degree, count, ctrlCond){}
    
     
    随机单色波浪线:
    var points = [0,-200,500,0,1000,-400,-10,500,-1000,0,0,100,-100,0,0,0,0,0];
          var ctrlPoints = [];
          for ( var i = 0, j = 10; i < j; i ++ ) {
            ctrlPoints.push(
              new TGL.Vec3(
                -500 + 100 * i ,
                points[i],
                0));
          }
         
          var line = mono.Line.createNurbs(ctrlPoints,3, 50, {
          });
          line.s({
            'm.type': 'phong',
            'm.color':'green'
          });
          line.setMaterialStyle('linewidth',10);
          line.setType(TGL.LineStrip);
    box.add(line);
    
    image.png

    在实际应用中,我们会根据曲线的高度值,设置不同的颜色,来模拟温度场之类的效果。

    var line = mono.Line.createNurbs(ctrlPoints,3, 50, {
           skyY : 100,
           skyColor : new mono.Color('red'),
           horizonY: 0,
           horizonColor: new mono.Color('yellow'),
           earthY : -100,
           earthColor: new mono.Color('green'),
         });
    
    image.png

    再制作一个弹簧效果

    image.png

    这只是用一些数学公式模拟出来的效果,如若使用比较真实的数据,看看效果如何:

    image.png

    大黄兔正脸照

    image.png

    侧脸照

    image.png

    一句话,逼真!

    5. mono.NurbsSurface

    /**
     * NurbsSurface 非均匀有理样条B样条曲面
     * NURBS是非有理B样条、有理以及非有理Bezier曲线曲面的推广
     * @class mono.NurbsSurface
     * @constructor
     * @extends mono.Curve
     * @param {Number} [degreeU] U方向阶数 <= U点数 - 1
     * @param {Number} [degreeV] V方向阶数 <= V点数 - 1
     * @param {Number} [ctrlPoints] 曲面的控制点
     * @return {mono.NurbsSurface} NurbsSurface对象
     * @example
     * 
     */
    
    var ctlPoints = [
          [
          new mono.Vec4(-200, 0, -200, 1 ),
          new mono.Vec4(-200, 100, -100, 1 ),
          new mono.Vec4(-200, -100, 100, 1 ),
          new mono.Vec4(-200, 0, 200, 1 ),
          new mono.Vec4(-200, 100, 200, 1 ),
          new mono.Vec4(-200, 0, 300, 1 ),
          ],
          [
          new mono.Vec4(0, 0, -200, 1 ),
          new mono.Vec4(0, 100, -100, 1 ),
          new mono.Vec4(0, -100, 100, 1 ),
          new mono.Vec4(0, 0, 200, 1 ),
          new mono.Vec4(0, 100, 200, 1 ),
          new mono.Vec4(0, 0, 300, 1 ),
          ],
          ];
          var degreeU = 0;// 阶数 <= 点数 - 1 = 3 -1
          var degreeV = 3;//阶数 <= 点数 - 1 = 6 - 1
     
          var nurbsSurface = new mono.NurbsSurface(degreeU, degreeV, ctlPoints);
          var surface = window.surface = new mono.Surface(nurbsSurface, 3,150,{
            skyY : 100,
            horizonY: 0,
            earthY : -100,
            skyColor : new mono.Color('red'),
            horizonColor: new mono.Color('gray'),
            earthColor: new mono.Color('green'),
          });
          surface.s(
          {
            'm.type': 'basic',
            'm.color': 'white',
            'm.side':mono.DoubleSide,
            'm.ambient': 'white',
            // 'm.texture.image':'./images/collage.jpg',
            // 'm.wireframe':true,
            'm.wireframeLinewidth': 1,
            'm.wireframeLinecolor': 'orange',
            'm.wireframeLineopacity': 1,
          });
          surface.setSelectable(false);
          box.add(surface);
    
    image.png

    将一幅2D温度云图转换为3D效果:

    image.png image.png

    结合数学知识,可以展现各种各样的效果:
    番茄天空盒(内嵌温度场)

    image.png

    图像RGB展示

    image.png

    引力场

    image.png

    6.参考链接:

    [1].http://codeazur.com.br/experiments/webgl_curve_1/
    [2].https://mattdesl.svbtle.com/drawing-lines-is-hard
    [3].https://www.khronos.org/webgl/wiki/Demo_Repository
    [4].http://nurbscalculator.in/
    [5].http://omni360.github.io/webcad/Org/three.js-master/examples/webgl_geometry_ctrnurbs2d.html
    [6].https://www.ibiblio.org/e-notes/Splines/Intro.htm
    [7].https://www.ibiblio.org/e-notes/webgl/models.htm#spline

    相关文章

      网友评论

        本文标题:TWaver3D直线、曲线、曲面的绘制

        本文链接:https://www.haomeiwen.com/subject/delilxtx.html