openGL绘图基本框架
openGL绘图入门和导入外部文件
本文主要介绍通用绘图软件openGL的数据类型和基本的绘图框架,此外还提供了导入obj外部文件的方法,提供的代码稍作修改即可使用,希望能方便初学者快速上手。
openGL的数据类型
openGL的程序结构
openGL的基本绘图框架
#include <GL/glut.h>
#include <cstdlib> void main(int argc, char** argv)
{
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB); // 在创建窗口的时候,指定其显示模式的类型(包括颜色模式和缓冲区类型) ,设置GLUT_DEPTH才能显示3D图形
glutInitWindowPosition(50, 100); // 设置窗口显示的初始位置
glutInitWindowSize(400, 300); // 设置窗口的宽和高
glutCreateWindow("窗口的名字"); // 创建窗口
init(); // 执行你自己编写的初始化函数
glutDisplayFunc(myDisplay); // 回调函数,显示图像,参数是你自己编写的显示函数
glutMainLoop(); // 显示并且等待后续的命令
} void init(void)//初始化设置
{
glClearColor(1.0, 1.0, 1.0, 0.0); // 指定颜色缓冲区的清除值,设置窗口的背景颜色
//投影的变换也常常被写到reshape里面,init中就不用
//画二维的图像
glMatrixMode(GL_PROJECTION); // 设置矩阵模式
//画二维图像,用二维正投影
gluOrtho2D(0.0, 200.0, 0.0, 150.0);
//画三维的图像,设置视椎体,开启深度测试
//为了显示 3D 图形,需要启用 GLUT 窗口程序的深度缓冲区(GLUT_DEPTH),深度测试遮挡剔除(GL_DEPTH_TEST),并设置观察裁剪空间
glFrustum(-2.5, 2.5, -2.5, 2.5, mynear, myfar);
glEnable(GL_DEPTH_TEST);
} void myDisplay(void)//显示函数
{
//设置颜色,R,G,B在0到1
glColor3f(0.0, 0.4, 0.2);
//在显示函数里面调用执行画图操作的函数
myGraphy();
//刷新当前缓冲区
glFlush();
} void myGraphy()
{
//画点,不可以直接用glVertex2i,这应该只是一个定位函数,不会显示
glBegin(GL_POINTS);
glVertex2i(xCoord, yCoord);
glEnd();
//画线,设置两个端点的位置
glBegin(GL_LINES);
glVertex2i(180, 15);
glVertex2i(10, 145);
glEnd();
} //为了防止变形可以用reshape函数进行设置,把init里面的一些初始化设置移到reshape里面,在main函数中init()的后面调用glutReshapeFunc(myReshape);
void myReshape(int w, int h)
{
winWidth = w;
winHeight = h;
glViewport(0, 0, w, h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(-5.0, 5.0, -5.0, 5.0, mynear, myfar);
viewxform_z = -5.0;
glMatrixMode(GL_MODELVIEW);
}
导入外部文件
首先介绍一下OBJ文件的格式
OBJ是一种3D模型文件,因此不包含动画、贴图路径、动力学等信息,且主要支持由多边形面片绘制成的模型。OBJ文件不包含面的颜色和材质定义信息,材质库信息储存在后缀是".mtl"的独立文件中。
obj文件的导入分为两个阶段,首先解析文件,也就是按文件的格式保存相应的参数,然后再根据这些参数绘制多边形面片,这些面片拼接成了3D模型。
1.OBJ文件解析:原理就是读取文件中的多边形面片的相关数据并存储在数组中方便绘制模型时使用。文件中顶点通过“v”进行标识,格式为“v x y z”。其中x,y,z分别表示三个维度的坐标值。面对象由“f”标识,可以由三角形或者四边形构成。解析代码如下:
ObjLoader::ObjLoader(string filename)
{
string line;
fstream f;
f.open(filename, ios::in);
if (!f.is_open()) {
cout << "Something Went Wrong When Opening Objfiles" << endl;
} while (!f.eof()) {
getline(f, line);//拿到obj文件中一行,作为一个字符串
vector<string>parameters;
string tailMark = " ";
string ans = ""; line = line.append(tailMark);
for (int i = 0; i < line.length(); i++) {
char ch = line[i];
if (ch != ' ') {
ans += ch;
}
else {
parameters.push_back(ans); //取出字符串中的元素,以空格切分
ans = "";
}
}
//cout << parameters.size() << endl;
if (parameters.size() != 4 && parameters.size() != 5) {
cout << "the size is not correct" << endl;
}
else {
if (parameters[0] == "v") { //如果是顶点的话
vector<GLfloat>Point;
for (int i = 1; i < 4; i++) { //从1开始,将顶点的xyz三个坐标放入顶点vector
GLfloat xyz = atof(parameters[i].c_str());
Point.push_back(xyz);
}
vSets.push_back(Point);
} else if (parameters[0] == "f") { //如果是面的话,存放三个顶点的索引
vector<GLint>vIndexSets;
if (parameters.size() == 5)
{
for (int i = 1; i <= 4; i++) {
string x = parameters[i];
string ans = "";
for (int j = 0; j < x.length(); j++) { //跳过‘/’
char ch = x[j];
if (ch != '/') {
ans += ch;
}
else {
break;
}
}
GLint index = atof(ans.c_str());
index = index--;//因为顶点索引在obj文件中是从1开始的,而我们存放的顶点vector是从0开始的,因此要减1
vIndexSets.push_back(index);
}
fSets.push_back(vIndexSets);
}
else
{
for (int i = 1; i < 4; i++) {
string x = parameters[i];
string ans = "";
for (int j = 0; j < x.length(); j++) { //跳过‘/’
char ch = x[j];
if (ch != '/') {
ans += ch;
}
else {
break;
}
}
GLint index = atof(ans.c_str());
index = index--;//因为顶点索引在obj文件中是从1开始的,而我们存放的顶点vector是从0开始的,因此要减1
vIndexSets.push_back(index);
}
fSets.push_back(vIndexSets);
}
}
}
}
f.close();
}
2.多边形面片的绘制:网上的有些源代码把所有的“f”标识的语句都默认成了只含三个参数,导致只能绘制三角形面片,无法呈现出完整的模型。其实可以有三个或者四个参数,用三角形或者四边形面片来绘制,对代码进行修改后绘出了完整模型。
void ObjLoader::Draw() {
for (int i = 0; i < fSets.size(); i++) {
GLfloat VN[3];
//三个顶点
GLfloat SV1[4];
GLfloat SV2[4];
GLfloat SV3[4];
GLfloat SV4[4]; if ((fSets[i]).size() != 4&& (fSets[i]).size() != 3) {
cout << "the fSetsets_Size is not correct" << endl;
}
else {
if ((fSets[i]).size() == 3)
{
glBegin(GL_TRIANGLES);//开始绘制三角形
glColor3f(0.255, 0.215, 0);
GLint firstVertexIndex = (fSets[i])[0];//取出顶点索引
GLint secondVertexIndex = (fSets[i])[1];
GLint thirdVertexIndex = (fSets[i])[2]; SV1[0] = (vSets[firstVertexIndex])[0];//第一个顶点
SV1[1] = (vSets[firstVertexIndex])[1];
SV1[2] = (vSets[firstVertexIndex])[2]; SV2[0] = (vSets[secondVertexIndex])[0]; //第二个顶点
SV2[1] = (vSets[secondVertexIndex])[1];
SV2[2] = (vSets[secondVertexIndex])[2]; SV3[0] = (vSets[thirdVertexIndex])[0]; //第三个顶点
SV3[1] = (vSets[thirdVertexIndex])[1];
SV3[2] = (vSets[thirdVertexIndex])[2]; GLfloat vec1[3], vec2[3], vec3[3];//计算法向量
//(x2-x1,y2-y1,z2-z1)
vec1[0] = SV1[0] - SV2[0];
vec1[1] = SV1[1] - SV2[1];
vec1[2] = SV1[2] - SV2[2]; //(x3-x2,y3-y2,z3-z2)
vec2[0] = SV1[0] - SV3[0];
vec2[1] = SV1[1] - SV3[1];
vec2[2] = SV1[2] - SV3[2]; //(x3-x1,y3-y1,z3-z1)
vec3[0] = vec1[1] * vec2[2] - vec1[2] * vec2[1];
vec3[1] = vec2[0] * vec1[2] - vec2[2] * vec1[0];
vec3[2] = vec2[1] * vec1[0] - vec2[0] * vec1[1]; GLfloat D = sqrt(pow(vec3[0], 2) + pow(vec3[1], 2) + pow(vec3[2], 2)); VN[0] = vec3[0] / D;
VN[1] = vec3[1] / D;
VN[2] = vec3[2] / D; glNormal3f(VN[0], VN[1], VN[2]);//绘制法向量
glVertex3f(SV1[0], SV1[1], SV1[2]);//绘制三角面片
glVertex3f(SV2[0], SV2[1], SV2[2]);
glVertex3f(SV3[0], SV3[1], SV3[2]);
glEnd();
}
else
{ glBegin(GL_POLYGON);
glColor3f(0.5, 0.5, 0);
GLint firstVertexIndex = (fSets[i])[0];//取出顶点索引
GLint secondVertexIndex = (fSets[i])[1];
GLint thirdVertexIndex = (fSets[i])[2];
GLint fourthVertexIndex = (fSets[i])[3]; SV1[0] = (vSets[firstVertexIndex])[0];//第一个顶点
SV1[1] = (vSets[firstVertexIndex])[1];
SV1[2] = (vSets[firstVertexIndex])[2]; SV2[0] = (vSets[secondVertexIndex])[0]; //第二个顶点
SV2[1] = (vSets[secondVertexIndex])[1];
SV2[2] = (vSets[secondVertexIndex])[2]; SV3[0] = (vSets[thirdVertexIndex])[0]; //第三个顶点
SV3[1] = (vSets[thirdVertexIndex])[1];
SV3[2] = (vSets[thirdVertexIndex])[2]; SV4[0] = (vSets[fourthVertexIndex])[0]; //第四个顶点
SV4[1] = (vSets[fourthVertexIndex])[1];
SV4[2] = (vSets[fourthVertexIndex])[2]; glVertex3f(SV1[0], SV1[1], SV1[2]);//绘制四边形面片
glVertex3f(SV2[0], SV2[1], SV2[2]);
glVertex3f(SV3[0], SV3[1], SV3[2]);
glVertex3f(SV4[0], SV4[1], SV4[2]);
glEnd();
}
}
}
}
效果展示:
github源代码:ursulalujun/CG-openGL (github.com)
这个仓库里还有几何变换,观察变换,鼠标、键盘交互等其他操作的源代码,欢迎大家访问!
参考文章:
https://blog.csdn.net/qq_38906523/article/details/75210105
openGL绘图基本框架的更多相关文章
- iOS 使用Quartz和OpenGL绘图
http://blog.csdn.net/coder9999/article/details/7641701 第十二章 使用Quartz和OpenGL绘图 有时应用程序需要能够自定义绘图.一个库是Qu ...
- C#使用原生的Directx和OpenGL绘图
原文 混合语言编程-C#使用原生的Directx和OpenGL绘图的方法 由于项目需要做一些图形展示,所以就想到了使用Directx和OpenGL来绘图,但项目准备使用C#来开发(大家比较熟悉C#), ...
- OpenGL绘图框架(GLFW)
下载地址:http://www.glfw.org/download.html
- 对OpenGL的GLFrame框架进行的扩展截至2014年11月29日
框架源自<OpenGL游戏编程>,增加了此框架的部分功能.其中有些小错误,尤其是MD2模型的那章,给出的框架只支持载入一个BOSS,当再载入一个BOSS时,就会发现两个模型的帧速会乱套. ...
- 在MFC框架中使用OpenGL的简单实例
引言 我们知道,在MFC框架中,用于绘图的接口是GDI.但GDI只能绘制简单的2D图形,要想制作精美的3D图形,一个可行的办法是使用OpenGL或者Direct3D等第三方库. 由于最近在给导师的一个 ...
- OpenGL编程-OpenGL框架-win32项目
在win32项目中开发的程序 小知识: 控制台应用程序运行就是dos的界面 项目一般采用了可视化开发 开发出来的东西就像QQ之类的 是有窗口界面的 程序运行结果是这样的 源代码:对第45行进行覆盖 # ...
- VC基于单文档OpenGL框架
本文是在VC6.0的环境下,运用MFC实现的OpenGL最基本框架,需要简单了解MFC编程(会在VC6.0里创建MFC单文档应用程序就行),甚至不必了解OpenGL的知识.以下是具体的步骤. 1.创建 ...
- iOS绘图UIBezierPath 和 Core Graphics框架
前言 iOS系统本身提供了两套绘图的框架,即UIBezierPath 和 Core Graphics.而前者所属UIKit,其实是对Core Graphics框架关于path的进一步封装,所以使用起来 ...
- IOS 绘图教程Quartz2D
http://www.cocoachina.com/industry/20140115/7703.html http://www.cnblogs.com/wendingding/p/3803020.h ...
随机推荐
- CF734B Anton and Digits 题解
Content 有 \(k_2\) 个 \(2\).\(k_3\) 个 \(3\).\(k_5\) 个 \(5\) 和 \(k_6\) 个 \(6\),你可以用这里面的数字来组成 \(256,32\) ...
- CF1433B Yet Another Bookshelf 题解
Content 在一个仅有 \(0,1\) 这两个数的数列上,每次可以选择一段全为1的连续区间将其左移 \(1\) 或者右移 \(1\).现给出 \(t\) 次询问,每次询问给出一个长度为 \(n\) ...
- Python sys模块 os模块、OS.open() | open() | OS._exit() | sys.exit() | exit()
sys模块:负责程序和Python交互. sys常用方法:=========================== sys.stdout.write('please:')val = sys.stdin ...
- c++设计模式概述之访问者
代码写的不够规范,目的是为了缩短篇幅,实际中请注意. 参看: http://c.biancheng.net/view/1397.html 1.概述 类比生活中的场景,购物商场中的商品.顾客.收营员.商 ...
- Android中Log信息的输出方法
第一步:在对应的mk文件中加入:LOCAL_LDLIBS:= -llog第二步:在要使用LOG的cpp文件中加入:#include <android/log.h>#define LOGD( ...
- 【LeetCode】648. Replace Words 解题报告(Python & C++)
作者: 负雪明烛 id: fuxuemingzhu 个人博客: http://fuxuemingzhu.cn/ 目录 题目描述 题目大意 解题方法 set 字典 前缀树 日期 题目地址:https:/ ...
- 【LeetCode】706. Design HashMap 解题报告(Python)
作者: 负雪明烛 id: fuxuemingzhu 个人博客: http://fuxuemingzhu.cn/ 目录 题目描述 题目大意 解题方法 日期 题目地址:https://leetcode.c ...
- 【.NET 遇上 GraphQL】 ChilliCream 平台介绍
ChilliCream ChilliCream 是一个开源免费的 GraphQL 平台, 提供了构建.管理, 和访问 GraphQL API 的端到端的解决方案. https://chillicrea ...
- Spring MVC 文件上传、Restful、表单校验框架
目录 文件上传 Restful Restful 简介 Rest 行为常用约定方式 Restful开发入门 表单校验框架 表单校验框架介绍 快速入门 多规则校验 嵌套校验 分组校验 综合案例 实用校验范 ...
- Morphological Image Processing
目录 概 reflection and translation Erosion and Dilation Erosion 示例 skimage.morphology.erosion dilation ...