OpenGL —— 2.1、绘制第一个三角形(附源码,glfw+glad)

news2024/11/25 7:00:46
源码效果

在这里插入图片描述

C++源码

     vertexShader.glsl

#version 330 core

layout(location = 0) in vec3 aPos;
void main()
{
	gl_Position = vec4(aPos.x, aPos.y, aPos.z, 1.0);
};


     fragmentShader.glsl

#version 330 core

out vec4 FragColor;
void main()
{
	FragColor = vec4(1.0f, 1.0f, 1.0f, 1.0f);
};


     main.c

#include <Windows.h>
#include <iostream>
#include <string>
#include <fstream>
#include <sstream>

#include "glad/glad.h"
#include "GLFW/glfw3.h"

unsigned int VBO = 0, VAO = 0;
unsigned int shaderProgram = 0;		// shader的链接程序

void _Render()
{
	// 使用程序
	glUseProgram(shaderProgram);

	// 绑定VAO
	glBindVertexArray(VAO);

	// 绘制三角形
	glDrawArrays(GL_TRIANGLES, 0, 3);

	// 关闭使用程序
	glUseProgram(0);
}

void _initModel()
{
	float vertices[]
	{
		-0.5f,-0.5f,0.0f,
		0.5f,-0.5f,0.0f,
		0.0f,0.5f,0.0f
	};


	/****************************************************/	// VAO
	// 创建VAO
	glGenVertexArrays(1, &VAO);

	// 绑定指定的顶点数组对象(Vertex Array Object, VAO)
	glBindVertexArray(VAO);
	/****************************************************/


	/****************************************************/	// VBO
	// 生成缓冲区对象
	glGenBuffers(1, &VBO);

	// 绑定命名缓冲区对象
	glBindBuffer(GL_ARRAY_BUFFER, VBO);

	// 缓冲对象(VBO,IBO 等)分配空间并存储数据
	glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);;

	// 指定顶点属性在顶点缓冲对象中的布局,并将其与顶点着色器中的顶点属性进行关联(参数1:第0个layout)
	glVertexAttribPointer(0	, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void *)0);

	// 激活锚点(参数:第0个layout)
	glEnableVertexAttribArray(0);

	// VBO解绑VAO
	glBindVertexArray(0);
	/****************************************************/
}

std::string ReadGlslContext(const char *sPath)
{
	std::string strContext;
	if (!sPath) { return strContext; }

	std::ifstream sFile;
	sFile.open(sPath);
	if (sFile.is_open())
	{
		std::stringstream sStream;
		sStream << sFile.rdbuf();
		strContext = sStream.str();
	}
	return strContext;
}

bool _initShader(const char *_vertexPath, const char *_fragPath)
{
	char infoLog[512] = { 0 };
	int successFlag = 0;

	/*********************************************************/	// vertex编译
	std::string vertexContext = ReadGlslContext(_vertexPath); if (vertexContext.empty()) { return false; }
	const char *cVertexContext = vertexContext.c_str();

	// 创建顶点着色器对象
	unsigned int iVertexID = glCreateShader(GL_VERTEX_SHADER);

	// 为顶点着色器指定源码(参数2:传过去几个)
	glShaderSource(iVertexID, 1, &cVertexContext, nullptr);

	// 编译顶点着色器源码
	glCompileShader(iVertexID);

	// 查看编译顶点着色器源码结果
	glGetShaderiv(iVertexID, GL_COMPILE_STATUS, &successFlag);
	if (!successFlag)	// 编译失败
	{
		// 获取编译失败原因
		glGetShaderInfoLog(iVertexID, 512, nullptr, infoLog);
		std::cout << "glGetShaderiv GL_VERTEX_SHADER" << iVertexID << " fail:" << infoLog << std::endl; return false;
	}
	cVertexContext = nullptr;
	/*********************************************************/


	/*********************************************************/	// fragment编译
	std::string fragmentContext = ReadGlslContext(_fragPath); if (fragmentContext.empty()) { return false; }
	const char *cFragmentContext = fragmentContext.c_str();

	// 创建顶点着色器对象
	unsigned int iFragmentID = glCreateShader(GL_FRAGMENT_SHADER);

	// 为顶点着色器指定源码(参数2:传过去几个)
	glShaderSource(iFragmentID, 1, &cFragmentContext, nullptr);

	// 编译顶点着色器源码
	glCompileShader(iFragmentID);

	// 查看编译顶点着色器源码结果
	glGetShaderiv(iFragmentID, GL_COMPILE_STATUS, &successFlag);
	if (!successFlag)	// 编译失败
	{
		// 获取编译失败原因
		glGetShaderInfoLog(iFragmentID, 512, nullptr, infoLog);
		std::cout << "glGetShaderiv GL_FRAGMENT_SHADER" << iFragmentID << " fail:" << infoLog << std::endl; return false;
	}
	cFragmentContext = nullptr;
	/*********************************************************/


	/*********************************************************/	// 链接
	// 创建一个空的着色器程序对象
	shaderProgram = glCreateProgram();

	// 将着色器对象附加到着色器程序对象上
	glAttachShader(shaderProgram, iVertexID);
	glAttachShader(shaderProgram, iFragmentID);

	// 进行链接程序对象
	glLinkProgram(shaderProgram);

	// 查看链接状态
	glGetProgramiv(shaderProgram, GL_LINK_STATUS, &successFlag);
	if (!successFlag)	// 链接失败
	{
		// 获取链接失败原因
		glGetProgramInfoLog(shaderProgram, 512, nullptr, infoLog);
		std::cout << "glGetProgramiv " << shaderProgram << " fail:" << infoLog << std::endl; return false;
	}
	/*********************************************************/


	/* 在链接完成后,将编译shader相关删除。仅留下链接ID */
	glDeleteShader(iVertexID);
	glDeleteShader(iFragmentID);
	return true;
}

void _GLFWframebuffersizefun(GLFWwindow* window, int width, int height)
{
	// 在窗口中定义一个像素矩形,最终的图形将映射到个矩形中
	glViewport(0, 0, width, height);
}

void processInput(GLFWwindow *window)
{
	if (window)
	{
		// 获取窗口按键是否ESC
		if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS)
		{
			// 设置窗口关闭标志
			glfwSetWindowShouldClose(window, true);
		}
	}
	window = nullptr;
}

int main()
{
	// 初始化glfw上下文
	if (glfwInit() == GLFW_FALSE) { std::cout << "glfwInit fail!\n"; return -1; }
	glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);					// 3.3版本
	glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
	glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);	// 使用OpenGL核心模式

	// 创建OpenGL窗体
	GLFWwindow *window = glfwCreateWindow(800, 600, "opengl Core", nullptr, nullptr);
	if (!window) { std::cout << "glfwCreateWindow fail!\n"; return -1; }

	// 当前OpenGL上下文绑定窗口
	glfwMakeContextCurrent(window);

	// 加载所有OpenGL函数指针
	if (GL_FALSE == gladLoadGLLoader((GLADloadproc)glfwGetProcAddress))
	{std::cout << "gladLoadGLLoader fail!\n"; return -1;}

	// 在窗口中定义一个像素矩形,最终的图形将映射到个矩形中
	glViewport(0, 0, 800, 600);

	// 窗口大小调整回调
	glfwSetFramebufferSizeCallback(window, _GLFWframebuffersizefun);

	// 初始化VAO/VBO
	_initModel();

	// 初始化shader
	if (!_initShader("vertexShader.glsl", "fragmentShader.glsl"))
	{std::cout << "_initShader fail!\n"; system("pause"); return -1;}
	
	// 窗口标志是否是关闭
	while (!glfwWindowShouldClose(window))
	{
		// 输入按键处理
		processInput(window);
		
		// 使用红,绿,蓝以及alpha值来清除颜色缓冲区
		glClearColor(0.328125f, 0.35156f, 0.82421f, 1.0f);

		// 将从窗口中清除最后一次所绘制的图形
		/*
			GL_COLOR_BUFFER_BIT:    当前可写的颜色缓冲
			GL_DEPTH_BUFFER_BIT:    深度缓冲
			GL_ACCUM_BUFFER_BIT:	累积缓冲
  			GL_STENCIL_BUFFER_BIT:	模板缓冲
		*/
		glClear(GL_COLOR_BUFFER_BIT);

		_Render();

		// 双缓冲技术,使用OpenGL或OpenGL ES进行渲染
		glfwSwapBuffers(window);

		// glfw事件循环
		glfwPollEvents();

		// 睡眠10ms,防止造成GPU疯狂消耗。实际具体调整
		Sleep(10);
	}

	// 释放资源,终止GLFW库
	glfwTerminate();

	//system("pause");
	return 0;
}

关注

Wx GZH:码农总动员

笔者 - jxd

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/912920.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

基于transformer预测双色球(代码+数据+一键可运行)

对AI炒股感兴趣的小伙伴可加WX群&#xff1a; 1、引言 在这期内容中&#xff0c;我们将暂时将股票搁置一旁&#xff0c;转而探索人工智能技术如何应用于另一个有趣的领域&#xff1a;预测未来双色球号码。 2、AI与双色球预测的关系 在彩票预测中&#xff0c;AI充当着数据分析…

QRadioButton

QRadioButton API使用方式 QRadioButton是Qt提供的单选按钮, 一般都是以组的方式来使用(多个按钮中同时只能选中其中一个) 如果单选按钮被选中, 再次点击这个按钮选中状态是不能被取消的 API // 构造函数 /* 参数:- text: 按钮上显示的标题- parent: 按钮的父对象 */ QRadio…

SpringBoot3.x原生镜像-Native Image实践

前提 之前曾经写过一篇《SpringBoot3.x 原生镜像-Native Image 尝鲜》&#xff0c;当时SpringBoot处于3.0.0-M5版本&#xff0c;功能尚未稳定。这次会基于SpringBoot当前最新的稳定版本3.1.2详细分析Native Image的实践过程。系统或者软件版本清单如下&#xff1a; 组件版本备注…

【已解决】Linux中启动docker 出现 ‘ Failed to start docker.service: Unit not found. ’ 错误

启动docker 出现 ‘ Failed to start docker.service: Unit not found. ’ 错误 这是因为缺少 rhel-push-plugin.socket 单元&#xff0c;该单元是rhel-push-plugin软件包的一部分。所以我们执行以下指令就可以成功解决&#xff1a; curl -sSL https://get.docker.com/ | sh 执…

学习平台助力职场发展与提升

近年来&#xff0c;随着互联网技术的发展&#xff0c;学习平台逐渐成为了职场发展和提升的必备工具。学习平台通过提供丰富的课程内容、灵活的学习时间和个性化的学习路径&#xff0c;帮助职场人士更好地提升自己的技能和知识储备&#xff0c;为职场发展打下坚实的基础。 学习…

mysql 8.0 窗口函数 之 分布函数 与 sql server (2017以后支持) 分布函数 一样

mysql 分布函数 percent_rank&#xff08;&#xff09; &#xff1a;等级值 百分比cume_dist() &#xff1a;累积分布值 percent_rank&#xff08;&#xff09; 计算方式 (rank-1)/(rows-1)&#xff0c; 其中 rank 的值为使用RANK()函数产生的序号&#xff0c;rows 的值为当前…

并查集及其简单应用

文章目录 一.并查集二.并查集的实现三.并查集的基本应用 一.并查集 并查集的逻辑结构:由多颗不相连通的多叉树构成的森林(一个这样的多叉树就是森林的一个连通分量) 并查集的元素(树节点)用0~9的整数表示,并查集可以表示如下: 并查集的物理存储结构:并查集一般采用顺序结构实…

Springboot 项目配置Swagger2

1. 加入swagger 依赖 springboot 项目的 pom.xml 中添加下列依赖&#xff1a; <dependency><groupId>io.springfox</groupId><artifactId>springfox-swagger2</artifactId><version>2.9.2</version> </dependency> <depe…

Postgresql部署及简单操作

目录 1、介绍 2、什么是PostgreSQL 3、PostgreSQL 的特点 4、数据库定为 5、环境准备 6、编译安装 6.1 安装依赖包 6.2 下载安装包 6.3 创建用户 6.4 创建 postgresql数据目录并授权 6.5 上传压缩包并解压 6.6 编译postgresql源码 6.7 配置环境变量 6.8 初始化数…

使用 wxPython 和 pymupdf进行 PDF 加密

PDF 文件是一种常见的文档格式&#xff0c;但有时候我们希望对敏感信息进行保护&#xff0c;以防止未经授权的访问。在本文中&#xff0c;我们将使用 Python 和 wxPython 库创建一个简单的图形用户界面&#xff08;GUI&#xff09;应用程序&#xff0c;用于对 PDF 文件进行加密…

2023年你会选择哪种编程语言?

2023年你会选择哪种编程语言&#xff1f; 关于编程语言的个人见解。 KOTLIN&#xff1a;由于其先进的多平台能力&#xff0c;未来5年内它很可能成为开发任何类型的客户端应用&#xff08;移动端、桌面端或Web端&#xff09;的首选编程语言。他们正在为iOS和WebAssembly开发的…

power designer 反向工程过程已中断,原因是某些字符无法通过ANSI-->UTF-16转换进行映射

起因&#xff1a;sqlserver导入sql时报错&#xff0c;一查询是power designer 反向工程过程已中断&#xff0c;原因是。某些字符无法通过ANSI-->UTF-16转换进行映射&#xff08;会导致数据丢失&#xff09; 解决办法&#xff1a; 导入成功

【Vue】全家桶之vue-Router

文章目录 概述后端路由前端路由Vue Router安装 vue-router 的常见用法路由懒加载路由重定向嵌套路由动态路由匹配 声明式导航 & 编程式导航声明式导航编程式导航 导航守卫全局前置守卫守卫方法的 3 个形参next 函数的 3 种调用方式控制后台主页的访问权限 路由的两种工作模…

骨传导耳机音质好吗?骨传导耳机音质和普通耳机对比哪个好?

相信不少朋友还是比较排斥骨传导耳机的&#xff0c;并不是说骨传导技术不成熟&#xff0c;而是骨传导对技术的要求实在太高了&#xff0c;尤其是对音质以及防漏音的考验。作为一款新兴产品&#xff0c;骨传导耳机打破了传统的传音模式&#xff0c;由空气传导&#xff0c;转变为…

element上传图片,调取接口传值,参数FormData为空

需求 输入完reason&#xff0c;选完文件后&#xff0c;点击提交按钮后 调取接口。 遇到的问题 上传文件orderFile 字段一直为空 打印了发现&#xff0c;上传文件也是有值得。但是传到接口中就为空 原因 json里边不能放file&#xff0c;但是formData里可以放 file 也可以放…

每个世界500强公司,都遇到过增长瓶颈

在《财富》100强公司的增长历程分析中&#xff0c;最容易得出的结论是大部分大型企业都曾经历过一段停滞期。这些公司的规模大小各不相同&#xff0c;尽管绝大部分停滞都发生在收入10亿—100亿美元之间的公司内&#xff0c;但任何规模的企业都有可能出现增长停滞。这是因为&…

C++学习第十五天----循环和文本输入

昨天说到使用cin进行键盘输入的一些弊端&#xff0c;那么怎么解决呢&#xff1f; 1.使用cin.get&#xff08;char&#xff09;进行补救 使用下面这句代码替换掉cin >> ch;,这样就会回显空格&#xff1b; cin.get(ch);//读取输入中的下一个字符&#xff08;即使它是空格&…

LeetCode——二叉树片(七)

刷题顺序及思路来源于代码随想录&#xff0c;网站地址&#xff1a;https://programmercarl.com 目录 617. 合并二叉树 700. 二叉搜索树中的搜索 98. 验证二叉搜索树 530. 二叉搜索树的最小绝对差 501. 二叉搜索树中的众数 617. 合并二叉树 给你两棵二叉树&#xff1a; …

leetcode 309. 买卖股票的最佳时机含冷冻期

2023.8.22 本题是买卖股票系列 冷冻期。 由于引入了冷冻期&#xff0c;并且这个冷冻期是在卖出股票才会出现&#xff0c;因此我dp数组设置了四种状态&#xff1a; 状态一&#xff1a;持有股票。状态二&#xff1a;不持有股票&#xff1a; 之前就卖了&#xff0c;所以今天不处…

小区新冠疫情管理系统的设计与实现/基于springboot的小区疫情管理系统

摘要 采用更加便于维护和使用的Java语言&#xff0c;其可拓展性高且更富于表现力&#xff0c;基于mysql数据库、Springboot框架开发的小区新冠疫情管理系统&#xff0c;方便用户查看物资信息、疫苗信息。通过Eclipse来进行网页编程&#xff0c;其方便易用、移植适用性广、更加安…