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 ...
随机推荐
- 什么是Docker?
容器技术的起源 假设你们公司正在秘密研发下一个"今日头条"APP,我们姑且称为明日头条,程序员自己从头到尾搭建了一套环境开始写代码,写完代码后程序员要把代码交给测试同学测试,这时测 ...
- [BUUCTF]PWN——inndy_rop
inndy_rop 附件 步骤: 例行检查,32位,开启了nx保护 本地调试运行没看出个啥,直接上ida,一开始f5会报错, 找到报错提示的位置,点击option–>general调出如图的界面 ...
- c#中Array,ArrayList 与List<T>的区别、共性与转换
本文内容来自我写的开源电子书<WoW C#>,现在正在编写中,可以去WOW-Csharp/学习路径总结.md at master · sogeisetsu/WOW-Csharp (gith ...
- 深入理解java虚拟机(一)
java历史 1996.01.23发布Jdk1.0 1998.12.04发布jdk1.2(里程碑的版本)注意:集合容器Collection和Map都是从1.2开始 1999.04.27HotSpot虚 ...
- Python写业务逻辑的几个编码原则
作为一个写业务逻辑的boy,我需要专注的就是把业务逻辑写好.写业务逻辑并不复杂,就是把编程最基础的东西使用好,有变量.循环.流程控制.函数.数据库等. 但是写出的逻辑要通俗易懂.易于理解,避免炫技.晦 ...
- 【LeetCode】1110. Delete Nodes And Return Forest 解题报告 (C++)
作者: 负雪明烛 id: fuxuemingzhu 个人博客:http://fuxuemingzhu.cn/ 目录 题目描述 题目大意 解题方法 递归 日期 题目地址:https://leetcode ...
- 【LeetCode】394. Decode String 解题报告(Python)
作者: 负雪明烛 id: fuxuemingzhu 个人博客: http://fuxuemingzhu.cn/ 目录 题目描述 题目大意 解题方法 栈 日期 题目地址:https://leetcode ...
- 1340 - Story of Tomisu Ghost
1340 - Story of Tomisu Ghost PDF (English) Statistics Forum Time Limit: 2 second(s) Memory Limit: ...
- 使用.NET 6开发TodoList应用(9)——实现PUT请求
系列导航及源代码 使用.NET 6开发TodoList应用文章索引 需求 PUT请求本身其实可说的并不多,过程也和创建基本类似.在这篇文章中,重点是填上之前文章里留的一个坑,我们曾经给TodoItem ...
- 本地修改配置hosts文件解决Github加载慢问题
本地修改配置hosts文件解决Github加载慢问题 手动方式 hosts 文件在每个系统的位置不一,详情如下: Windows 系统:C:\Windows\System32\drivers\etc\ ...