OpenGL编程轻松入门(四)
例10:绘制一个曲面,本程序使用二维求值器绘制一个曲面。本例中也有一些特殊效果的操作。
#include <windows.h>
#include <GL/GLAUX.h>
#include <GL/glut.h>
#include <math.h>
GLfloat ctrlpoints[5][5][3] = {{{-2,0,0},{-1,1,0},{0,0,0},{1,-1,0},{2,0,0}},
{{-2,0,-1},{-1,1,-1},{0,0,-1},{1,-1,-1},{2,0,-1}},
{{-2,0,-2},{-1,1,-2},{0,0,-2},{1,-1,-2},{2,0,-2}},
{{-2,0,-3},{-1,1,-3},{0,0,-3},{1,-1,-3},{2,0,-3}},
{{-2,0,-4},{-1,1,-4},{0,0,-4},{1,-1,-4},{2,0,-4}}};
GLfloat mat_ambient[] = {0.1,0.1,0.1,1.0};
GLfloat mat_diffuse[] = {1.0,0.6,0.0,1.0};
GLfloat mat_specular[] = {1.0,1.0,1.0,1.0};
GLfloat light_ambient[] = {0.1,0.1,0.1,1.0};
GLfloat light_diffuse[] = {1.0,1.0,1.0,0.0};
GLfloat light_specular[] = {1.0,1.0,1.0,0.0};
GLfloat light_position[] = {2.0,23.0,-4.0,1.0};
void myInit(void)
{
glClearColor(0.0,0.0,0.0,0.0);//设置背景色
/*为光照模型指定材质参数*/
glMaterialfv(GL_FRONT,GL_AMBIENT,mat_ambient);
glMaterialfv(GL_FRONT,GL_DIFFUSE,mat_diffuse);
glMaterialfv(GL_FRONT,GL_SPECULAR,mat_specular);
glMaterialf(GL_FRONT,GL_SHININESS,60.0);
/*设置光源参数*/
glLightfv(GL_LIGHT0,GL_AMBIENT,light_ambient);
glLightfv(GL_LIGHT0,GL_DIFFUSE,light_diffuse);
glLightfv(GL_LIGHT0,GL_SPECULAR,light_specular);
glLightfv(GL_LIGHT0,GL_POSITION,light_position);
glEnable(GL_LIGHTING);
glEnable(GL_LIGHT0);
/*enable depth comparisons and update the depth buffer*/
glEnable(GL_DEPTH_TEST);
/*设置特殊效果*/
glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
glHint(GL_LINE_SMOOTH_HINT,GL_DONT_CARE);
glEnable(GL_BLEND);
glEnable(GL_AUTO_NORMAL);
glEnable(GL_NORMALIZE);
glFrontFace(GL_CW);
glShadeModel(GL_SMOOTH);
glEnable(GL_LINE_SMOOTH);
}
void myDisplay(void)
{
glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
glColor3f(0.0,0.0,0.0);
glTranslatef(0.0,-1.0,0.0);
glRotatef(50.0,1.0,0.0,0.0);
glPushMatrix();
/*绘制曲面*/
glEnable(GL_MAP2_VERTEX_3);
glMap2f(GL_MAP2_VERTEX_3,0,1,3,5,0,1,15,5,&ctrlpoints[0][0][0]);
glMapGrid2f(10.0,0.0,1.0,10.0,0.0,1.0);
glEvalMesh2(GL_FILL,0,10.0,0,10.0);
glPopMatrix();
glutSwapBuffers();
}
void myReshape(GLsizei w,GLsizei h)
{
glViewport(0,0,w,h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(60.0,(GLfloat)w/(GLfloat)h,1.0,100.0);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glTranslatef(0.0,0.0,-5.0);
}
int main(int argc,char ** argv)
{
/*初始化*/
glutInit(&argc,argv);
glutInitDisplayMode(GLUT_DOUBLE|GLUT_RGB|GLUT_DEPTH);
glutInitWindowSize(400,400);
glutInitWindowPosition(200,200);
/*创建窗口*/
glutCreateWindow("lighted Bezier surface");
/*绘制与显示*/
myInit();
glutReshapeFunc(myReshape);
glutDisplayFunc(myDisplay);
glutMainLoop();
return(0);
}
myInit()中的几个有关特殊效果的操作。
l glBlendFunc(GLenum sfactor,GLenum dfactor) 指定像素算法。sfactor指定红,绿,蓝及alpha源混合因素是如何计算的。dfactor指定红,绿,蓝及alpha目标混合因素是如何计算的。
l glHint(GLenum target,GLenum mode)指定操作线索。
Target为需要控制的符号常量。mode为所希望的行为符号常数。本例中GL_LINE_SMOOTH_HINT指定反走样线段的采样质量。GL_DONT_CARE指对选项不做考虑。
myDisplay()中的曲面操作
l void glMap2f(GLenum target,GLfloat u1,GLfloat u2,Glint ustride, Glint uorder, GLfloat v1, GLfloat v2, Glint vstride, Glint vorder, const GLfloat *points);定义2维求值器。
target指定求值器生成的数值类型。本例中的GL_MAP2_VERTEX_3 指明每一个控制点为x、y、z表示的三个浮点值。
u1,u2指定线性映射。
ustride 指定控制点Rij的起始点和控制点 R(i+1)j的的起始点之间单精度或双精度浮点值的个数。这里i和j分别是u和v控制点索引,它允许控制点装入任意的数据结构中。唯一的限制是对于特定控制点的数值必须存在连续的内存单元。
uorder控制点数组在u轴方向上的维数。
v1,v2指定线性映射v
vstride指定控制点Rij的起始点和控制点 Ri(j+ 1)的起始点之间单精度或双精度浮点值的个数。这里i和j分别是u和v控制点索引,它允许控制点装入任意的数据结构中。唯一的限制是对于特定控制点的数值必须存在连续的内存单元。
vorder控制点数组在v轴方向上的维数。
points 一个指向控制点数组的指针。
l glMapGrid定义一维或二维网格。void glMapGrid2f(Glint un, GLfloat u1, GLfloat u2,Glint vn, GLfloat v1,GLfloat v2);
un 在网格[u1,u2]中的分段数目。
u1,u2 指定整数网格范围 i= 0;i= un的映射。
vn在网格[v1,v2]中的分段数目。
v1,v2 指定整数网格范围 j = 0;j= vn的映射。
l glEvalMesh 计算一维或二维点或线网格。本例中为2维。void glEvalMesh2(GLenum mode,Glint i1,Glint i2,Glint j1,Glint j2);
mode 指定是否计算二维点、线或多边形的网格。
i1,i2 分别为网格定义域变量i的第一个和最后一个整数值。
j1,j2分别为网格定义域变量j的第一个和最后一个整数值。
glMapGrid和glEvalMesh用来生成并求取一系列等间隔的网格点,glEvalMesh逐步计算一维或二维网格,他的定义范围由glMap指定。mode决定最终计算的顶点是绘制为点、线还是充实的多边形。具体的映射关系及有关图形方面的知识,你可以很方便的在MSDN、互联网及有关书籍中查到,本文就不详述这方面的内容。
2. 绘制NURBS曲线和曲面
例11:此例绘制两个相同形状的NURBS曲面,不同之处是一个为线框式,一个是由实多边形组成。运行后可以看到其中的区别。
#include <windows.h>
#include <GL/glut.h>
GLUnurbsObj *theNurb1;
GLUnurbsObj *theNurb2;
GLfloat ctrlpoints[5][5][3] = {{{-3,0.5,0},{-1,1.5,0},{-2,2,0},{1,-1,0},{-5,0,0}},
{{-3,0.5,-1},{-1,1.5,-1},{-2,2,-1},{1,-1,-1},{-5,0,-1}},
{{-3,0.5,-2},{-1,1.5,-2},{-2,2,-2},{1,-1,-2},{-5,0,-2}},
{{-3,0.5,-3},{-1,1.5,-3},{-2,2,-3},{1,-1,-3},{-5,0,-3}},
{{-3,0.5,-4},{-1,1.5,-4},{-2,2,-4},{1,-1,-4},{-5,0,-4}}};//控制点
GLfloat mat_diffuse[] = {1.0,0.5,0.1,1.0};
GLfloat mat_specular[] = {1.0,1.0,1.0,1.0};
GLfloat mat_shininess[] = {100.0};
GLfloat light_position[] = {0.0,-10.0,0.0,1.0};
void myInit(void)
{
glClearColor(1.0,1.0,1.0,0.0);//设置背景色
/*为光照模型指定材质参数*/
glMaterialfv(GL_FRONT,GL_DIFFUSE,mat_diffuse);
glMaterialfv(GL_FRONT,GL_SPECULAR,mat_specular);
glMaterialfv(GL_FRONT,GL_SHININESS,mat_shininess);
glLightfv(GL_FRONT,GL_POSITION,light_position);//设置光源参数
glLightModeli(GL_LIGHT_MODEL_TWO_SIDE,GL_TRUE);//设置光照模型参数
/*激活光照*/
glEnable(GL_LIGHTING);
glEnable(GL_LIGHT0);
glDepthFunc(GL_LEQUAL);
glEnable(GL_DEPTH_TEST);
glEnable(GL_LEQUAL);
glEnable(GL_AUTO_NORMAL);
glEnable(GL_NORMALIZE);
/*设置特殊效果*/
glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
glHint(GL_LINE_SMOOTH_HINT,GL_DONT_CARE);
glEnable(GL_BLEND);
glFrontFace(GL_CW);
glShadeModel(GL_SMOOTH);
glEnable(GL_LINE_SMOOTH);
theNurb1 = gluNewNurbsRenderer();//创建NURBS对象theNurb1
gluNurbsProperty(theNurb1,GLU_SAMPLING_TOLERANCE,25.0);
gluNurbsProperty(theNurb1,GLU_DISPLAY_MODE,GLU_OUTLINE_POLYGON);
theNurb2 = gluNewNurbsRenderer();//创建NURBS对象theNurb2
gluNurbsProperty(theNurb2,GLU_SAMPLING_TOLERANCE,25.0);
gluNurbsProperty(theNurb2,GLU_DISPLAY_MODE,GLU_FILL);
}
int spin = 0;
/*接收键盘指令*/
static void myKey(unsigned char key,int x,int y)
{
switch(key)
{
case'd':
spin = spin + 1;
glRotatef(spin,1.0,1.0,0.0);
glutPostRedisplay();
break;
case 27:
exit(0);
default:
break;
}
}
/*绘制曲面*/
void myDisplay(void)
{
GLfloat knots[10] = {0.0,0.0,0.0,0.0,0.0,1.0,1.0,1.0,1.0,1.0};
glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
glRotatef(50.0,1.0,1.0,0.0);
/*第一个曲面*/
glPushMatrix();
glTranslatef(1.0,0.0,0.0);
gluBeginSurface(theNurb1);
/*定义曲面形状*/
gluNurbsSurface(theNurb1,10,knots,10,knots,5*3,3,&ctrlpoints[0][0][0],5,5,GL_MAP2_VERTEX_3);
gluEndSurface(theNurb1);
glPopMatrix();
/*第二个曲面*/
glPushMatrix();
glTranslatef(7.0,0.0,0.0);
gluBeginSurface(theNurb2);
/*定义曲面形状*/
gluNurbsSurface(theNurb2,10,knots,10,knots,5*3,3,&ctrlpoints[0][0][0],5,5,GL_MAP2_VERTEX_3);
gluEndSurface(theNurb2);
glPopMatrix();
glutSwapBuffers();
}
void myReshape(GLsizei w,GLsizei h)
{
glViewport(0,0,w,h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(50.0,(GLfloat)w/(GLfloat)h,1.0,15.0);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glTranslatef(0.0,0.0,-9.0);
}
int main(int argc,char ** argv)
{
/*初始化*/
glutInit(&argc,argv);
glutInitDisplayMode(GLUT_DOUBLE|GLUT_RGB|GLUT_DEPTH);
glutInitWindowSize(600,400);
glutInitWindowPosition(200,200);
/*创建窗口*/
glutCreateWindow("NURBS surface");
/*绘制与显示*/
myInit();
glutKeyboardFunc(myKey);
glutReshapeFunc(myReshape);
glutDisplayFunc(myDisplay);
glutMainLoop();
return(0);
}
l GLUnurbsObj* glNewNurbsRenderer()创建一个NURBS对象,并返回一个指向该对象的指针。如果没有足够的内存分配给该对象,则返回值为0。
l void gluNurbsProperty(GLUnurbsObj* nobj, GLenum property, GLfloat value)设置NURBS属性。
nobj 指向NURBS对象的指针。
property需设置的属性。
value 设置指定属性的值。
l glBeginSurface及gluEndSurface两个函数一起限定一个NURBS面的定义。返回值均为void,参数均为GLUnurbsObj* nobj,为指向NURBS对象的指针。
l void gluNurbsSurface(GLUnurbsObj *nobj, Glint knot_count, GLfloat tknot_count, GLfloat *tknot, Glint s_stride, Glint t_stride, GLfloat *ctlarry, GLint sorder, GLint torder,GLenum type) 定义NURBS曲面形状。
nobj 指向NURBS对象的指针。
sknot_count 参数化u方向上的节点数。
sknot 参数化u方向上的非递减节点值。
tknot_count 参数化v方向上的节点数。
tknot 参数化v方向上的非递减节点值。
s_stride在ctlarry中参数化u方向上相邻控制点的偏移量。
t_stride在ctlarry中参数化v方向上相邻控制点的偏移量。
ctlarryNURBS的控制点数组。
sorder参数化u方向上NURBS的阶数,阶数比维数大1。
torder参数化v方向上NURBS的阶数,阶数比维数大1。
type曲面类型。
例12:绘制一个彩色的曲线,曲线闭合成圆。在曲线的边缘绘制8个点。
#include <windows.h>
#include <GL/glut.h>
GLUnurbsObj *theNurb;
GLfloat ctrlpoints[12][3] = {{4,0,0},{2.828,2.828,0},{0,4,0},{-2.828,2.828,0},
{-4,0,0},{-2.828,-2.828,0},{0,-4,0},{2.828,-2.828,0},
{4,0,0},{2.828,2.828,0},{0,4,0},{2.828,2.828,0}};//控制点
GLfloat color[12][3]={{1.0,0.0,0.0},{1.0,1.0,0.0},{0.0,1.0,0.0},{-1.0,1.0,0.0},
{-1.0,0.0,0.0},{-1.0,-1.0,0.0},{0.0,-1.0,0.0},{1.0,-1.0,0.0},
{1.0,0.0,0.0},{1.0,1.0,0.0},{0.0,1.0,0.0},{1.0,1.0,0.0}};
GLfloat knots[15] = {1,2,3,4,5,6,7,8,9,10,11,12,13,14,15};
void myInit(void)
{
glClearColor(1.0,1.0,1.0,0.0);//设置背景色
theNurb = gluNewNurbsRenderer();//创建NURBS对象theNurb
gluNurbsProperty(theNurb,GLU_SAMPLING_TOLERANCE,10);
}
/*绘制曲线*/
void myDisplay(void)
{
int i;
glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
glColor3f(0.0,0.0,0.0);
glLineWidth(3.0);
/*绘制曲线*/
gluBeginCurve(theNurb);
gluNurbsCurve(theNurb,15,knots,3,&ctrlpoints[0][0],3,GL_MAP1_VERTEX_3);
gluNurbsCurve(theNurb,15,knots,3,&ctrlpoints[0][0],3,GL_MAP1_COLOR_4);
gluEndCurve(theNurb);
/*绘制点*/
glColor3f(1.0,0.0,0.0);
glPointSize(5.0);
glBegin(GL_POINTS);
for(i = 0;i < 8;i++)
glVertex2fv(&ctrlpoints[i][0]);
glEnd();
glutSwapBuffers();
}
void myReshape(GLsizei w,GLsizei h)
{
glViewport(0,0,w,h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
if(w <=h)
glOrtho(-10.0,10.0,-10.0*(GLfloat)h/(GLfloat)w,10.0*(GLfloat)h/(GLfloat)w,-10.0,10.0);
else
glOrtho(-10.0*(GLfloat)w/(GLfloat)h,10.0*(GLfloat)w/(GLfloat)h,-10.0,10.0,-10.0,10.0);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glTranslatef(0.0,0.0,-9.0);
}
int main(int argc,char ** argv)
{
/*初始化*/
glutInit(&argc,argv);
glutInitDisplayMode(GLUT_DOUBLE|GLUT_RGB|GLUT_DEPTH);
glutInitWindowSize(600,400);
glutInitWindowPosition(200,200);
/*创建窗口*/
glutCreateWindow("NURBS curve");
/*绘制与显示*/
myInit();
glutReshapeFunc(myReshape);
glutDisplayFunc(myDisplay);
glutMainLoop();
return(0);
}
l gluBeginCurve,gluEndCurve限定NURBS曲面。返回值均为void,参数均为GLUnurbsObj* nobj,为指向NURBS对象的指针。
l void gluNurbsCurve(GLUnurbsObj *nobj, GLint nknots, GLfloat *knot, Glint stride, GLfloat *ctlarray, GLint order,GLenum type)定义曲线形状。
nobj 指向NURBS对象的指针。
nknots 节点数,节点数等于控制点数加上阶数。
knot nknots数组非递减节点值。
stride相邻控制点的偏移量。
Ctlarry指向NURBS的控制点数组的指针。
order NURBS曲线的阶数,阶数比维数大1。
type曲面类型。
3. 二次几何体
例13:本例使用GLU库函数绘制了四个几何物体,分别为圆柱体、球体、圆盘和部分圆盘。
#include <windows.h>
#include <GL/glut.h>
#include <math.h>
/*声明四个二次曲面物体*/
GLUquadricObj *quadObj1;
GLUquadricObj *quadObj2;
GLUquadricObj *quadObj3;
GLUquadricObj *quadObj4;
static float light_ambient[] = {0.1,0.1,0.1,1.0};
static float light_diffuse[] = {0.5,1.0,1.0,1.0};
static float light_position[] = {90.0,90.0,150.0,0.0};
static float front_mat_shininess[] = {60.0};
static float front_mat_specular[] = {0.2,0.2,0.2,1.0};
static float front_mat_diffuse[] = {0.5,0.5,0.28,1.0};
static float back_mat_shininess[] = {60.0};
static float back_mat_specular[] = {0.5,0.5,0.2,1.0};
static float back_mat_diffuse[] = {1.0,0.9,0.2,1.0};
static float Imodel_ambient[] = {1.0,1.0,1.0,1.0};
static float Imodel_twoside[] = {GL_TRUE};
static float Imodel_oneside[] = {GL_FALSE};
void myInit(void)
{
/*设置背景色*/
glClearColor(0.0,0.0,0.0,1.0);
glEnable(GL_DEPTH_TEST);
glDepthFunc(GL_LEQUAL);
/*设置光照*/
glLightfv(GL_LIGHT0,GL_AMBIENT,light_ambient);
glLightfv(GL_LIGHT0,GL_DIFFUSE,light_diffuse);
glLightfv(GL_LIGHT0,GL_POSITION,light_position);
/*设置材质*/
glMaterialfv(GL_FRONT,GL_DIFFUSE,front_mat_diffuse);
glMaterialfv(GL_FRONT,GL_SPECULAR,front_mat_specular);
glMaterialfv(GL_FRONT,GL_SHININESS,front_mat_shininess);
glMaterialfv(GL_BACK,GL_DIFFUSE,back_mat_diffuse);
glMaterialfv(GL_BACK,GL_SPECULAR,back_mat_specular);
glMaterialfv(GL_BACK,GL_SHININESS,back_mat_shininess);
/*设置光照模型参数*/
glLightModelfv(GL_LIGHT_MODEL_AMBIENT,Imodel_ambient);
glLightModelfv(GL_LIGHT_MODEL_TWO_SIDE,Imodel_twoside);
/*激活关照*/
glEnable(GL_LIGHTING);
glEnable(GL_LIGHT0);
glShadeModel(GL_SMOOTH);
}
void myDisplay(void)
{
glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
/*创建四个二次曲面物体*/
quadObj1 = gluNewQuadric();
quadObj2 = gluNewQuadric();
quadObj3 = gluNewQuadric();
quadObj4 = gluNewQuadric();
/*绘制一个圆柱体*/
glPushMatrix();
gluQuadricDrawStyle(quadObj1,GLU_FILL);
gluQuadricNormals(quadObj1,GL_FLAT);
gluQuadricOrientation(quadObj1,GLU_INSIDE);
gluQuadricTexture(quadObj1,GL_TRUE);
glColor3f(1.0,1.0,0.0);
glRotatef(30,1.0,0.0,0.0);
glRotatef(40,0.0,1.0,0.0);
gluCylinder(quadObj1,2.0,2.0,9.0,20.0,8.0);
glPopMatrix();
/*绘制一个球体*/
glPushMatrix();
gluQuadricDrawStyle(quadObj2,GLU_SILHOUETTE);
glTranslatef(-5.0,-1.0,0.0);
gluSphere(quadObj2,3.0,20.0,20.0);
glPopMatrix();
/*绘制一个圆盘*/
glPushMatrix();
gluQuadricDrawStyle(quadObj3,GLU_LINE);
glTranslatef(-2.0,4.0,0.0);
gluDisk(quadObj3,2.0,5.0,15.0,10.0);
glPopMatrix();
/*绘制一个部分圆盘*/
glPushMatrix();
gluQuadricDrawStyle(quadObj4,GLU_POINT);
glTranslatef(-3.0,-7.0,0.0);
gluPartialDisk(quadObj4,2.0,5.0,15.0,10.0,10.0,100.0);
glPopMatrix();
/*删除四个二次曲面物体对象*/
gluDeleteQuadric(quadObj1);
gluDeleteQuadric(quadObj2);
gluDeleteQuadric(quadObj3);
gluDeleteQuadric(quadObj4);
glFlush();
}
void myReshape(int w,int h)
{
glViewport(0,0,(GLsizei)w,(GLsizei)h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(45.0,(GLfloat)w/(GLfloat)h,1.0,50.0);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glTranslatef(0.0,0.0,-25.0);
}
int main(int argc,char ** argv)
{
/*初始化*/
glutInit(&argc,argv);
glutInitDisplayMode(GLUT_SINGLE|GLUT_RGB|GLUT_DEPTH);
glutInitWindowSize(400,400);
glutInitWindowPosition(100,100);
/*创建窗口*/
glutCreateWindow(" DRAW QUADRIC OBJECTS ");
/*绘制与显示*/
myInit();
glutReshapeFunc(myReshape);
glutDisplayFunc(myDisplay);
glutMainLoop();
return 0;
}
l gluNewQuadric创建一个二次对象。这个函数创建并返回一个指向新的二次对象的指针。当调用二次描述和控制函数是指向这个对象。如果返回值为0则表明没有足够的空间分配给该对象。
l glQuadricDrawStyle函数指定二次对象的绘制方式。本例中圆柱体的绘制方式为GLU_FILL。含义为用多边形原绘制本二次对象,多边形的绘制方式为逆时针。球体的绘制方式为GL_SILHOUETTE,即除边界外用一系列线来绘制二次对象。圆盘的绘制方式为GL_LINE,即用一系列线来绘制二次对象。部分圆盘的绘制方式为GL_POINT,即用一系列点来绘制二次对象。
l glQuadricNormals,指定二次对象使用的法向量类型。
l glQuadricOrientation,指定二次对象的内面或外面方位。GLU_OUTSIDE为缺省值,表明使用指向内面的法相量绘出二次对象,GLU_INSIDE表明使用指向外面的法相量绘出二次对象。
l glQuadricTexture指定二次对象是否使用纹理。GL_FALSE为缺省值。
l void gluCylinder(GLUquadricObj *qobj,GLdouble baseRadius,GLdouble topRadius,GLdouble height,Glint slices,Glint stacks)绘制一个圆柱体。
qobj指明是哪个二次对象。
baseRadius圆柱体在z=0时的半径。
topRadius圆柱体在z=height时的半径。
height圆柱体的高。
slices围绕着z轴分片的个数。
stacks顺着z轴分片的个数。stacks和slices垂直。
l void gluSphere(GLUquadricObj *qobj,GLdouble radius,Glint slices,Glint stacks)绘制一个球形。
qobj指明是哪个二次对象。
radius球体半径。
slices围绕着z轴分片的个数。
stacks顺着z轴分片的个数。
l void gluDisk(GLUquadricObj *qobj,GLdouble innerRadius,GLdouble outerRadius,Glint slices,Glint loops)绘制一个圆盘。
qobj指明是哪个二次对象。
innerRadius圆盘的内部半径,可能为0。
outerRadius圆盘的外部半径。
slices围绕着z轴分片的个数。
loops圆盘同心圆个数。
l void gluPartialDisk(GLUquadricObj *qobj,GLdouble innerRadius,GLdouble outerRadius,Glint slices,Glint loops,GLdouble startAngle,GLdouble sweepAngle)绘制一个圆盘的一部分。
startAngle起始角度,单位为度。
sweepAngle扫描角,单位为度。
4. 像素操作
例14:本例在窗口绘制一个三角形,然后利用glCopyPixel函数拷贝了五次该图形,并将这五个三角形放置在窗口的不同位置。
#include <stdlib.h>
#include <GL/glut.h>
/*设置背景色*/
void myInit(void)
{
glClearColor(1.0,1.0,1.0,1.0);
}
/*绘制彩色三角形*/
void triangle(void)
{
glBegin(GL_TRIANGLES);
glColor3f(1.0,1.0,0.0);
glVertex2f(10.0,10.0);
glColor3f(0.0,0.3,1.0);
glVertex2f(20.0,30.0);
glColor3f(1.0,0.0,0.0);
glVertex2f(30.0,10.0);
glEnd();
}
void myDisplay()
{
int i;
glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
glPushMatrix();
glTranslatef(10.0,100.0,0.0);
triangle();
glPopMatrix();
glPushMatrix();
for(i = 0;i < 5;i++)
{
glRasterPos2i(20+i*30,10+i*5);//为像素操作指定光栅位置
glCopyPixels(50,200,500,500,GL_COLOR);//在缓存中拷贝像素
}
glPopMatrix();
glFlush();
}
void myReshape(int w,int h)
{
glViewport(0,0,(GLsizei)w,(GLsizei)h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
if( w <= h)
gluOrtho2D(0.0,150,0.0,150.0*(GLfloat)h/(GLfloat)w);
else
gluOrtho2D(0.0,150*(GLfloat)w/(GLfloat)h,0.0,150.0);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
}
int main(int argc,char ** argv)
{
glutInit(&argc,argv);
glutInitDisplayMode(GLUT_SINGLE|GLUT_RGB|GLUT_DEPTH);
glutInitWindowSize(500,400);
glutInitWindowPosition(100,100);
glutCreateWindow(" copy ");
myInit();
glutReshapeFunc(myReshape);
glutDisplayFunc(myDisplay);
glutMainLoop();
return 0;
}
l glRasterPos在像素操作中指定光栅位置。同样后面的数字表示坐标维数,2表示坐标为x、y,3表示、,y、z。数字后面的字母表示参数类型。最后带V表示参数为指针。
l void glCopyPixels(GLint x, Glint y, GLsizei width, GLsizei height, GLenum type)函数将像素拷贝到缓存中。
x,y指定被拷贝像素的右下角坐标。
width,heigth指定被拷贝像素矩形区域的大小。
type指定拷贝数值的类型。值为颜色、深度或膜板值。本例中为颜色。
例15:此例在窗口左下角写单词FILE。
#include <stdlib.h>
#include <GL/glut.h>
/*字母F*/
GLubyte f_rasters[12] = {0xc0,0xc0,0xc0,0xc0,0xc0,0xfc,
0xfc,0xc0,0xc0,0xc0,0xff,0xff};
/*字母I*/
GLubyte i_rasters[12] = {0xff,0xff,0x18,0x18,0x18,0x18,
0x18,0x18,0x18,0x18,0xff,0xff};
/*字母L*/
GLubyte l_rasters[12] = {0xff,0xff,0xc0,0xc0,0xc0,0xc0,
0xc0,0xc0,0xc0,0xc0,0xc0,0xc0};
/*字母E*/
GLubyte e_rasters[12] = {0xff,0xff,0xc0,0xc0,0xc0,0xff,
0xff,0xc0,0xc0,0xc0,0xff,0xff};
void myInit(void)
{
glPixelStorei(GL_UNPACK_ALIGNMENT,1);//设置像素存储模式
glClearColor(1.0,1.0,1.0,1.0);//设置背景为白色
}
void myDisplay()
{
glClear(GL_COLOR_BUFFER_BIT);
glColor3f(0.0,0.0,0.0);//设置像素颜色为黑色
glRasterPos2i(20,20);//为像素指定位置
/*绘制位图*/
glBitmap(8,12,0.0,0.0,14.0,0.0,f_rasters);
glBitmap(8,12,0.0,0.0,14.0,0.0,i_rasters);
glBitmap(8,12,0.0,0.0,14.0,0.0,l_rasters);
glBitmap(8,12,0.0,0.0,14.0,0.0,e_rasters);
glFlush();
}
void myReshape(int w,int h)
{
glViewport(0,0,(GLsizei)w,(GLsizei)h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(0,w,0,h,-1.0,1.0);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
}
int main(int argc,char ** argv)
{
/*初始化*/
glutInit(&argc,argv);
glutInitDisplayMode(GLUT_SINGLE|GLUT_RGB);
glutInitWindowSize(500,400);
glutInitWindowPosition(100,100);
/*创建窗口*/
glutCreateWindow(" BitMap");
/*绘制图形*/
myInit();
glutReshapeFunc(myReshape);
glutDisplayFunc(myDisplay);
glutMainLoop();//进入GLUT事件处理循环
return 0;
}
l glBitmap(GLsizei width,GLsizei height,GLfloat xorig,GLfloat yorig,GLfloat xmove,GLfloat ymove,const GLubyte *bitmap)函数绘制一个位图。
width,height分别指定位图图像的宽度和高度。
xorig,yorig位图图像的原点位置。原点为位图的左下角。向右和向上为坐标轴的正向。
xmove,ymove绘制完位图后x,y相对于当前光栅的位移。
bitmap位图图像的地址。
你可以改变此函数的参数,观察不同大小不同位置的效果。
5. 动画
例16:一个旋转的立方体
#include <GL/glut.h>
GLfloat X = 10.0f;
GLfloat Y = 1.0f;
GLfloat Z = 5.0f;
void myDisplay(void)
{
GLfloat diffuse[] = {0.7,0.7,0.0,1.0};
glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
glColor3f(1.0,1.0,1.0);
/*绘制立方体*/
glPushMatrix();
glRotatef(X,1.0,0.0,0.0);
glRotatef(Y,0.0,1.0,0.0);
glRotatef(Z,0.0,0.0,1.0);
glMaterialfv(GL_FRONT,GL_DIFFUSE,diffuse);
glutSolidCube(1.0);
glPopMatrix();
glFlush();
glutSwapBuffers();//交换当前窗口使用层的缓存
}
void myReshape(int w,int h)
{
glViewport(0,0,w,h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluOrtho2D(-1.5,1.5,-1.5,1.5);
if(w <= h)
glOrtho(-2.25,2.25,-2.25*h/w,2.25*h/w,-10.0,10.0);
else
glOrtho(-2.25*w/h,2.25*w/h,-2.25,2.25,-10.0,10.0);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
}
void myAnimate(void)
{
X += 1.0;
Y += 1.0;
Z += 1.0;
glutPostRedisplay();//标记当前窗口需要重新绘制
}
int main(int argc,char ** argv)
{
/*初始化*/
glutInit(&argc,argv);
glutInitDisplayMode(GLUT_DOUBLE|GLUT_RGB|GLUT_DEPTH);
glutInitWindowSize(400,400);
glutInitWindowPosition(200,200);
/*创建窗口*/
glutCreateWindow("color");
/*绘制与显示*/
glutReshapeFunc(myReshape);
glutDisplayFunc(myDisplay);
glutIdleFunc(myAnimate);//设置全局空闲回调函数
glutMainLoop();
return(0);
}
myDisplay函数中有一个glutSwapBuffers()函数。此函数交换当前窗口使用层的缓存,它将后台缓存中的内容交换到前台缓存中,该函数执行的结果直到显示器垂直回行扫描后才看得到。必须使用双缓存结构,否则此函数不起任何作用。
myAanimate函数中glutPostRedisplay()函数标记当前窗口需要重新绘制。在glutMainLoop函数的事件处理循环的下一个反复中,将调用该窗口的显示回调函数重绘该窗口的图像层。
在main函数中glutInitDisplayMode中为GLUT_DOUBLE,而我们以前的很多例子为GLUT_SINGLE。main函数中还调用了glutIdleFunc,此函数设置全局空闲回调函数。,从而使GLUT程序可以执行后台任务或连续动画。
6. 菜单管理
例17:本例在蓝色的背景上绘制一个白色的正方形,在窗口内单击鼠标右键,弹出菜单,当选择不同菜单项时命令窗口会显示出是哪个菜单的哪个菜单相被激活。本例一个主菜单,主菜单有3个菜单条目及两个子菜单。两个子菜单都有3个菜单条目。
#include <GL/glut.h>
#include <stdio.h>
int menu,subMenu1,subMenu2;
/*在蓝色的背景上绘制一个白色的正方形*/
void myDraw(void)
{
glClearColor(0.0,0.0,1.0,0.0);
glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
glColor3f(1.0,1.0,1.0);
glOrtho(-1.0,1.0,-1.0,1.0,-1.0,1.0);
glBegin(GL_POLYGON);
glVertex2f(-0.5,-0.5);
glVertex2f(-0.5,0.5);
glVertex2f(0.5,0.5);
glVertex2f(0.5,-0.5);
glEnd();
glutSwapBuffers();
}
/*写出当前是哪个菜单*/
void GetCurrentMenu(void)
{
int nMenu;
nMenu = glutGetMenu();
if(nMenu == menu)
printf("The current menu is Main Menu.\n");
if(nMenu == subMenu1)
printf("The current menu is SubMenu1.\n");
if(nMenu == subMenu2)
printf("The current menu is SubMenu2.\n");
}
/*子菜单1*/
void SubMenuFunc1(int data)
{
GetCurrentMenu();
switch(data)
{
case 1:
printf("SubMenu1's item 1 is triggered.\n");
break;
case 2:
printf("SubMenu1's item 2 is triggered.\n");
break;
case 3:
printf("SubMenu1's item 3 is triggered.\n");
break;
}
}
/*子菜单2*/
void SubMenuFunc2(int data)
{
GetCurrentMenu();
switch(data)
{
case 1:
printf("SubMenu2's item 1 is triggered.\n");
break;
case 2:
printf("SubMenu2's item 2 is triggered.\n");
break;
case 3:
printf("SubMenu2's item 3 is triggered.\n");
break;
}
}
/*主菜单*/
void MenuFunc(int data)
{
GetCurrentMenu();
switch(data)
{
case 1:
printf("MainMenu's item 1 is triggered.\n");
break;
case 2:
printf("MainMenu's item 2 is triggered.\n");
break;
case 3:
printf("MainMenu's item 3 is triggered.\n");
break;
}
}
int main(int argc,char ** argv)
{
/*初始化*/
glutInit(&argc,argv);
glutInitDisplayMode(GLUT_DOUBLE|GLUT_RGB|GLUT_DEPTH);
glutInitWindowSize(500,400);
glutInitWindowPosition(100,100);
/*创建窗口*/
glutCreateWindow(" MENU");
glutDisplayFunc(myDraw);
/*创建子菜单1并加入菜单条目*/
subMenu1 = glutCreateMenu(SubMenuFunc1);
glutAddMenuEntry("SubMenu1's item1",1);
glutAddMenuEntry("SubMenu1's item2",2);
glutAddMenuEntry("SubMenu1's item3",3);
glutAttachMenu(GLUT_RIGHT_BUTTON);
/*创建子菜单2并加入菜单条目*/
subMenu2 = glutCreateMenu(SubMenuFunc2);
glutAddMenuEntry("SubMenu2's item1",1);
glutAddMenuEntry("SubMenu2's item2",2);
glutAddMenuEntry("SubMenu2's item3",3);
glutAttachMenu(GLUT_RIGHT_BUTTON);
/*创建主菜单并加入菜单条目及子菜单*/
menu = glutCreateMenu(MenuFunc);
glutAddMenuEntry("Item1",1);
glutAddMenuEntry("Item2",2);
glutAddMenuEntry("Item3",3);
glutAddSubMenu("SubMenu 1",subMenu1);
glutAddSubMenu("SubMenu 2",subMenu2);
glutAttachMenu(GLUT_RIGHT_BUTTON);
glutMainLoop();//进入GLUT事件处理循环
return 0;
}
l int glutCreateMenu(void(*func)(int value))创建一个新的弹出式菜单并返回一个唯一标识此菜单的整型表示符。func指明此菜单的功能。
l int glutAddMenuEntry(char *name,int value)在当前菜单底部增加一个菜单条目。
name指定显示在新菜单条目上的ASCII码字符串。
value指定当选择该菜单条目时传递到菜单回调函数中的数值。
l void glutAddSubMenu(char *name,int menu)在当前菜单的底部增加一个子菜单触发条目。
name指定显示在新菜单触发条目上的ASCII码字符串。
meun当选择该子菜单触发条目时弹出的子菜单的标识符。
l void glutAttachMenu(int button)把当前窗口的一个鼠标按键与当前菜单的标识符联系起来。
button指明鼠标的哪个按键。GLUT_LEFT_BUTTON、GLUT_MIDDLE_BUTTON及GLUT_RIGHT_BUTTON,分别表明鼠标左、中及右键。
l int glutGetMenu(void)获取当前菜单的标识符,如果没有菜单存在或前一个当前菜单被删除了,glutGetMenu则返回0值。
7. 小结
相关文章:

计算机科学实验教学示范中心,校领导调研计算机科学与技术国家级实验教学示范中心...
4月29日,副校长朱廷珺在实验管理中负责人陪同下,深入计算机科学与技术国家级实验教学示范中心、轨道交通信息与控制国家级虚拟仿真实验教学中心开展实地调研。在计算机实验中心,朱廷珺实地调研了计算机基础实验室、计算机软件实验室、硬件专业…

中科创达孙力:不迷信 AI 算法,智能视觉如何转型升级?
作者 | 若名 出品 | AI科技大本营 近日,中科创达副总裁孙力在 Thunder World 2018 嵌入式 AI 人工智能技术大会上发表了主题演讲,主要分享了以下三方面内容: 视觉的传统技术和挑战 嵌入式视觉AI智能视觉 智能视觉赋能行业的智能化升级转型 …

单元测试与敏捷开发
单元测试与敏捷开发 转载请保留作者信息: 作者:88250 Blog:http:/blog.csdn.net/DL88250 MSN & Gmail & QQ:DL88250gmail.com 在要求项目要尽量快地实现的时候,质量与开发进度上会出现一定的矛盾,…

“AI明星”第四范式C轮融资超10亿元,估值约12亿美元
AI科技大本营消息,12 月 19 日,第四范式宣布完成 C 轮融资,融资金额超过 10 亿元,估值约 12 亿美元。此次投资引入了包括国新、启迪、保利、三峡、中信、农银、交银等战略投资,红杉中国继续追加投资。除了原有股东中国…

精灵图 html为什么会变大,[html] 第128天 精灵图和base64如何选择呢?
可参考https://www.cnblogs.com/wangqi2019/p/10498627.htmlCss Sprites(雪碧图或css精灵),是网页图片处理的一种方式,它允许你将一个页面涉及到的所有零星图片都包含到一张大图中去,这样一来,当访问该页面时,载入的图…

组策略 从入门到精通(十)通过组策略进行软件分发和卸载
其实在前面windows server 2008的一些博文中,已经介绍了如何通过组策略进行软件的分发,在windows server 2003中有些无法完成的软件分发工作在windows server 2008中已经全部纠正了。http://zhengweiit.blog.51cto.com/1109863/291156 今天我们主要来探讨…

RedHatAS4.0-RAID技术
RedHatAS4.0-RAID技术

今晚8点直播 | 详解基于百度自定义模板的OCR结果结构化处理技术
随着行业的发展和技术的成熟,文字识别(OCR)目前已经应用到了多个行业中,比如物流行业快递包裹的分拣,金融行业的支票单据识别输入,交通领域中的车牌识别,以及日常生活中的卡证、票据识别等等。O…

电脑计算机科学型,电脑里附带的计算器有标准型和科学型二种,它 – 手机爱问...
2019-06-24如何用delphi7 0设计标准型计算器这是源代码:unit Unit1;interfaceuses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, Buttons, StdCtrls, ExtCtrls;type TForm1 class(TForm) Panel1: TPanel; Panel…

铜缆配线架的选择
我们现在考察一下为安装选择合适的铜缆配线架所必须考虑的因素。铜缆配线架一般分为经济型、中端或高端配线架。经济型配线架经济型配线架通常在结构上脆弱,性能不稳定交缺少技术支持或保证。配线架端接时一般会耗费较多的安装成本,没有电缆管理设备支持…

go6---slice切片
package main/* 切片Slice 其本身并不是数组,它指向底层的数组 作为变长数组的替代方案,可以关联底层数组的局部或全部 为引用类型 可以直接创建或从底层数组获取生成 使用len()获取元素个数,cap()获取容量 一般使用make()创建 如果多个slice…

TensorFlow支持Unicode,中文NLP终于省心了
整理 | 非主流出品 | AI科技大本营终于,TensorFlow 增加了对 Unicode 的支持。什么是 Unicode?Unicode 是计算机科学领域里的一项业界标准,包括字符集、编码方案等。Unicode 是为了解决传统的字符编码方案的局限而产生的,它为每种…

C#:String.Format数字格式化输出
C#:String.Format数字格式化输出 inta 12345678; //格式为sring输出//Label1.Text string.Format("asdfadsf{0}adsfasdf",a);//Label2.Text "asdfadsf"a.ToString()"adsfasdf";//Label1.Text string.Format("asdfadsf{0:C}adsfasdf&…

OpenStack如何实现高可用集群介绍
OpenStack是目前基于开源的,一个非常流行的云管理平台项目。这个项目由几个主要的组件组合起来完成一些具体的工作。因此它的集群比较复杂,也有多种选择方式。OpenStack 作为一个类似于 Amazon EC2 和 S3 的云基础架构服务(Infrastructure as a Service,…
accp8.0html作业,Accp8.0HTML标签
第一章1、HTML超文本标记语言2、网页3、网页头部4、网页标题5、网页主体6、DOCTYPE声明3种级别:(1)Strict 严格类型(2)Transitional过渡类型(3)Frameset框架类型7、网页摘要标签8、字符编码:gb2312简体中文ISO-885901纯英文big5繁体UTF-8国际通用编码9、…

向iOS越狱彻底说再见!
老牌第三方软件商店 Cydia 关闭在即,iPhone 越狱时代又见落日归途?作者 | 仲培艺出品 | CSDNCydia 线上商店是针对完成越狱的 iOS 设备的一种破解软件,在越狱过程中被装入到系统,为 iOS 设备提供第三方 App 的服务平台,…

ArrayList的subList方法
李说: ArrayList的subList方法获取到的是ArrayList的一段list,只是其中的一段视图。所以修改subList ,ArrayList同时会修改,因为本来就是同一个东西。 jdk文档中是这样说的: List<E> subList(int fromIndex, int toIndex) …

男孩子学计算机和学医哪个好,你认为学医好还是读211大学的电子信息好?
学医的好处。社会的地位和社会认可度较高。无可否认无论是在过去还是在将来,医生因为其救死扶伤的职业特点而被广泛大众所接受和认可。较高的社会地位会让你在将来的择偶、人际关系处理方面显得更有吸引力和话语权。工作稳定有保障。这点其实还是看题主的水平和实力…

Error Creating Control when creating a custom control
如果你在创建ASP.NET的Server Control 是遇到报错: "Error Creating Control" when creating a custom control 原因是 ToolboxData 元数据中的控件名称和控件的类(class)名不同,改为相同即可解决问题。转载于:https://www.cnblogs.com/DotNet…

精选180+Python开源项目,随你选!做项目何愁没代码
编辑 | Jane出品 | Python大本营每一位程序员,每天大部分时间都是在和代码打交道。但是对于广大的普通用户来说,最重要的不是代码,而是代码最终生成的应用程序。但是,每个项目都从头开始自己一行一行码代码,是非常不现…

八年级计算机网络公开课,计算机网络公开课教案.doc
计算机网络公开课教案公开课教案科目:计算机网络课题: 交换机配置文件备份与恢复知识目标:1、在本次课中要向学生传授交换机上传、下载服务器的安装和配置;2.学生学习交换机上传配置命令,完成交换机Flash内存中保存的配置文件上传…

Centos6.5升级系统自带gcc4.4.7到gcc4.8.0
下载 wget http://ftp.gnu.org/gnu/gcc/gcc-4.8.0/gcc-4.8.0.tar.bz2 解压 tar -xjvf gcc-4.8.0.tar.bz2 进入 cd gcc-4.8.0 下载所需软件( ftp://gcc.gnu.org/pub/gcc/infrastructure/mpfr-2.4.2.tar.bz2 ftp://gcc.gnu.org/pub/gcc/infrastructure/gmp-4.3.2.tar.…

photofunia
存个链接用~~~[url]http://www.photofunia.com/[/url]转载于:https://blog.51cto.com/wangyublues/120301

学计算机应用好还是汽车维修好,大学汽车运用与维修专业怎么样_学什么_前景好吗-520吉他网...
时间:2019-06-23 来源:网络资源 汽车运用与维修专业怎么样_学什么_前景好吗2019高考填报志愿时,汽车运用与维修专业怎么样、学什么、前景好吗等是广大考生和家长朋友们十分关心的问题。以下是大学生必备网整理的汽车运用与维修专业介绍、…

20T数据、百万奖金,同济和武大摘得开放数据创新应用大赛桂冠!
整理 | Jane出品 | AI科技大本营中国华录杯城市开放数据创新应用大赛,18 日在天津迎来了收官的决赛之战。本次大赛由中国华录集团有限公司和天津市津南区人民政府共同举办。利用天津市人民政府、企业开放的数据资源,吸引了众多国内高校科研团队和科技企业…

rrdtool报错
参考文档: http://serverfault.com/questions/662161/rrdtool-illegal-attempt-to-updatehttps://emacstragic.net/collectd-causing-rrd-illegal-attempt-to-update-using-time-errors/https://support.nagios.com/forum/viewtopic.php?f7&t26087 报错信息&am…

Grid R-CNN解读:商汤最新目标检测算法,定位精度超越Faster R-CNN
作者 | 周强来源 | 我爱计算机视觉Grid R-CNN是商汤科技最新发表于arXiv的一篇目标检测的论文,对Faster R-CNN架构的目标坐标回归部分进行了替换,取得了更加精确的定位精度,是最近非常值得一读的论文。今天就跟大家一起来细品此文妙处。一、作…

河南信息工程学校计算机协会申请书,协会成立申请书范文15篇.docx
协会成立申请书范文15篇协会成立申请书(一): 尊敬的系团委领导: 摄影作为一门艺术不仅仅能够丰富同学们的学习生活,同时对学院的建设也起到一个不可黙灭的作用。为了发挥自身优势,参加学校社团文化建设,培养同学…

Luna的大学读书史(1,Intro)
Luna看了看自己的屋子,乱乱的一大摊,地上有的地方的灰都已经是厚厚的一层,有的角落甚至还结了蜘蛛网。床上的被子和衣服搅在一起,书桌上散乱的摆着几根笔和一个大号笔记本,草稿纸上画了若干莫名其妙的符号,…

【BIEE】数据透视表格第一列添加序号
现在有这么一个需求,需要在数据透视图的表格前面条件一列序号,作为行号,如下图:那么实现这个如何实现呢?只需要在BIEE分析编辑界面,新建一列,然后公式定义为:RCOUNT(RSUM(1)) &#…