话说程序员有三大浪漫,操作系统、编译原理和计算机图形学。这里称作计算机图形学,而不是图形学,是为了避免歧义。

opengl是干什么的,可以自行google。这里仅作为一个学习里程中的记录。不作为权威指南。

入门教程参见,https://learnopengl-cn.readthedocs.io/zh/latest/01%20Getting%20started/02%20Creating%20a%20window/

opengl的环境配置可以见,https://zhuanlan.zhihu.com/p/23226676?utm_medium=social&utm_source=qq,谢谢大神分享。

本是在windows10, visual studio2015的环境下运行。顺便提一句,windows10自带opengl库,即包含了opengl32.lib。下面上代码。

shader.vs    顶点着色器代码

#version  core
layout (location = ) in vec3 position;//in 代表输入向量, location,与下面的顶点属性描述有关。
layout (location = ) in vec3 color; out vec3 ourColor;//out 代表输出3维向量,作为片段着色器的输入,见下文 void main()
{
gl_Position = vec4(position, 1.0f);
ourColor = color;
}

shader.frag  片段着色器代码

#version  core
in vec3 ourColor;
out vec4 color; void main()
{
color = vec4(ourColor, 1.0f);
}

main.cpp

#include <iostream>
// GLEW
#define GLEW_STATIC
#include <GL/glew.h>
// GLFW
#include <GLFW/glfw3.h>
// Other includes
#include "Shader.h" // Function prototypes
void key_callback(GLFWwindow* window, int key, int scancode, int action, int mode); // Window dimensions
const GLuint WIDTH = , HEIGHT = ;
// The MAIN function, from here we start the application and run the game loop
int main()
{
// Init GLFW
glfwInit();
// Set all the required options for GLFW
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, );
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, );
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
glfwWindowHint(GLFW_RESIZABLE, GL_FALSE); // Create a GLFWwindow object that we can use for GLFW's functions
GLFWwindow* window = glfwCreateWindow(WIDTH, HEIGHT, "LearnOpenGL", nullptr, nullptr);
glfwMakeContextCurrent(window); // Set the required callback functions
glfwSetKeyCallback(window, key_callback); // Set this to true so GLEW knows to use a modern approach to retrieving function pointers and extensions
glewExperimental = GL_TRUE;
// Initialize GLEW to setup the OpenGL Function pointers
glewInit(); // Define the viewport dimensions
glViewport(, , WIDTH, HEIGHT); //读取shader文件,并编译,见shader.h代码
Shader ourShader("C:\\Users\\leng\\Desktop\\shader.vs", "C:\\Users\\leng\\Desktop\\shader.frag"); // 一维数组,每六个代表一个顶点属性,前三个代表位置属性,后三个代表颜色属性
GLfloat vertices[] = {
// Positions // Colors
0.5f, -0.5f, 0.0f, 1.0f, 0.0f, 0.0f, // Bottom Right
-0.5f, -0.5f, 0.0f, 0.0f, 1.0f, 0.0f, // Bottom Left
0.0f, 0.5f, 0.0f, 0.0f, 0.0f, 1.0f // Top
};
GLuint VBO, VAO;//声明顶点缓冲,声明顶点数组用于管理顶点数据
glGenVertexArrays(, &VAO);//创建顶点数组,返回一个独一无二的整数,标识数组
glGenBuffers(, &VBO);//创建顶点缓冲,返回一个独一无二的整数,标识缓冲区 glBindVertexArray(VAO);//绑定顶点数组
glBindBuffer(GL_ARRAY_BUFFER, VBO);//绑定顶点缓冲
  //指定顶点数组的数据源为vertices,第四个参数代表显卡如何管理给定的数据,GL_STATIC_DRWA代表几乎不会改变
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW); // 指定顶点属性的解析方式。即,如何从顶点缓冲获取相应的顶点属性和相应的颜色属性。或者说,顶点着色器中如何知道去哪个顶点属性分量重着色呢
  //对每一个顶点而言,属性有2种,一是位置属性,而是颜色属性,因此每六个浮点数决定了一个顶点的位置和颜色   //顶点着色器中使用layout(location = 0)定义了position顶点属性的位置值(Location),因此第一个参数,代表属性分量的索引
  //参数二:顶点位置属性的维度,参数三:属性向量的数据类型,参数四:是否标准化;参数五,顶点位置属性的总字节长度,参数六:在缓冲数组中的偏移量,即起始位置
glVertexAttribPointer(, , GL_FLOAT, GL_FALSE, * sizeof(GLfloat), (GLvoid*));
glEnableVertexAttribArray();//启用属性0,因为默认是禁用的
// 参数一,对应顶点着色器中的layout (location = 1) in vec3 color;参数六:说明颜色属性的偏移量在三个浮点数后,与上文vertices一致
glVertexAttribPointer(, , GL_FLOAT, GL_FALSE, * sizeof(GLfloat), (GLvoid*)( * sizeof(GLfloat)));
glEnableVertexAttribArray();//启用属性1.
  //顶点数组对象(Vertex Array Object, VAO)的好处就是,当配置顶点属性指针时,你只需要将上面的代码调用执行一次,之后再绘制物体的时候只需要绑定相应的VAO就行了。如下文循环中的绑定再解绑
glBindVertexArray(); // 解绑 VAO
// Game loop
while (!glfwWindowShouldClose(window))
{
// 检查事件,调用相应的回调函数,如下文的key_callback函数
glfwPollEvents(); // Render
// Clear the colorbuffer
glClearColor(0.2f, 0.3f, 0.3f, 1.0f);//渲染颜色到后台缓冲
glClear(GL_COLOR_BUFFER_BIT);//清除前台缓冲 // Draw the triangle
ourShader.Use();//启用着色器程序
glBindVertexArray(VAO);//每次循环都调用,绑定函数绑定VAO
glDrawArrays(GL_TRIANGLES, , );
glBindVertexArray();//解绑 // Swap the screen buffers
glfwSwapBuffers(window);
}
// Properly de-allocate all resources once they've outlived their purpose
glDeleteVertexArrays(, &VAO);
glDeleteBuffers(, &VBO);
// Terminate GLFW, clearing any resources allocated by GLFW.
glfwTerminate();
return ;
} // Is called whenever a key is pressed/released via GLFW
void key_callback(GLFWwindow* window, int key, int scancode, int action, int mode)
{
if (key == GLFW_KEY_ESCAPE && action == GLFW_PRESS)
glfwSetWindowShouldClose(window, GL_TRUE);
}

Shader.h    从文件中读取着色器代码,并编译。

#ifndef SHADER_H
#define SHADER_H #include <string>
#include <fstream>
#include <sstream>
#include <iostream> #include <GL/glew.h> class Shader
{
public:
GLuint Program;
// Constructor generates the shader on the fly
Shader(const GLchar* vertexPath, const GLchar* fragmentPath)
{
// 1. Retrieve the vertex/fragment source code from filePath
std::string vertexCode;
std::string fragmentCode;
std::ifstream vShaderFile;
std::ifstream fShaderFile;
// ensures ifstream objects can throw exceptions:
vShaderFile.exceptions(std::ifstream::badbit);
fShaderFile.exceptions(std::ifstream::badbit);
try
{
// Open files
vShaderFile.open(vertexPath);
fShaderFile.open(fragmentPath);
std::stringstream vShaderStream, fShaderStream;
// Read file's buffer contents into streams
vShaderStream << vShaderFile.rdbuf();
fShaderStream << fShaderFile.rdbuf();
// close file handlers
vShaderFile.close();
fShaderFile.close();
// Convert stream into string
vertexCode = vShaderStream.str();
fragmentCode = fShaderStream.str();
}
catch (std::ifstream::failure e)
{
std::cout << "ERROR::SHADER::FILE_NOT_SUCCESFULLY_READ" << std::endl;
}
const GLchar* vShaderCode = vertexCode.c_str();
const GLchar * fShaderCode = fragmentCode.c_str();
// 2. Compile shaders
GLuint vertex, fragment;
GLint success;
GLchar infoLog[];
// Vertex Shader
vertex = glCreateShader(GL_VERTEX_SHADER);//创建顶点着色器
glShaderSource(vertex, , &vShaderCode, NULL);//指定源代码
glCompileShader(vertex);//编译着色器
// Print compile errors if any
glGetShaderiv(vertex, GL_COMPILE_STATUS, &success);//查看是否编译成功
if (!success)
{
glGetShaderInfoLog(vertex, , NULL, infoLog);
std::cout << "ERROR::SHADER::VERTEX::COMPILATION_FAILED\n" << infoLog << std::endl;
}
// Fragment Shader
fragment = glCreateShader(GL_FRAGMENT_SHADER);//创建片段着色器
glShaderSource(fragment, , &fShaderCode, NULL);
glCompileShader(fragment);
// Print compile errors if any
glGetShaderiv(fragment, GL_COMPILE_STATUS, &success);
if (!success)
{
glGetShaderInfoLog(fragment, , NULL, infoLog);
std::cout << "ERROR::SHADER::FRAGMENT::COMPILATION_FAILED\n" << infoLog << std::endl;
}
// Shader Program
this->Program = glCreateProgram();//创建着色程序
glAttachShader(this->Program, vertex);//关联顶点着色器
glAttachShader(this->Program, fragment);//关联片段着色器
glLinkProgram(this->Program);//链接编译器
// Print linking errors if any
glGetProgramiv(this->Program, GL_LINK_STATUS, &success);
if (!success)
{
glGetProgramInfoLog(this->Program, , NULL, infoLog);
std::cout << "ERROR::SHADER::PROGRAM::LINKING_FAILED\n" << infoLog << std::endl;
}
// Delete the shaders as they're linked into our program now and no longer necessery
glDeleteShader(vertex);
glDeleteShader(fragment); }
// Uses the current shader
void Use()
{
glUseProgram(this->Program);
}
}; #endif

最后附上,运行图片

opengl入门篇一: 第一个三角形的更多相关文章

  1. opengl入门篇二: 索引缓冲对象EBO

    在绘制图形的过程中,顶点可能会重复.比如两个三角形组成了四边形,那么,必然有两个点是重复的.因此采用索引的方式,四个点即可描述四边形. // 四个顶点 GLfloat vertices[] = { / ...

  2. Google C++测试框架系列入门篇:第一章 介绍:为什么使用GTest?

    原始链接:Introduction: Why Google C++ Testing Framework? 词汇表 版本号:v_0.1 介绍:为什么使用GTest? GTest帮助你写更好的C++测试代 ...

  3. Sping Boot入门到实战之入门篇(一):Spring Boot简介

    该篇为Spring Boot入门到实战系列入门篇的第一篇.对Spring Boot做一个大致的介绍. 传统的基于Spring的Java Web应用,需要配置web.xml, applicationCo ...

  4. Google C++测试框架系列入门篇:第二章 开始一个新项目

    上一篇:Google C++测试框架系列入门篇:第一章 介绍:为什么使用GTest? 原始链接:Setting up a New Test Project 词汇表 版本号:v_0.1 开始一个新项目 ...

  5. 【OpenCV入门指南】第一篇 安装OpenCV

    http://blog.csdn.net/morewindows/article/details/8225783/ win10下vs2015配置Opencv3.1.0过程详解(转) http://ww ...

  6. 新注册第一帖----------------------乱码新手自学.net 之Linq 入门篇

    作为一个业余开发,断断续续学.net/c#也有不少日子了, 学习过程中,不断忘了学,学了忘,这让我很苦恼. 以前学习过程中,我总是在笔记本中记录下来知识要点,这么久下来,笔记本都写了四五本了. 然而, ...

  7. .NET Core实战项目之CMS 第一章 入门篇-开篇及总体规划

    作者:依乐祝 原文地址:https://www.cnblogs.com/yilezhu/p/9977862.html 写在前面 千呼万唤始出来,首先,请允许我长吸一口气!真没想到一份来自28岁老程序员 ...

  8. net core体系-web应用程序-4asp.net core2.0 项目实战(CMS)-第一章 入门篇-开篇及总体规划

    .NET Core实战项目之CMS 第一章 入门篇-开篇及总体规划   原文地址:https://www.cnblogs.com/yilezhu/p/9977862.html 写在前面 千呼万唤始出来 ...

  9. SaltStack入门到精通第一篇:安装SaltStack

    SaltStack入门到精通第一篇:安装SaltStack 作者:纳米龙  发布日期:2014-06-09 17:50:36   实际环境的设定: 系统环境: centos6 或centos5 实验机 ...

随机推荐

  1. shell 实用脚本2

    脚本功能 拷贝文件夹 及 子文件夹内文件  到 对应的 文件结构下 ,且拷贝前先进行备份 #!/bin/sh #create by lizr -- #脚本功能 #覆盖文件前先备份 cfsuffix=$ ...

  2. 安装haroopad

    安装haroopad 1)官网下载安装包 http://pad.haroopress.com/user.html 2)执行安装命令: sudo dpkg -i haroopad-v0.13.1-x64 ...

  3. Nginx的软件架构

    nginx原理架构图 Nginx是 master/worker 模型 一个master进程,可生成一个或多个worker进程,每个worker进程基于事件驱动机制响应客户端请求: 事件驱动机制:epo ...

  4. 自学Python5.7-面向对象三大基本特征_封装

    自学Python之路-Python基础+模块+面向对象自学Python之路-Python网络编程自学Python之路-Python并发编程+数据库+前端自学Python之路-django 自学Pyth ...

  5. 第三次java测验2

    package java3; public class Suiji { public long a=12345L;//定义long类型的a,b,c变量 public long c=12345L; pu ...

  6. Linux文件类型和文件相关命令

    文件类型 ll后可以看到文件详情: -:常规文件(内部类型是什么,用file命令) d:directory,目录文件 b:blobk device,块设备文件,支持以“block”为单位进行随机访问 ...

  7. C++ Primer 第 5 版 习题参考答案

    从 5 月初 - 8 月 16 日,每天基本都在啃 C++ 的语法.起初直接看C++ Primer 中文版(第 5 版),发现后边的章节看着很吃力.所以就转而看了清华大学郑莉老师和李超老师的视频C++ ...

  8. Nginx 0.8.x + PHP 5.2.13(FastCGI)搭建胜过Apache十倍的Web服务器

    [文章作者:张宴 本文版本:v6.3 最后修改:2010.07.26 转载请注明原文链接:http://blog.zyan.cc/nginx_php_v6/] 前言:本文是我撰写的关于搭建“Nginx ...

  9. 【传输管理③】Client集团间的传输(例:开发环境300→310,300→320)

    之前有提到: 每个环境可能有若干个Client(客户端/集团),且每个Client用途都不一样. 如下图所示,开发环境就有300,310和320三个Client. 假设开发人员在Client300中新 ...

  10. cdh本地源安装-自用

    yum 安装cm 参考官网 主机名 /etc/hosts hostnamectl set-hostname foo-1.data.com hostnamectl set-hostname foo-2. ...