-
OpenGL绘制球体
2018-11-06 01:06:04OpenGL绘制球体分享一下我老师大神的人工智能教程!零基础,通俗易懂!http://blog.csdn.net/jiangjunshow
也欢迎大家转载本篇文章。分享知识,造福人民,实现我们中华民族伟大复兴!
//球心坐标为(x,y,z),球的半径为radius,M,N分别表示球体的横纵向被分成多少份void drawSphere(GLfloat xx, GLfloat yy, GLfloat zz, GLfloat radius, GLfloat M, GLfloat N){ float step_z = PI/M; float step_xy = 2*PI/N; float x[4],y[4],z[4]; float angle_z = 0.0; float angle_xy = 0.0; int i=0, j=0; glBegin(GL_QUADS); for(i=0; i<M; i++) { angle_z = i * step_z; for(j=0; j<N; j++) { angle_xy = j * step_xy; x[0] = radius * sin(angle_z) * cos(angle_xy); y[0] = radius * sin(angle_z) * sin(angle_xy); z[0] = radius * cos(angle_z); x[1] = radius * sin(angle_z + step_z) * cos(angle_xy); y[1] = radius * sin(angle_z + step_z) * sin(angle_xy); z[1] = radius * cos(angle_z + step_z); x[2] = radius*sin(angle_z + step_z)*cos(angle_xy + step_xy); y[2] = radius*sin(angle_z + step_z)*sin(angle_xy + step_xy); z[2] = radius*cos(angle_z + step_z); x[3] = radius * sin(angle_z) * cos(angle_xy + step_xy); y[3] = radius * sin(angle_z) * sin(angle_xy + step_xy); z[3] = radius * cos(angle_z); for(int k=0; k<4; k++) { glVertex3f(xx+x[k], yy+y[k],zz+z[k]); } } } glEnd();}
给我老师的人工智能教程打call!http://blog.csdn.net/jiangjunshow
-
C#+OpenGL绘制球体
2017-06-22 15:16:11用VS2012编写 -
Android OpenGL绘制球体
2016-08-16 18:01:52opengl画球~~_(:зゝ∠)_创建GLSurfaceView,并调用setRenderer(GLSurfaceView.Renderer)方法注册其渲染器.
GLSurfaceView.Renderer 定义了一个统一图形绘制的接口,它定义了如下三个接口函数:
onSurfaceCreated:在这个方法中主要用来设置一些绘制时不常变化的参数.
onSurfaceChanged:如果设备支持屏幕横向和纵向切换,这个方法将发生在横向<->纵向互换时。此时可以重新设置绘制的纵横比率。
onDrawFrame:定义实际的绘图操作.@Override public void onSurfaceCreated(GL10 gl, EGLConfig config) { // 设置背景色:白色 gl.glClearColor(1.0f, 1.0f, 1.0f, 1.0f); // 启动阴影平滑 gl.glShadeModel(GL10.GL_SMOOTH); // 复位深度缓存 gl.glClearDepthf(1f); // 所做深度测试的类型 gl.glDepthFunc(GL10.GL_LEQUAL); // 启动深度测试 gl.glEnable(GL10.GL_DEPTH_TEST); // 对透视进行修正 gl.glHint(GL10.GL_PERSPECTIVE_CORRECTION_HINT, GL10.GL_NICEST); //计算球面顶点坐标 makeSphereVertices(); } @Override public void onSurfaceChanged(GL10 gl, int width, int height) { // 设置输出屏幕大小 gl.glViewport(0, 0, width, height); // 设置投影矩阵 gl.glMatrixMode(GL10.GL_PROJECTION); // 重置投影矩阵 gl.glLoadIdentity(); // 设置视口大小 GLU.gluPerspective(gl, 50, (float) width / (float) height, 0.1f, 100.0f); // 设置透视图视口大小 gl.glMatrixMode(GL10.GL_MODELVIEW); // 重置投影矩阵 gl.glLoadIdentity(); } @Override public void onDrawFrame(GL10 gl) { // 清除屏幕和深度缓存 gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT); // 重置当前的模型观察矩阵 l.glLoadIdentity(); //设置画笔颜色 gl.glColor4f(0.0f, 0.0f, 0.0f, 1.0f); //设置视图点 GLU.gluLookAt(gl, 0.0f, 5.0f, 15.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f); //画图 draw(gl); }
makeSphereVertices()是用来计算球面顶点坐标的方法。球体的绘制,实际上就是绘制一个多面体,当多面体的边数够多,看起来就像是一个球了。
private void makeSphereVertices() { float altitude;//纬度 float altitudeDelta;//下一层纬度 float azimuth;//经度 float ex;//点坐标x float ey;//点坐标y float ez;//点坐标z //将纬度等分成divide份,这样就能计算出每一等份的纬度值 for(int i = 0; i <= divide; i++) { //获取当前等份的纬度值 altitude = (float) (Math.PI/2.0 - i * (Math.PI) / divide); //获取下一等份的纬度值 altitudeDelta = (float) (Math.PI/2.0 - (i + 1) * (Math.PI) / divide); //当前纬度和下一纬度的点坐标 float[] vertices = new float[divide*6+6]; //将经度等分成divide份,这样就能得到当前纬度值和下一纬度值的每一份经度值 for(int j = 0; j <= divide; j++) { //计算经度值 azimuth = (float)(j * (Math.PI*2) / divide); ex = (float) (Math.cos(altitude) * Math.cos(azimuth)); ey = (float) Math.sin(altitude); ez = (float) -(Math.cos(altitude) * Math.sin(azimuth)); //此经度值下的当前纬度的点坐标 vertices[6*j+0] = radius * ex; vertices[6*j+1] = radius * ey; vertices[6*j+2] = radius * ez; ex = (float) (Math.cos(altitudeDelta) * Math.cos(azimuth)); ey = (float) Math.sin(altitudeDelta); ez = (float) -(Math.cos(altitudeDelta) * Math.sin(azimuth)); //此经度值下的下一纬度的点坐标 vertices[6*j+3] = radius * ex; vertices[6*j+4] = radius * ey; vertices[6*j+5] = radius * ez; } //将点坐标转换成FloatBuffer类型添加到点坐标集合ArrayList<FloatBuffer>里 mVertices.add(makeFloatBufferFromArray(vertices)); } }
makeFloatBufferFromArray()用来将点坐标数组转换成绘画时声明点坐标的FloatBuffer类型private FloatBuffer makeFloatBufferFromArray(float[] array) { ByteBuffer byteBuffer = ByteBuffer.allocateDirect(array.length * Float.SIZE); byteBuffer.order(ByteOrder.nativeOrder()); FloatBuffer floatBuffer = byteBuffer.asFloatBuffer(); floatBuffer.put(array); floatBuffer.position(0); return floatBuffer; }
最后是draw()方法,当点坐标都获取、所有数据都初始化之后,就可以将球画出来啦。<pre name="code" class="java"> private void draw(GL10 gl) { //打开顶点开关 gl.glEnableClientState(GL10.GL_VERTEX_ARRAY); //每次声明两条临近的纬度线的点坐标并绘制出来 for(int i = 0;i <= divide ; i++){ //将顶点坐标传给 OpenGL 管道 gl.glVertexPointer(3, GL10.GL_FLOAT, 0, mVertices.get(i)); //用画线的方式将点连接并画出来 gl.glDrawArrays(GL10.GL_LINE_STRIP, 0, divide*2+2); } //关闭顶点开关 gl.glDisableClientState(GL10.GL_VERTEX_ARRAY); }
最后就长这样啦~~~(✿◡‿◡)
完整代码下载地址:点击打开链接
-
结合基于对话框的MFC+opencv+OpenGL绘制球体或者读取图片
2018-12-03 15:44:07本工具主要是利用基于对话框的MFC工程结合OpenCV和OpenGL读取图片或者绘制球体三角形等形状。主要通过点击MFC对话框的button按钮,弹出两个非模态对话框,一个用于OpenGL显示图像,另一个设置滑动条控件控制图像的... -
OpenGL绘制球体模拟自由落体运动(基于Qt)
2018-05-10 17:05:371、其中比较关键的是设定一个计时器,在一个视觉暂留时间段(dt=0.02s)内根据小球的位置坐标绘制小球。2、在小球弹到地面的时候会因为碰撞而有能量损耗,其表现形式为速度减小并反向,而速度减小则可以通过改变加...自由落体的物理公式想必大家都清楚(y=vt+0.5gt^2)。
但是用程序如何模拟这个过程呢?
1、其中比较关键的是设定一个计时器,在一个视觉暂留时间段(dt=0.02s)内根据小球的位置坐标绘制小球。
2、在小球弹到地面的时候会因为碰撞而有能量损耗,其表现形式为速度减小并反向,而速度减小则可以通过改变加速度a的大小来控制(F=ma嘛,不知道这样解释合不合理,迷)
3、终止条件的判断:
if(ball.vy<1 && ball.y<-2.0){ //中止条件
ball.vy=0;
ball.y=-2.0;
G=0;
}
这里ball.vy为速度大小,ball.y为高度坐标(地面位置为-2.0),条件为什么不是ball.vy<0呢?这是因为速度的减少或增加是以dt为单位的(非连续),不一定能取到0值,如果条件设为0那么小球会一直在一个很小的范围内震动。(不信你可以试试)
下面附上我的程序实现:(因为考试复习原因没有给小球添加纹理,后面有时间了再补上)
widget.h
QTimer *timer; //定时器
//GLuint texName; //材质路径
GLdouble dt; //间隔时间
bool direction; //小球运动方向,向下为true
double G;
GLuint *tex0;//纹理
QString bmpfile;
QPoint m_last;
double dist,horizontal,vertical;
typedef struct b //定义储存球体的结构
{
GLdouble y;
GLdouble vy;
} Ball;
Ball ball;
public slots:
void updataScene();
widget.cpp
Widget::Widget(QWidget *parent)
: QGLWidget(parent)
{
timer = new QTimer(this);
connect(timer,SIGNAL(timeout()),this,SLOT(updataScene()));
timer->start(10);
}
void Widget::initializeGL(){
dt=0.02;
ball.y = 10 ; //初始化球体属性
ball.vy = 0 ;
direction = true;
G = 9.8;
bmpfile = "://floor.jpg";
tex0 = new GLuint;
dist = 2.0;
vertical=45.0;
horizontal=45.0;
glClearColor(0.0,0.0,0.0,0.0);
glEnable(GL_DEPTH_TEST);
glShadeModel(GL_SMOOTH);
//glEnable(GL_LIGHTING); //开启光照
// glEnable(GL_LIGHT0); //开启光源0
glEnable(GL_AUTO_NORMAL);
glEnable(GL_NORMALIZE);
glMaterialf(GL_FRONT,GL_SHININESS,64.0);
loadTexture(bmpfile,tex0);
}
void Widget::paintGL(){
glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
glClearColor(0.6,0.6,0.6,1);
glLoadIdentity();
float eyex=dist*cos(vertical/180.0*PI)*sin(horizontal/180.0*PI);
float eyey=dist*sin(vertical/180.0*PI);
float eyez=dist*cos(vertical/180.0*PI)*cos(horizontal/180.0*PI);
gluLookAt(eyex, eyey,eyez, 0.0, 0.0, 0.0, 0, 1, 0);
//gluLookAt(1,2,1,0,0,0,0,1,0);
glDisable(GL_TEXTURE_2D); //画小球时先不使用纹理
glPushMatrix();
glTranslated(0,ball.y,0.0);
glutWireSphere(2,50,50);
if(ball.vy<1 && ball.y<-2.0){ //中止条件
ball.vy=0;
ball.y=-2.0;
G=0;
}
if(direction){ //向下运动
G=9.8;
if(ball.y-(ball.vy*dt+0.5*G*dt*dt) <=-2){
direction = false; //触发转向条件,改变direction的值,使球体运动方向改变
G += 6.0;
}
ball.y = ball.y-(ball.vy*dt+0.5*G*dt*dt); //根据牛顿运动定律计算出球的位移公式
ball.vy = ball.vy + G*dt; //根据牛顿运动定律计算出球体的速度
}
else{ //向上运动
if(ball.y >-2 && ball.vy<0){
direction = true;
}
ball.y = ball.y+(ball.vy*dt-0.5*G*dt*dt);
ball.vy = ball.vy-G*dt;
}
glPopMatrix(); //将当前矩阵弹出
glPushMatrix();
// glPushAttrib(GL_ALL_ATTRIB_BITS);
// glColor3f(0.0, 0.0, 1.0);
glEnable(GL_TEXTURE_2D);
// loadTexture(bmpfile,tex0);
glBegin(GL_QUADS);
glTexCoord2f( 0.0, 0.0 );glVertex3f(10.0,-4.0,0.0);
glTexCoord2f( 1.0, 0.0 );glVertex3f(0.0,-4.0,-6.0);
glTexCoord2f( 1.0, 1.0 );glVertex3f(-6.0,-4.0,0.0);
glTexCoord2f( 0.0, 1.0 );glVertex3f(0.0, -4.0,10.0);
glEnd();
//glPopAttrib();
glPopMatrix();
glFlush();
}
void Widget::loadTexture(QString filepath, GLuint *texture){ //加载纹理
QImage tex, buf;
if(!buf.load(filepath))
{
qDebug()<<"Error: failed to load image!";
exit(1);
}
tex = convertToGLFormat(buf); //转化为rgba类型的数据集
glGenTextures(1, texture);
glBindTexture(GL_TEXTURE_2D, *texture);
gluBuild2DMipmaps(GL_TEXTURE_2D, GL_RGBA, tex.width(), tex.height(), GL_RGBA, GL_UNSIGNED_BYTE,tex.bits());
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 0);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAX_LEVEL,3);
}
void Widget::mousePressEvent(QMouseEvent *e)
{
m_last = e->pos();
}
void Widget::mouseMoveEvent(QMouseEvent *e)
{
if(e->buttons() & Qt::LeftButton)
{
QPoint m_now = e->pos();
float disx = m_now.x() - m_last.x();//两个鼠标x坐标的差
float disy = m_now.y() - m_last.y(); //m_last是之前点击事件取得的鼠标位置
//更改观察方向
horizontal -= disx/25;
vertical += disy/25;
m_last = m_now;
updateGL();
}
}
运行结果截图:
此处只截取从一定高度落下并来回弹跳的最终结果。以下为完整工程代码的链接:
https://download.csdn.net/download/did_you/10406118
-
OpenGL球体绘制与球体贴图
2016-08-18 16:16:34OpenGL球体绘制与球体贴图 -
【OpenGL】绘制球体
2020-03-06 18:45:27EBO(准备再GPU中进行处理),设置顶点属性指针(本质上就是告诉OpenGL如何处理数据) 4-着色器: 给出顶点和片段着色器,然后链接为着色器程序,渲染时使用着色器程序 5-渲染: 使用画线模式画圆,开启面...步骤
1-初始化:
GLFW窗口,GLAD
2-计算球体顶点:
通过数学方法计算球体的每个顶点坐标
3-数据处理:
通过球体顶点坐标构造三角形网络,生成并绑定VAO&VBO&EBO(准备再GPU中进行处理),设置顶点属性指针(本质上就是告诉OpenGL如何处理数据)
4-着色器:
给出顶点和片段着色器,然后链接为着色器程序,渲染时使用着色器程序
5-渲染:
使用画线模式画圆,开启面剔除,剔除背面,使用线框模式画球,清空缓冲,交换缓冲区检查触发事件
6-结束:
释放资源
结果
填充模式和线框模式效果对比
开启面剔除和线框模式效果对比
只需要展示一个面,否则会有重合,此处剔除背面为例
代码
此处只给出main.cpp,具体工程参考本人的github
main.cpp
/* 步骤: 1-初始化: GLFW窗口,GLAD 2-计算球体顶点:通过数学方法计算球体的每个顶点坐标 3-数据处理: 通过球体顶点坐标构造三角形网络,生成并绑定VAO&VBO&EBO(准备再GPU中进行处理),设置顶点属性指针(本质上就是告诉OpenGL如何处理数据) 4-着色器:给出顶点和片段着色器,然后链接为着色器程序,渲染时使用着色器程序 5-渲染:使用画线模式画圆,开启面剔除,剔除背面,使用线框模式画球,清空缓冲,交换缓冲区检查触发事件 6-结束:释放资源 */ #include <glad/glad.h> #include <GLFW/glfw3.h> #include "Shader.h" #include <iostream> #include <math.h> #include <vector> const unsigned int screen_width = 780; const unsigned int screen_height = 780; const GLfloat PI= 3.14159265358979323846f; //将球横纵划分成50*50的网格 const int Y_SEGMENTS = 50; const int X_SEGMENTS = 50; int main() { /*1-初始化*/ //初始化GLFW glfwInit();//初始化GLFW glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);//opengl版本号3.3 glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);// 次版本号3 glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);//使用核心模式(无序向后兼容性) glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);//如果使用的是Mac OS X系统,需加上这行 glfwWindowHint(GLFW_RESIZABLE, false);//不可改变窗口大小 //创建窗口(宽、高、窗口名称) auto window = glfwCreateWindow(screen_width, screen_height,"Sphere",nullptr,nullptr); //检测窗口是否创建成功 if (window==nullptr) { std::cout << "Failed to Create OpenGL Context" << std::endl; glfwTerminate(); return -1; } glfwMakeContextCurrent(window);//将窗口的上下文设置为当前进程的主上下文 //初始化GLAD,加载OpenGL指针地址的函数 if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress)) { std::cout<<"Failed to initialize GLAD"<<std::endl; return -1; } //指定当前视口尺寸(前两个参数为左下角位置,后两个参数是渲染窗口宽、高) glViewport(0, 0, screen_width, screen_height); std::vector<float> sphereVertices; std::vector<int> sphereIndices; /*2-计算球体顶点*/ //生成球的顶点 for (int y=0;y<=Y_SEGMENTS;y++) { for (int x=0;x<=X_SEGMENTS;x++) { float xSegment = (float)x / (float)X_SEGMENTS; float ySegment = (float)y / (float)Y_SEGMENTS; float xPos = std::cos(xSegment * 2.0f * PI) * std::sin(ySegment * PI); float yPos = std::cos(ySegment * PI); float zPos = std::sin(xSegment * 2.0f * PI) * std::sin(ySegment * PI); sphereVertices.push_back(xPos); sphereVertices.push_back(yPos); sphereVertices.push_back(zPos); } } //生成球的Indices for (int i=0;i<Y_SEGMENTS;i++) { for (int j=0;j<X_SEGMENTS;j++) { sphereIndices.push_back(i * (X_SEGMENTS + 1) + j); sphereIndices.push_back((i + 1) * (X_SEGMENTS + 1) + j); sphereIndices.push_back((i + 1) * (X_SEGMENTS + 1) + j+1); sphereIndices.push_back(i* (X_SEGMENTS + 1) + j); sphereIndices.push_back((i + 1) * (X_SEGMENTS + 1) + j + 1); sphereIndices.push_back(i * (X_SEGMENTS + 1) + j + 1); } } /*3-数据处理*/ unsigned int VBO, VAO; glGenVertexArrays(1, &VAO); glGenBuffers(1, &VBO); //生成并绑定球体的VAO和VBO glBindVertexArray(VAO); glBindBuffer(GL_ARRAY_BUFFER, VBO); //将顶点数据绑定至当前默认的缓冲中 glBufferData(GL_ARRAY_BUFFER, sphereVertices.size() * sizeof(float), &sphereVertices[0], GL_STATIC_DRAW); GLuint element_buffer_object;//EBO glGenBuffers(1, &element_buffer_object); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, element_buffer_object); glBufferData(GL_ELEMENT_ARRAY_BUFFER, sphereIndices.size() * sizeof(int), &sphereIndices[0], GL_STATIC_DRAW); //设置顶点属性指针 glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0); glEnableVertexAttribArray(0); //解绑VAO和VBO glBindBuffer(GL_ARRAY_BUFFER, 0); glBindVertexArray(0); /*4-着色器*/ Shader shader("task3.vs", "task3.fs"); /*5-渲染*/ //渲染循环 while (!glfwWindowShouldClose(window)) { //清空颜色缓冲 glClearColor(0.0f, 0.34f, 0.57f, 1.0f); glClear(GL_COLOR_BUFFER_BIT); shader.Use(); //绘制球 //开启面剔除(只需要展示一个面,否则会有重合) glEnable(GL_CULL_FACE); glCullFace(GL_BACK); glBindVertexArray(VAO); //使用线框模式绘制 glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); glDrawElements(GL_TRIANGLES, X_SEGMENTS * Y_SEGMENTS * 6, GL_UNSIGNED_INT, 0); //点阵模式绘制 //glPointSize(5); //glDrawElements(GL_POINTS, X_SEGMENTS * Y_SEGMENTS * 6, GL_UNSIGNED_INT, 0); //交换缓冲并且检查是否有触发事件(比如键盘输入、鼠标移动) glfwSwapBuffers(window); glfwPollEvents(); } /*6-结束*/ //删除VAO和VBO,EBO glDeleteVertexArrays(1, &VAO); glDeleteBuffers(1, &VBO); glDeleteBuffers(1, &element_buffer_object); //清理所有的资源并正确退出程序 glfwTerminate(); return 0; }
-
opengl:绘制球体
2017-05-03 09:53:32这里只是绘制了球面,如果想绘制球体,只用在渲染时,加入点的法向量即可。 点的数据结构: class Point { public : Point (){}; Point( double a, double b, double c):x(a),y(b),z(c){}; public ... -
9-OpenGLES绘制球体
2020-07-14 14:25:05// 计算球体坐标 float R = 0.7f;// 球半径 int statck = 8;// 水平层数 float stackStep = (float) (Math.PI / statck);// 单位角度值 int slice = 12; float sliceStep = (float) Math.PI / ... -
ios应用源码之利用opengl固定流水线绘制球体opengltest 2018127
2018-12-07 12:35:49ios应用源码之利用opengl固定流水线绘制球体opengltest -
使用OpenGL完成绘制旋转球体
2020-06-13 11:54:55尝试课本实例使用OpenGL完成绘制旋转球体课本实例效果窗口初始设置绘制球体准备绘制球体MainActivity函数设置实现效果参考 课本实例效果 自用 窗口初始设置 窗口的一些初始设置 @Override public void ... -
OpenGL ES 3. 绘制球体 实战
2020-04-05 15:59:45绘制球体。 OpenGL ES 中任何形状的 3D 物体都是用三角形而成的, 因此,构建面物体最重要的就是到将面恰当划分成三角形的策略。最基本的策略是首先按照一定的规则将物体按行和列两个方向进行划分,这时就可以... -
OpenGL递归细分四面体法绘制球体
2020-06-30 03:25:18北京航空航天大学计算机学院 2020春季计算机图形学课程第三次作业的一部分,使用OpenGL,用递归细分四面体法绘制球体 -
OpenGL+WebGL——绘制球体
2019-08-30 15:32:26编写C++程序main.cpp,包括构建点的数据结构、计算球体的参数、绘制球面、初始化设置、绘图函数与主函数调用 #include <GL\glut.h> #include <math.h> #define PI 3.14159265358979323846 #define PI2... -
Fractal:小型C ++-绘制球体的OpenGL程序-源码
2021-04-06 03:36:56小型C ++-绘制球体的OpenGL程序