文档章节

OpenGL基础图形编程 - 复杂物体建模

小青_1989
 小青_1989
发布于 2014/06/05 14:31
字数 5775
阅读 738
收藏 1
点赞 0
评论 0

13.1 图元扩展

  13.1.1 点和线
  下面分别介绍点和线的扩展形式及用法。
  1)点。OpenGL中定义的点可以有不同的尺寸,其函数形式为:

  void glPointSize(GLfloat size);

  设置点的宽度(以象素为单位)。参数size必须大于0.0,缺省时为1.0。

  2)线。OpenGL能指定线的各种宽度和绘制不同的虚点线,如点线、虚线等。相应的函数形式如下:

  void glLineWidth(GLfloat width);

  设置线宽(以象素为单位)。参数width必须大于0.0,缺省时为1.0。

  void glLineStipple(GLint factor,GLushort pattern);

  设置线为当前的虚点模式。参数pattern是一系列的16位数(0或1),它重复地赋给所指定的线。其中每一位代表一个象素,且从低位开始,1表示用当前颜色绘制一个象素(或比例因子指定的个数),0表示当前不绘制,只移动一个象素位(或比例因子指定的个数)。参数factor是个比例因子,它用来拉伸pattern中的元素,即重复绘制1或移动0,比如,factor为2,则碰到1时就连续绘制2次,碰到0时连续移动2个单元。factor的大小范围限制在1到255之间。在绘制虚点线之前必须先启动一下,即调用函数glEnable(GL_LINE_STIPPLE);若不用,则调用glDisable(GL_LINE_STIPPLE)关闭。下面举出一个点线扩展应用实例: 

  例13-1 点线扩展应用例程expntlin.c

  #include "glos.h"
  #include <GL/gl.h>
  #include <GL/glu.h>
  #include <GL/glaux.h>

  void myinit(void);
  void line2i(GLint x1,GLint y1,GLint x2,GLint y2);
  void CALLBACK display(void); void myinit (void)
  {
    glClearColor (0 , 0.0, 0.0, 0.0);
    glShadeModel (GL_FLAT);
  }

  void line2i(GLint x1,GLint y1,GLint x2,GLint y2)
  {
    glBegin(GL_LINES);
    glVertex2f(x1,y1);
    glVertex2f(x2,y2);
    glEnd();
  }

  void CALLBACK display(void)
  {
    int i;

    glClear (GL_COLOR_BUFFER_BIT);


    /* 第一行绘制的是一系列大小尺寸不同的点(以象素为基本扩展单元) */
    glColor3f(0.8,0.6,0.4);
    for (i = 1; i <= 10; i++)
    {
      glPointSize(i*2);
      glBegin (GL_POINTS);
        glVertex2f (30.0 + ((GLfloat) i * 50.0), 330.0);
      glEnd ();
    }


    /* 第二行绘制的是三条不同线型的线段 */

    glEnable (GL_LINE_STIPPLE);

    glLineStipple (1, 0x0101);
 /* 点线 */
    glColor3f(1.0 ,0.0,0.0);
    line2i (50, 250, 200, 250);

    glLineStipple (1, 0x00FF);
 /* 虚线 */
    glColor3f(1.0,1.0,0.0);
    line2i (250 , 250 , 400, 250 );

    glLineStipple (1, 0x1C47);
 /* 虚点线 */
    glColor3f(0.0,1.0,0.0);
    line2i (450 , 250 , 600 , 250 );


    /* 第三行绘制的是三条不同宽度的线段 */

    glLineWidth (5.0);
    glLineStipple (1, 0x0101);
    glColor3f(1.0 ,0.0,0.0);
    line2i (50 , 200 , 200 , 200 );

    glLineWidth (3.0);
    glLineStipple (1, 0x00FF);
    glColor3f(1.0 ,1.0,0.0);
    line2i (250 , 200 , 400 , 200 );

    glLineWidth (2.0);
    glLineStipple (1, 0x1C47);
    glColor3f(0.0 ,1.0,0.0);
    line2i (450 , 200 , 600 , 200 );


    /* 设置以下线段的宽度为 1 */
    glLineWidth(1);

    /* 第四行绘制的是一条虚点线 */

    glLineStipple (1, 0xff0c);
    glBegin (GL_LINE_STRIP);
      glColor3f(0.0 ,1.0,1.0);
      for (i = 0; i < 12; i++)
        glVertex2f (50.0 + ((GLfloat) i * 50.0), 150.0);
      glEnd ();


    /* 第五行绘制的是十条独立的虚点斜线 */

    glColor3f(0.4 ,0.3,0.8);
    for (i = 0; i < 10; i++)
    {
      line2i (50 + ( i * 50), 70, 75 + ((i+1) * 50), 100);
    }


    /* 第六行绘制的是一条虚点线,其中线型模式每个元素被重复操作5次 */

    glLineStipple (5, 0x1C47);
    glColor3f(1.0 ,0.0,1.0);
    line2i (50 , 25 , 600 , 25 );

    glFlush ();
  }

  void main(void)
  {
    auxInitDisplayMode (AUX_SINGLE | AUX_RGBA);
    auxInitPosition (0, 0, 650, 450);
    auxInitWindow ("External Points and Lines");
    myinit ();
    auxMainLoop(display);
  }


  以上程序运行结果是显示不同尺寸的点及不同线型和宽度的线的绘制方式。

图13-1 扩展点线


  13.1.2 多边形
  多边形的绘制模式包含有好几种:全填充式、轮廓点式、轮廓线式以及图案填充式。下面分别介绍相应的OpenGL函数形式。
  1)多边形模式设置。其函数为:

  void glPolygonMode(GLenum face,GLenum mode);

  控制多边形指定面的绘制模式。参数face为GL_FRONT、GL_BACK或GL_FRONT_AND_BACK;参数mode为GL_POINT、GL_LINE或GL_FILL,分别表示绘制轮廓点式多边形、轮廓线式多边形或全填充式多边形。缺省时,绘制的是正反面全填充式多边形。

  2)设置图案填充式多边形。其函数为:

  void glPolygonStipple(const GLubyte *mask);

  为当前多边形定义填充图案模式。参数mask是一个指向32x32位图的指针。与虚点线绘制的道理一样,某位为1时绘制,为0时什么也不绘。注意,在调用这个函数前,必须先启动一下,即用glEnable(GL_POLYGON_STIPPLE);不用时用glDisable(GL_POLYGON_STIPPLE)关闭。下面举出一个多边形扩展绘制实例:

  例 13-2 多边形图案填充例程polystpl.c

  #include "glos.h"
  #include <GL/gl.h>
  #include <GL/glu.h>
  #include <GL/glaux.h>

  void myinit(void);
  void CALLBACK display(void);

  void myinit (void)
  {
    glClearColor (0.0, 0.0, 0.0, 0.0);
    glShadeModel (GL_FLAT);
  }

  void CALLBACK display(void)
  {


    /* 填充模式定义 (32x32) */
    GLubyte pattern[]= {
      0x00, 0x01, 0x80, 0x00,
      0x00, 0x03, 0xc0, 0x00,
      0x00, 0x07, 0xe0, 0x00,
      0x00, 0x0f, 0xf0, 0x00,
      0x00, 0x1f, 0xf8, 0x00,
      0x00, 0x3f, 0xfc, 0x00,
      0x00, 0x7f, 0xfe, 0x00,
      0x00, 0xff, 0xff, 0x00,
      0x01, 0xff, 0xff, 0x80,
      0x03, 0xff, 0xff, 0xc0,
      0x07, 0xff, 0xff, 0xe0,
      0x0f, 0xff, 0xff, 0xf0,
      0x1f, 0xff, 0xff, 0xf8,
      0x3f, 0xff, 0xff, 0xfc,
      0x7f, 0xff, 0xff, 0xfe,
      0xff, 0xff, 0xff, 0xff,
      0xff, 0xff, 0xff, 0xff,
      0x7f, 0xff, 0xff, 0xfe,
      0x3f, 0xff, 0xff, 0xfc,
      0x1f, 0xff, 0xff, 0xf8,
      0x0f, 0xff, 0xff, 0xf0,
      0x07, 0xff, 0xff, 0xe0,
      0x03, 0xff, 0xff, 0xc0,
      0x01, 0xff, 0xff, 0x80,
      0x00, 0xff, 0xff, 0x00,
      0x00, 0x7f, 0xfe, 0x00,
      0x00, 0x3f, 0xfc, 0x00,
      0x00, 0x1f, 0xf8, 0x00,
      0x00, 0x0f, 0xf0, 0x00,
      0x00, 0x07, 0xe0, 0x00,
      0x00, 0x03, 0xc0, 0x00,
      0x00, 0x01, 0x80, 0x00
    };

    glClear (GL_COLOR_BUFFER_BIT);


    /* 绘制一个指定图案填充的矩形 */

    glColor3f(0.1,0.8,0.7);
    glEnable (GL_POLYGON_STIPPLE);
    glPolygonStipple (pattern);
    glRectf (48.0, 80.0, 210.0, 305.0);


    /* 绘制一个指定图案填充的三角形 */
    glColor3f(0.9,0.86,0.4);
    glPolygonStipple (pattern);
    glBegin(GL_TRIANGLES);
      glVertex2i(310,310);
      glVertex2i(220,80);
      glVertex2i(405,80);
    glEnd();

    glDisable (GL_POLYGON_STIPPLE);

    glFlush ();
  }

  void main(void)
  {
    auxInitDisplayMode (AUX_SINGLE | AUX_RGBA);
    auxInitPosition (0, 0, 500, 400);
    auxInitWindow ("Polygon Stippling");
    myinit ();
    auxMainLoop(display);
  }


图13-2 图案填充多边形


13.2、法向计算
  法向,又称法向量(Mormal Vector)。对于一个平面,其上各点的法向的一样,统一为这个平面的法向,所以称为平面法向。对于一个曲面,虽然它在计算机图形中是由许多片小的平面多边形逼近,但是每个顶点的法向都不一样,因此曲面上每个点的法向计算就可以根据不同的应用有不同的算法,则最后效果也不相同。OpenGL有很大的灵活性,它只提供赋予当前顶点法向的函数,并不在内部具体计算其法向量,这个值由编程者自己根据需要计算。下面介绍一下法向基本计算方法和OpenGL法向定义。 

  13.2.1 法向基本计算方法
  首先,讲述平面法向的计算方法。在一个平面内,有两条相交的线段,假设其中一条为矢量W,另一条为矢量V,且平面法向为N,如图13-3所示,则平面法向就等于两个矢量的叉积(遵循右手定则),即N=WxV。

图13-3 平面法向计算


  比如计算一个三角形平面的法向,就可以用它的三个顶点来计算,如图13-4所示。

图13-4 三角形平面法向计算


  设三个顶点分别为P0、P1、P2,相应两个向量为W、V,则三角平面法向的计算方式见下列一段代码:

  /* ------ get value of N (normal vector) ---------- */
  void getNormal(GLfloat gx[3],GLfloat gy[3],GLfloat gz[3],GLfloat *ddnv)
  {
    GLfloat w0,w1,w2,v0,v1,v2,nr,nx,ny,nz;

    w0=gx[0]-gx[1]; w1=gy[0]-gy[1]; w2=gz[0]-gz[1];
    v0=gx[2]-gx[1]; v1=gy[2]-gy[1]; v2=gz[2]-gz[1];
    nx=(w1*v2-w2*v1);
    ny=(w2*v0-w0*v2);
    nz=(w0*v1-w1*v0);
    nr=sqrt(nx*nx+ny*ny+nz*nz);
    ddnv[0]=nx/nr; ddnv[1]=ny/nr; ddnv[2]=nz/nr;
  }


  以上函数的输出参数为指针ddnv,它指向法向的三个分量,并且程序中已经将法向单位化(或归一化)了。
  此外,对于曲面各顶点的法向计算有很多种,最常用的是平均平面法向法,如图15-5 所示。在图中,曲面顶点P的法向就等于其相邻的四个平面的法向平均值,即:

Np = (N1+N2+N3+N4)/4


图13-5 曲面顶点的平均法向计算


  13.2.2 法向定义
  OpenGL法向定义函数为:

  void glNormal3{bsifd}(TYPE nx,TYPE ny,TYPE nz);
  void glNormal3{bsifd}v(const TYPE *v);


  设置当前法向值。非向量形式定义法向采用第一种方式,即在函数中分别给出法向三个分量值nx、ny和nz;向量形式定义采用第二种,即将v设置为一个指向拥有三个元素的指针,例如v[3]={nx,ny,nz}。因为法向的各分量值只定义法向的方向,因此它的大小不固定,但建议最好将各值限制在[-1.0,1.0]之间,即法向归一化;若法向不归一化,则在定义法向之前必须启动法向归一,即调用函数glEnable(GL_NORMALIZE),这样会降低整个程序运行性能。下面举出一个自己定义法向的例子:

  例13-3 自定义颜色立方体法向例程nmlcolr.c

  #include "glos.h"
  #include <GL/gl.h>
  #include <GL/glu.h>
  #include <GL/glaux.h>

  static GLfloat p1[]={0.5,-0.5,-0.5}, p2[]={0.5,0.5,-0.5},
          p3[]={0.5,0.5,0.5},  p4[]={0.5,-0.5,0.5},
          p5[]={-0.5,-0.5,0.5}, p6[]={-0.5,0.5,0.5},
          p7[]={-0.5,0.5,-0.5}, p8[]={-0.5,-0.5,-0.5};

  static GLfloat m1[]={1.0,0.0,0.0},  m2[]={-1.0,0.0,0.0},
          m3[]={0.0,1.0,0.0},  m4[]={0.0,-1.0,0.0},
          m5[]={0.0,0.0,1.0},  m6[]={0.0,0.0,-1.0};

  static GLfloat c1[]={0.0,0.0,1.0},  c2[]={0.0,1.0,1.0},
          c3[]={1.0,1.0,1.0},  c4[]={1.0,0.0,1.0},
          c5[]={1.0,0.0,0.0},  c6[]={1.0,1.0,0.0},
          c7[]={0.0,1.0,0.0},  c8[]={1.0,1.0,1.0};

  void myinit(void);
  void CALLBACK myReshape(GLsizei w, GLsizei h);
  void CALLBACK display(void);
  void DrawColorBox(void);

  void myinit(void)
  {
    GLfloat light_ambient[]={0.3,0.2,0.5};
    GLfloat light_diffuse[]={1.0,1.0,1.0};
    GLfloat light_position[] = { 2.0, 2.0, 2.0, 1.0 };

    GLfloat light1_ambient[]={0.3,0.3,0.2};
    GLfloat light1_diffuse[]={1.0,1.0,1.0};
    GLfloat light1_position[] = { -2.0, -2.0, -2.0, 1.0 };

    glLightfv(GL_LIGHT0, GL_AMBIENT, light_ambient);
    glLightfv(GL_LIGHT0, GL_DIFFUSE, light_diffuse);
    glLightfv(GL_LIGHT0, GL_POSITION, light_position);

    glLightfv(GL_LIGHT1, GL_AMBIENT, light1_ambient);
    glLightfv(GL_LIGHT1, GL_DIFFUSE, light1_diffuse);
    glLightfv(GL_LIGHT1, GL_POSITION, light1_position);

    glEnable(GL_LIGHTING);
    glEnable(GL_LIGHT0);
    glEnable(GL_LIGHT1);

    glDepthFunc(GL_LESS);
    glEnable(GL_DEPTH_TEST);

    glColorMaterial(GL_FRONT_AND_BACK,GL_DIFFUSE);
    glEnable(GL_COLOR_MATERIAL);
  }

  void CALLBACK display(void)
  {
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    glPushMatrix();
      glRotatef(45,0.0,1.0,0.0);
      glRotatef(315,0.0,0.0,1.0);
      DrawColorBox();
    glPopMatrix();

    glFlush();
  }

  void CALLBACK myReshape(GLsizei w, GLsizei h)
  {
    glViewport(0, 0, w, h);
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    if (w <= h)
      glOrtho (-1.5, 1.5, -1.5*(GLfloat)h/(GLfloat)w,1.50*(GLfloat)h/(GLfloat)w, -10.0, 10.0);
    else
      glOrtho (-1.5*(GLfloat)w/(GLfloat)h,1.5*(GLfloat)w/(GLfloat)h, -1.5, 1.5, -10.0, 10.0);
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity ();
  }

  void DrawColorBox(void)
  {
    glBegin (GL_QUADS);
      glColor3fv(c1);
      glNormal3fv(m1);
      glVertex3fv(p1);
      glColor3fv(c2);
      glVertex3fv(p2);
      glColor3fv(c3);
      glVertex3fv(p3);
      glColor3fv(c4);
      glVertex3fv(p4);

      glColor3fv(c5);
      glNormal3fv(m5);
      glVertex3fv(p5);
      glColor3fv(c6);
      glVertex3fv(p6);
      glColor3fv(c7);
      glVertex3fv(p7);
      glColor3fv(c8);
      glVertex3fv(p8);

      glColor3fv(c5);
      glNormal3fv(m3);
      glVertex3fv(p5);
      glColor3fv(c6);
      glVertex3fv(p6);
      glColor3fv(c3);
      glVertex3fv(p3);
      glColor3fv(c4);
      glVertex3fv(p4);

      glColor3fv(c1);
      glNormal3fv(m4);
      glVertex3fv(p1);
      glColor3fv(c2);
      glVertex3fv(p2);
      glColor3fv(c7);
      glVertex3fv(p7);
      glColor3fv(c8);
      glVertex3fv(p8);

      glColor3fv(c2);
      glNormal3fv(m5);
      glVertex3fv(p2);
      glColor3fv(c3);
      glVertex3fv(p3);
      glColor3fv(c6);
      glVertex3fv(p6);
      glColor3fv(c7);
      glVertex3fv(p7);

      glColor3fv(c1);
      glNormal3fv(m6);
      glVertex3fv(p1);
      glColor3fv(c4);
      glVertex3fv(p4);
      glColor3fv(c5);
      glVertex3fv(p5);
      glColor3fv(c8);

    glEnd();
  }

  void main(void)
  {
    auxInitDisplayMode (AUX_SINGLE | AUX_RGBA);
    auxInitPosition (0, 0, 500,400);
    auxInitWindow ("ColorBox");
    myinit();
    auxReshapeFunc (myReshape);
    auxMainLoop(display);
  }


  以上程序运行结果是一个自定义法向的彩色正方体,其中每个顶点的颜色值不一样,且为光滑的明暗处理模式。

图13-6 自定义法向的彩色立方体


13.3、曲线生成
  计算机图形学中,所有的光滑曲线都采用线段逼近来模拟,而且许多有用的曲线在数学上只用少数几个参数(如控制点等)来描述。本节简要地介绍一下OpenGL中Bezier曲线的绘制方法。

  13.3.1 曲线绘制举例
  下面我们来看一个简单的例子,这是用四个控制顶点来画一条三次Bezier曲线。程序如下: 

  例13-4 Bezier曲线绘制例程bzcurve.c

  #include "glos.h"
  #include <GL/gl.h>
  #include <GL/glu.h>
  #include <GL/glaux.h>

  void myinit(void);
  void CALLBACK myReshape(GLsizei w, GLsizei h);
  void CALLBACK display(void);

  GLfloat ctrlpoints[4][3] = {
    { -4.0, -4.0, 0.0 }, { -2.0, 4.0, 0.0 },
    { 2.0, -4.0, 0.0 }, { 4.0, 4.0, 0.0 }
  };

  void myinit(void)
  {
    glClearColor(0.0, 0.0, 0.0, 1.0);
    glMap1f(GL_MAP1_VERTEX_3, 0.0, 1.0, 3, 4, &ctrlpoints[0][0]);
    glEnable(GL_MAP1_VERTEX_3);
    glShadeModel(GL_FLAT);
  }

  void CALLBACK display(void)
  {
    int i;

    glClear(GL_COLOR_BUFFER_BIT);
    glColor3f(1.0, 1.0, 1.0);
    glBegin(GL_LINE_STRIP);
    for (i = 0; i <= 30; i++)
      glEvalCoord1f((GLfloat) i/30.0);
    glEnd();


    /* 显示控制点 */
    glPointSize(5.0);
    glColor3f(1.0, 1.0, 0.0);
    glBegin(GL_POINTS);
    for (i = 0; i < 4; i++)
      glVertex3fv(&ctrlpoints[i][0]);
    glEnd();
    glFlush();
  }

  void CALLBACK myReshape(GLsizei w, GLsizei h)
  {
    glViewport(0, 0, w, h);
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    if (w <= h)
      glOrtho(-5.0, 5.0, -5.0*(GLfloat)h/(GLfloat)w, 5.0*(GLfloat)h/(GLfloat)w, -5.0, 5.0);
    else
      glOrtho(-5.0*(GLfloat)w/(GLfloat)h, 5.0*(GLfloat)w/(GLfloat)h, -5.0, 5.0, -5.0, 5.0);
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
  }

  void main(void )
  {
    auxInitDisplayMode (AUX_SINGLE | AUX_RGBA);
    auxInitPosition (0, 0, 500, 500);
    auxInitWindow ("Bezier Curves");
    myinit();
    auxReshapeFunc (myReshape);
    auxMainLoop(display);
  }


图13-7 一条光滑的Bezier曲线


  13.3.2 曲线定义和启动
  OpenGL中曲线定义的函数为:

  void glMap1{fd}(GLenum target,TYPE u1,TYPE u2,GLint stride, GLint order,const TYPE *points);

  函数的第一个参数target指出控制顶点的意义以及在参数points中需要提供多少值,具体值见表13-1所示。参数points指针可以指向控制点集、RGBA颜色值或纹理坐标串等。例如若target是GL_MAP1_COLOR_4,则就能在RGBA四维空间中生成一条带有颜色信息的曲线,这在数据场可视化中应用极广。参数u1和u2,指明变量U的范围,U一般从0变化到1。参数stride是跨度,表示在每块存储区内浮点数或双精度数的个数,即两个控制点间的偏移量,比如上例中的控制点集ctrpoint[4][3]的跨度就为3,即单个控制点的坐标元素个数。函数参数order是次数加1,叫阶数,与控制点数一致。

参数 意义
GL_MAP1_VERTEX_3 x,y,z 顶点坐标
GL_MAP1_VERTEX_4 x,y,z,w 顶点坐标
GL_MAP1_INDEX 颜色表
GL_MAP1_COLOR_4 R,G,B,A
GL_MAP1_NORMAL 法向量
GL_MAP1_TEXTURE_COORD_1 s    纹理坐标
GL_MAP1_TEXTURE_COORD_2 s,t   纹理坐标
GL_MAP1_TEXTURE_COORD_3 s,t,r  纹理坐标
GL_MAP1_TEXTURE_COORD_4 s,t,r,q 纹理坐标

表13-1 用于glMap1*()控制点的数据类型


  曲线定义后,必须要启动,才能进行下一步的绘制工作。启动函数仍是glEnable(),其中参数与glMap1*()的第一个参数一致。同样,关闭函数为glDisable(),参数也一样。

  13.3.3 曲线坐标计算
  这里提到的坐标概念是广义的,与以前定义的有点不同,具体地说就是表13-1所对应的类型值。OpenGL曲线坐标计算的函数形式如下:

  void glEvalCoord1{fd}[v](TYPE u);

  产生曲线坐标值并绘制。参数u是定义域内的值,这个函数调用一次只产生一个坐标。

  13.3.4 定义均匀间隔曲线坐标值
  在使用glEvalCoord1*()计算坐标,因为u可取定义域内的任意值,所以由此计算出的坐标值也是任意的。但是,目前用得最普遍的仍是取等间隔值。要获得等间隔值,OpenGL提供了两个函数,即先调用glMapGrid1*()定义一个一维网格,然后用glEvalMesh1()计算响应的坐标值。下面详细解释这两个函数:

  void glMapGrid1{fd}(GLint n,TYPE u1,TYPE u2);

  定义一个网格,从u1到u2分为n步,它们是等间隔的。实际上,这个函数定义的是参数空间网格。

  void glEvalMesh1(GLenum mode,GLint p1,GLint p2);

  计算并绘制坐标点。参数mode可以是GL_POINT或GL_LINE,即沿曲线绘制点或沿曲线绘制相连的线段。这个函数的调用效果同在p1和p2之间的每一步给出一个glEvalCoord1()的效果一样。从编程角度来说,除了当i=0或i=n,它准确以u1或u2作为参数调用glEvalCoord1()之外,它等价于一下代码:

  glBegin(GL_POINT); /* glBegin(GL_LINE_STRIP); */
  for(i=p1;i<=p2;i++)
    glEvalCoord1(u1+i*(u2-u1)/n);
  glEnd();


13.4、曲面构造
  同样,计算机图形学中的所有光滑曲面也都采用多边形逼近来绘制,而且许多有用的曲面在数学上也只用少数几个参数(如控制点或网等)来描述。通常,若用16个控制点描述一个曲面,要比用1000多个三角形和每个顶点的法向信息要节省很多内存。而且,1000个三角形仅仅只逼近曲面,而控制点可以精确地描述实际曲面,且可自动计算法向。本节简要地介绍一下OpenGL中Bezier曲面的绘制方法,所有相关的函数都与曲线的情况类似,只是二维空间而已。

  13.4.1 曲面定义和坐标计算
  曲面定义函数为:

  void glMap2{fd}(GLenum target,TYPE u1,TYPE u2,GLint ustride,GLint uorder,
          TYPE v1,TYPE v2,GLint vstride,GLint vorder,TYPE points);


  参数target可以是表13-1中任意值,不过需将MAP1改为MAP2。同样,启动曲面的函数仍是glEnable(),关闭是glDisable()。u1、u2为u的最大值和最小值;v1、v2为v的最大值和最小值。参数ustride和vstride指出在控制点数组中u和v向相邻点的跨度,即可从一个非常大的数组中选择一块控制点长方形。例如,若数据定义成如下形式:

  GLfloat ctlpoints[100][100][3];

  并且,要用从ctlpoints[20][30]开始的4x4子集,选择ustride为100*3,vstride为3,初始点设置为ctlpoints[20][30][0]。最后的参数都是阶数,uorder和vorder,二者可以不同。曲面坐标计算函数为:

  void glEvalCoord2{fd}[v](TYPE u,TYPE v);

  产生曲面坐标并绘制。参数u和v是定义域内的值。下面看一个绘制Bezier曲面的例子:

  例13-5 Bezier网状曲面绘制例程bzwiresf.c

  #include "glos.h"
  #include <GL/gl.h>
  #include <GL/glu.h>
  #include <GL/glaux.h>

  void myinit(void);
  void CALLBACK myReshape(GLsizei w, GLsizei h);
  void CALLBACK display(void);


  /* 控制点的坐标 */
  GLfloat ctrlpoints[4][4][3] = {
    {{-1.5, -1.5, 2.0}, {-0.5, -1.5, 2.0},
     {0.5, -1.5, -1.0}, {1.5, -1.5, 2.0}},
    {{-1.5, -0.5, 1.0}, {-0.5, 1.5, 2.0},
     {0.5, 0.5, 1.0}, {1.5, -0.5, -1.0}},
    {{-1.5, 0.5, 2.0}, {-0.5, 0.5, 1.0},
     {0.5, 0.5, 3.0}, {1.5, -1.5, 1.5}},
    {{-1.5, 1.5, -2.0}, {-0.5, 1.5, -2.0},
     {0.5, 0.5, 1.0}, {1.5, 1.5, -1.0}}
  };

  void myinit(void)
  {
    glClearColor (0.0, 0.0, 0.0, 1.0);
    glMap2f(GL_MAP2_VERTEX_3, 0, 1, 3, 4, 0, 1, 12, 4, &ctrlpoints[0][0][0]);
    glEnable(GL_MAP2_VERTEX_3);
    glMapGrid2f(20, 0.0, 1.0, 20, 0.0, 1.0);
    glEnable(GL_DEPTH_TEST);
  }

  void CALLBACK display(void)
  {
    int i, j;

    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    glColor3f(0.3, 0.6, 0.9);
    glPushMatrix ();
    glRotatef(35.0, 1.0, 1.0, 1.0);
    for (j = 0; j <= 8; j++)
    {
      glBegin(GL_LINE_STRIP);
      for (i = 0; i <= 30; i++)
        glEvalCoord2f((GLfloat)i/30.0, (GLfloat)j/8.0);
      glEnd();

      glBegin(GL_LINE_STRIP);
        for (i = 0; i <= 30; i++)
          glEvalCoord2f((GLfloat)j/8.0, (GLfloat)i/30.0);
        glEnd();
    }
    glPopMatrix ();
    glFlush();
  }

  void CALLBACK myReshape(GLsizei w, GLsizei h)
  {
    glViewport(0, 0, w, h);
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    if (w <= h)
      glOrtho(-4.0, 4.0, -4.0*(GLfloat)h/(GLfloat)w, 4.0*(GLfloat)h/(GLfloat)w, -4.0, 4.0);
    else
      glOrtho(-4.0*(GLfloat)w/(GLfloat)h, 4.0*(GLfloat)w/(GLfloat)h, -4.0, 4.0, -4.0, 4.0);
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
  }

  void main(void)
  {
    auxInitDisplayMode (AUX_SINGLE | AUX_RGBA);
    auxInitPosition (0, 0, 500, 500);
    auxInitWindow ("Wireframe Bezier Surface");
    myinit();
    auxReshapeFunc (myReshape);
    auxMainLoop(display);
  }


  以上程序运行结果是一个网状的曲面。

图13-8 Bezier网状曲面


  13.4.2 定义均匀间隔的曲面坐标值
  OpenGL中定义均匀间隔的曲面坐标值的函数与曲线的类似,其函数形式为:

  void glMapGrid2{fd}(GLenum nu,TYPE u1,TYPE u2, GLenum nv,TYPE v1,TYPE v2);
  void glEvalMesh2(GLenum mode,GLint p1,GLint p2,GLint q1,GLint q2);


  第一个函数定义参数空间的均匀网格,从u1到u2分为等间隔的nu步,从v1到v2分为等间隔的nv步,然后glEvalMesh2()把这个网格应用到已经启动的曲面计算上。第二个函数参数mode除了可以是GL_POINT和GL_LINE外,还可以是GL_FILL,即生成填充空间曲面。下面举出一个用网格绘制一个经过光照和明暗处理的Bezier曲面的例程:

  例13-6 加光照的均匀格网Bezier曲面绘制例程bzmesh.c

  #include "glos.h"
  #include <GL/gl.h>
  #include <GL/glu.h>
  #include <GL/glaux.h>

  void myinit(void);
  void initlights(void);
  void CALLBACK myReshape(GLsizei w, GLsizei h);
  void CALLBACK display(void);


  /* 控制点坐标 */

  GLfloat ctrlpoints[4][4][3] = {
    {{-1.5, -1.5, 2.0}, {-0.5, -1.5, 2.0},
     {0.5, -1.5, -1.0}, {1.5, -1.5, 2.0}},
    {{-1.5, -0.5, 1.0}, {-0.5, 1.5, 2.0},
     {0.5, 0.5, 1.0}, {1.5, -0.5, -1.0}},
    {{-1.5, 0.5, 2.0}, {-0.5, 0.5, 1.0},
     {0.5, 0.5, 3.0}, {1.5, -1.5, 1.5}},
    {{-1.5, 1.5, -2.0}, {-0.5, 1.5, -2.0},
     {0.5, 0.5, 1.0}, {1.5, 1.5, -1.0}}
  };

  void initlights(void)
  {
    GLfloat ambient[] = { 0.4, 0.6, 0.2, 1.0 };
    GLfloat position[] = { 0.0, 1.0, 3.0, 1.0 };
    GLfloat mat_diffuse[] = { 0.2, 0.4, 0.8, 1.0 };
    GLfloat mat_specular[] = { 1.0, 1.0, 1.0, 1.0 };
    GLfloat mat_shininess[] = { 80.0 };

    glEnable(GL_LIGHTING);
    glEnable(GL_LIGHT0);

    glLightfv(GL_LIGHT0, GL_AMBIENT, ambient);
    glLightfv(GL_LIGHT0, GL_POSITION, position);

    glMaterialfv(GL_FRONT, GL_DIFFUSE, mat_diffuse);
    glMaterialfv(GL_FRONT, GL_SPECULAR, mat_specular);
    glMaterialfv(GL_FRONT, GL_SHININESS, mat_shininess);
  }

  void CALLBACK display(void)
  {
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    glPushMatrix();
    glRotatef(35.0, 1.0, 1.0, 1.0);
    glEvalMesh2(GL_FILL, 0, 20, 0, 20);
    glPopMatrix();
    glFlush();
  }

  void myinit(void)
  {
    glClearColor (0.0, 0.0, 0.0, 1.0);
    glEnable (GL_DEPTH_TEST);
    glMap2f(GL_MAP2_VERTEX_3, 0, 1, 3, 4, 0, 1, 12, 4, &ctrlpoints[0][0][0]);
    glEnable(GL_MAP2_VERTEX_3);
    glEnable(GL_AUTO_NORMAL);
    glEnable(GL_NORMALIZE);
    glMapGrid2f(20, 0.0, 1.0, 20, 0.0, 1.0);
    initlights();
  }

  void CALLBACK myReshape(GLsizei w, GLsizei h)
  {
    glViewport(0, 0, w, h);
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    if (w <= h)
      glOrtho(-4.0, 4.0, -4.0*(GLfloat)h/(GLfloat)w, 4.0*(GLfloat)h/(GLfloat)w, -4.0, 4.0);
    else
      glOrtho(-4.0*(GLfloat)w/(GLfloat)h, 4.0*(GLfloat)w/(GLfloat)h, -4.0, 4.0, -4.0, 4.0);
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
  }

  void main(void)
  {
    auxInitDisplayMode (AUX_SINGLE | AUX_RGBA);
    auxInitPosition (0, 0, 500, 500);
    auxInitWindow ("Lighted and Filled Bezier Surface");
    myinit();
    auxReshapeFunc (myReshape);
    auxMainLoop(display);
  }


  以上程序运行结果是一个加上光影的曲面。

图13-9 带光影的曲面


  13.4.3 纹理曲面
  在前面我们已经讲过纹理的用法,这一节将结合曲面的生成试试纹理的应用。下面我们先看一个例子:

  例13-17 纹理曲面例程绘制texsurf.c

  #include "glos.h"
  #include <GL/gl.h>
  #include <GL/glu.h>
  #include <GL/glaux.h>
  #include <math.h>

  void myinit(void);
  void makeImage(void);
  void CALLBACK display(void);
  void CALLBACK myReshape(GLsizei w, GLsizei h);

  GLfloat ctrlpoints[4][4][3] = {
    {{-1.5, -1.5, 2.0}, {-0.5, -1.5, 2.0},
     {0.5, -1.5, -1.0}, {1.5, -1.5, 2.0}},
    {{-1.5, -0.5, 1.0}, {-0.5, 1.5, 2.0},
     {0.5, 0.5, 1.0}, {1.5, -0.5, -1.0}},
    {{-1.5, 0.5, 2.0}, {-0.5, 0.5, 1.0},
     {0.5, 0.5, 3.0}, {1.5, -1.5, 1.5}},
    {{-1.5, 1.5, -2.0}, {-0.5, 1.5, -2.0},
     {0.5, 0.5, 1.0}, {1.5, 1.5, -1.0}} };

  GLfloat texpts[2][2][2] = {{{0.0, 0.0}, {0.0, 1.0}}, {{1.0, 0.0}, {1.0, 1.0}}};

  void CALLBACK display(void)
  {
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    glColor3f(1.0, 1.0, 1.0);
    glEvalMesh2(GL_FILL, 0, 20, 0, 20);
    glFlush();
  }

  #define imageWidth 64
  #define imageHeight 64
  GLubyte image[3*imageWidth*imageHeight];

  void makeImage(void)
  {
    int i, j;
    float ti, tj;

    for (i = 0; i < imageWidth; i++)
    {
      ti = 2.0*3.14159265*i/imageWidth;
      for (j = 0; j < imageHeight; j++)
      {
        tj = 2.0*3.14159265*j/imageHeight;

        image[3*(imageHeight*i+j)] = (GLubyte) 127*(1.0+sin(ti));
        image[3*(imageHeight*i+j)+1] = (GLubyte) 127*(1.0+cos(2*tj));
        image[3*(imageHeight*i+j)+2] = (GLubyte) 127*(1.0+cos(ti+tj));
      }
    }
  }

  void myinit(void)
  {
    glMap2f(GL_MAP2_VERTEX_3, 0, 1, 3, 4, 0, 1, 12, 4, &ctrlpoints[0][0][0]);
    glMap2f(GL_MAP2_TEXTURE_COORD_2, 0, 1, 2, 2, 0, 1, 4, 2, &texpts[0][0][0]);
    glEnable(GL_MAP2_TEXTURE_COORD_2);
    glEnable(GL_MAP2_VERTEX_3);
    glMapGrid2f(20, 0.0, 1.0, 20, 0.0, 1.0);
    makeImage();
    glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL);
    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
    glTexImage2D(GL_TEXTURE_2D, 0, 3, imageWidth, imageHeight, 0,
      GL_RGB, GL_UNSIGNED_BYTE, image);
    glEnable(GL_TEXTURE_2D);
    glEnable(GL_DEPTH_TEST);
    glEnable(GL_NORMALIZE);
    glShadeModel (GL_FLAT);
  }

  void CALLBACK myReshape(GLsizei w, GLsizei h)
  {
    glViewport(0, 0, w, h);
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    if (w <= h)
      glOrtho(-4.0, 4.0, -4.0*(GLfloat)h/(GLfloat)w, 4.0*(GLfloat)h/(GLfloat)w, -4.0, 4.0);
    else
      glOrtho(-4.0*(GLfloat)w/(GLfloat)h, 4.0*(GLfloat)w/(GLfloat)h, -4.0, 4.0, -4.0, 4.0);
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
    glRotatef(35.0, 1.0, 1.0, 1.0);
  }

  void main(void)
  {
    auxInitDisplayMode (AUX_SINGLE | AUX_RGBA);
    auxInitPosition (0, 0, 500, 400);
    auxInitWindow ("Texture Surface");
    myinit();
    auxReshapeFunc (myReshape);
    auxMainLoop(display);
  }


  以上程序运行结果是一个带纹理的曲面。

图13-10 带纹理的曲面


  13.4.4 NURBS曲面
  OpenGL的功能库提供了一系列NURBS曲面(非均匀有理B样条曲面)的函数。本节不具体讲各函数的用法,仅举出一个应用例子,其余的读者可以参考有关手册。例程如下:

  例13-8 NURBS曲面绘制例程nurbsurf.c

  #include "glos.h"
  #include <GL/gl.h>
  #include <GL/glu.h>
  #include <GL/glaux.h>

  void myinit(void);
  void init_surface(void);
  void CALLBACK display(void);
  void CALLBACK myReshape(GLsizei w, GLsizei h);

  GLfloat ctlpoints[4][4][3];

  GLUnurbsObj *theNurb;


  /* 初始化控制点坐标,x,y,z范围从-3到3 */

  void init_surface(void)
  {
    int u, v;
    for (u = 0; u < 4; u++)
    {
      for (v = 0; v < 4; v++)
      {
        ctlpoints[u][v][0] = 2.0*((GLfloat)u - 1.5);
        ctlpoints[u][v][1] = 2.0*((GLfloat)v - 1.5);

        if ( (u == 1 || u == 2) && (v == 1 || v == 2))
          ctlpoints[u][v][2] = 3.0;
        else
          ctlpoints[u][v][2] = -3.0;
      }
    }
  }


  /* 定义曲面材质 (金色) */

  void myinit(void)
  {
    GLfloat mat_diffuse[] = { 0.88, 0.66, 0.22, 1.0 };
    GLfloat mat_specular[] = { 0.92, 0.9, 0.0, 1.0 };
    GLfloat mat_shininess[] = { 80.0 };

    glClearColor (0.0, 0.0, 0.0, 1.0);
    glMaterialfv(GL_FRONT, GL_DIFFUSE, mat_diffuse);
    glMaterialfv(GL_FRONT, GL_SPECULAR, mat_specular);
    glMaterialfv(GL_FRONT, GL_SHININESS, mat_shininess); glEnable(GL_LIGHTING);

    glEnable(GL_LIGHT0);
    glDepthFunc(GL_LESS);
    glEnable(GL_DEPTH_TEST);
    glEnable(GL_AUTO_NORMAL);
    glEnable(GL_NORMALIZE);

    init_surface();

    theNurb = gluNewNurbsRenderer();
    gluNurbsProperty(theNurb, GLU_SAMPLING_TOLERANCE, 25.0);
    gluNurbsProperty(theNurb, GLU_DISPLAY_MODE, GLU_FILL);
  }

  void CALLBACK display(void)
  {
    GLfloat knots[8] = {0.0, 0.0, 0.0, 0.0, 1.0, 1.0, 1.0, 1.0};

    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    glPushMatrix();
    glRotatef(330.0, 1.,0.,0.);
    glScalef (0.5, 0.5, 0.5);

    gluBeginSurface(theNurb);
    gluNurbsSurface(theNurb,
      8,
      knots,
      8,
      knots,
      4 * 3,
      3,
      &ctlpoints[0][0][0],
      4, 4,
      GL_MAP2_VERTEX_3);
    gluEndSurface(theNurb);

    glPopMatrix();
    glFlush();
  }

  void CALLBACK myReshape(GLsizei w, GLsizei h)
  {
    glViewport(0, 0, w, h);
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    gluPerspective (45.0, (GLdouble)w/(GLdouble)h, 3.0, 8.0);

    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
    glTranslatef (0.0, 1.0, -5.0);
  }

  void main(void)
  {
    auxInitDisplayMode (AUX_SINGLE | AUX_RGBA);
    auxInitPosition (0, 0, 500, 500);
    auxInitWindow ("NURBS Surface");
    myinit();
    auxReshapeFunc (myReshape);
    auxMainLoop(display);
  }


  以上程序运行结果是一个银白色的NURBS曲面。

图13-11 NURBS曲面


本文转载自:http://blog.csdn.net/popkiler/article/details/1753815

共有 人打赏支持
小青_1989
粉丝 3
博文 44
码字总数 12913
作品 0
大连
程序员
OpenGL入门(一)freeglut和glew的编译

写在前面 最近对OpenGL编程又双叒产生了浓厚的兴趣,决定把学习OpenGL过程中学到的知识都整理到博客中来,一来方便日后查看,而来也是为了和诸位大佬共勉。有不当的地方还望诸位批评指正,谢...

renkai0406 ⋅ 04/23 ⋅ 0

在Android中使用OpenGL ES进行开发第(二)课:定义图形

一、前期基础知识储备 笔者计划写三篇文章来详细分析OpenGL ES基础的同时也是入门关键的三个点: ①OpenGL ES是什么?与OpenGL的关系是什么?——概念部分 ②使用OpenGLES绘制2D/3D图形的第一...

weixin_41101173 ⋅ 04/22 ⋅ 0

OpenGL实现物体动画和视频特效

OpenGL实现视频的水印、滤镜?OpenGL实现视频的剪裁、旋转? 2D/3D物体的 旋转,平移,缩放? OpenGL图片滤镜与视频滤镜? 矩阵(Matrix)是一个按照长方阵列排列的复数或实数集合,最早来自于方...

shareus ⋅ 04/24 ⋅ 0

图片和图形之构建一个OpenGL ES环境(10)

原文 概要 构建一个OpenGL ES环境 为了在Android应用程序中使用OpenGL ES绘制图形,您必须为它们创建一个视图容器。其中一种更直接的方法是实现a GLSurfaceView和a GLSurfaceView.Renderer。...

lichong951 ⋅ 05/26 ⋅ 0

图片和图形之用OpenGL ES显示图形(9)

原文 概要 Android框架提供了大量用于创建有吸引力的功能性图形用户界面的标准工具。但是,如果您想要更多地控制应用程序在屏幕上绘制的内容,或者冒险进入三维图形,则需要使用其他工具。A...

lichong951 ⋅ 05/26 ⋅ 0

计算机图形/图像(GPU/OpenGL)

> OpenGL ES 《OpenGL ES应用开发实践指南 -Android卷》-https://download.csdn.net/download/donkor/9931418 《计算机图形学(openGL版)第三版(中文版)》 矩阵变换:《线性代数》和《3D 数学...

shareus ⋅ 04/25 ⋅ 0

图片和图形之应用投影和相机视图(13)

原文 概要 在OpenGL ES环境中,投影和相机视图允许您以更接近您用眼睛看物体的方式显示绘制的对象。这种物理观察的模拟是通过绘制物体坐标的数学变换完成的: 投影 - 此变换根据GLSurfaceVi...

lichong951 ⋅ 05/26 ⋅ 0

计算机图形与OpenGL学习六(二维观察2.OpenGL二维观察函数)

OpenGL二维观察函数 本节概念性内容较多,为便于理解与记忆,可以查看之前文章的实例中的函数操作 1. OpenGL投影模式 在选择OpenGL裁剪窗口和视口之前,必须建立合适的模式以便构建从世界坐标...

lhs322 ⋅ 04/17 ⋅ 0

u3d shader着色器学习笔记(一)

基础知识:MeshFilter 存储一个mesh(网格,模型网格,模型由哪些三角面组成,组成什么样子的模型,三角面的一些顶点信息) MeshRender 根据MeshFilter 存储的三角面顶点信息 用来渲染一个模...

nihao561 ⋅ 05/24 ⋅ 0

跨平台图像引擎 - Octoon

Octoon 是一个免费和开源的跨平台图形引擎,采用MIT协议。 用户可以使用一组统一的API轻松创建图形应用程序。 应用程序可以导出到许多平台,包括Linux,Mac OSX,Windows,Android和HTML5。 ...

匿名 ⋅ 05/27 ⋅ 0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

对于程序员的招聘问题,作为软件人的一些吐槽和建议

作为软件人,找工作有时候似乎挺苦逼的。 说真的,让我去掉前面这句中“似乎”二字吧。就是苦逼!很多人都曾抱怨处在招聘的一方很糟糕——我们没有任何可靠的方式来甄别会写代码并且写得好的...

老道士 ⋅ 28分钟前 ⋅ 0

HDFS原理学习

一、概述 1、 Hadoop整合了众多的文件系统,首先提供了一个高层的文件系统抽象org.apache.hadoop.fs.FileSystem。然后有各个文件系统的实现类。 2、Hadoop是JAVA编写的,不同文件系统之间的交...

cjxcloud ⋅ 32分钟前 ⋅ 0

Linux下MySQL表名不区分大小写的设置方法(抄袭别人的)

Linux下MySQL表名不区分大小写的设置方法 MySQL表名不区分大小写的设置方法 在用centox安装mysql后,把项目的数据库移植了过去,发现一些表的数据查不到,排查了一下问题,最后发现是表名的大...

随风而浮沉 ⋅ 37分钟前 ⋅ 0

ubuntu下安装宋体simsun

sudo cp simsun.ttc /usr/share/fonts cd /usr/share/fonts sudo chmod 644 simsun.ttc 更新字体缓存: 代码: sudo mkfontscale 代码: sudo mkfontdir 代码: sudo fc-cache -fsv 安装chrome扩......

wangxuwei ⋅ 39分钟前 ⋅ 0

利用 ssh 传输文件

Linux 下一般可以用 scp 命令通过 ssh 传送文件: #把服务器上的 /home/user/a.txt 发送到本机的 /var/www/local_dir 目录下scp username@servername:/home/user/a.txt /var/www/local_dir...

大灰狼时间 ⋅ 49分钟前 ⋅ 0

web3j教程:android和java程序员如何使用web3j开发区块链以太坊

如何使用web3j为Java应用或Android App增加以太坊区块链支持,本教程内容即涉及以太坊中的核心概念,例如账户管理包括账户的创建、钱包创建、交易转账,交易与状态、智能合约开发与交互、过滤...

智能合约 ⋅ 今天 ⋅ 0

web3j开发java或android以太坊智能合约快速入门

web3j简介 web3j是一个轻量级、高度模块化、响应式、类型安全的Java和Android类库提供丰富API,用于处理以太坊智能合约及与以太坊网络上的客户端(节点)进行集成。 可以通过它进行以太坊区块链...

笔阁 ⋅ 今天 ⋅ 0

一起读书《深入浅出nodejs》-异步I/O

异步I/O “异步”这个名词其实很早就诞生了,但它大规模流行却是在Web 2.0浪潮中,它伴随着AJAX的第一个A(Asynchronous)席卷了Web。 为什么要异步I/O 关于异步I/O为何在Node里如此重要,这与...

小草先森 ⋅ 今天 ⋅ 0

JVM各种问题

1、如果启动什么都不设,会怎样? 先来看一个命令 [root@localhost bin]# java -XX:+PrintCommandLineFlags -version -XX:InitialHeapSize=29899008 -XX:MaxHeapSize=478384128 -XX:+PrintCo......

算法之名 ⋅ 今天 ⋅ 0

SAS笔记-宏2

宏是一种文本,一般来说其编译是在程序执行之前。 宏变量的创建 %let语句 %let macro_variables = text; %let是常见的宏变量建立方式,其编译就在执行前。如下例中,想要宏变量test等于数据集...

tonorth123 ⋅ 今天 ⋅ 0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

返回顶部
顶部