【OpenGL进阶】01.使用Shader绘制三角形

2023-11-16

在前一个阶段的文章中,主要是使用OpenGL的固定管线来实现了一系列的操作,内容并不复杂,十分好理解,接下来的进阶系列中,我们将使用shader代码来实现一些效果。首先通过shader来实现一个三角形的绘制。

首先来看main.cs,创建窗口以及调用绘制指令都在这个脚本中实现:

#include "ggl.h"
#include "scene.h"
#include "Utils.h"


#pragma comment(lib,"opengl32.lib")
#pragma comment(lib,"glew32.lib")

unsigned char* LoadFileContent(const char* path, int& filesize)
{
	unsigned char* fileContent = nullptr;
	filesize = 0;
	FILE* pFile = fopen(path, "rb");
	if (pFile)
	{
		fseek(pFile, 0, SEEK_END);
		int nLen = ftell(pFile);
		if (nLen > 0)
		{
			rewind(pFile);
			fileContent = new unsigned char[nLen + 1];
			fread(fileContent, sizeof(unsigned char), nLen, pFile);
			fileContent[nLen] = '\0';
			filesize = nLen;
		}
		fclose(pFile);
	}
	return fileContent;
}

LRESULT CALLBACK GLWindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
	switch (msg)
	{
	case WM_CLOSE:
		PostQuitMessage(0);
		return 0;
	}
	return DefWindowProc(hwnd, msg, wParam, lParam);
}

INT WINAPI WinMain(HINSTANCE hinstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd)
{
	WNDCLASSEX wndclass;
	wndclass.cbClsExtra = 0;
	wndclass.cbSize = sizeof(WNDCLASSEX);
	wndclass.cbWndExtra = 0;
	wndclass.hbrBackground = NULL;
	wndclass.hCursor = LoadCursor(NULL, IDC_ARROW);
	wndclass.hIcon = NULL;
	wndclass.hIconSm = NULL;
	wndclass.hInstance = hinstance;
	wndclass.lpfnWndProc = GLWindowProc;
	wndclass.lpszClassName = L"GLWindow";
	wndclass.lpszMenuName = NULL;
	wndclass.style = CS_VREDRAW | CS_HREDRAW;
	ATOM atom = RegisterClassEx(&wndclass);
	if (!atom)
	{
		MessageBox(NULL, L"Notice", L"Error", MB_OK);
		return 0;
	}
	RECT rect;
	rect.left = 0;
	rect.right = 800;
	rect.top = 0;
	rect.bottom = 600;
	
	AdjustWindowRect(&rect, WS_OVERLAPPEDWINDOW, NULL);

	int windowWidth = rect.right - rect.left;
	int windowHeight = rect.bottom - rect.top;
	HWND hwnd = CreateWindowEx(NULL, L"GLWindow", L"OpenGL Window", WS_OVERLAPPEDWINDOW,
		100, 100, windowWidth, windowHeight,
		NULL, NULL, hinstance, NULL);
	
	HDC hdc = GetDC(hwnd);
	PIXELFORMATDESCRIPTOR pfd;
	memset(&pfd, 0, sizeof(PIXELFORMATDESCRIPTOR));
	pfd.nVersion = 1;
	pfd.nSize = sizeof(PIXELFORMATDESCRIPTOR);
	pfd.cColorBits = 32;
	pfd.cDepthBits = 24;
	pfd.cStencilBits = 8;
	pfd.iPixelType = PFD_TYPE_RGBA;
	pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER;
	int pixelFormat = ChoosePixelFormat(hdc, &pfd);
	SetPixelFormat(hdc, pixelFormat, &pfd);
	HGLRC rc = wglCreateContext(hdc);
	wglMakeCurrent(hdc, rc);

	glewInit();
	Init();
	SetViewPortSize(800.0f, 600.0f);

	ShowWindow(hwnd, SW_SHOW);
	UpdateWindow(hwnd); 

	MSG msg;
	while (true)
	{
		if (PeekMessage(&msg, NULL, NULL, NULL, PM_REMOVE))
		{
			if (msg.message == WM_QUIT)
			{
				break; 
			}
			TranslateMessage(&msg);
			DispatchMessage(&msg);
		}
		Draw();
		SwapBuffers(hdc);
	}
	return 0;
}

我们看到main.cs中include了三个.h文件,分别是ggl.h,scene.h,Utils.h。我们分别看下里边的内容:

ggl.h:

#pragma once
#include <windows.h>
#include "glew.h"
#include <stdio.h>
#include <math.h>
#include <string.h>
#include <sstream>
#include <vector>
#include <functional>
#include <map>
#include "Glm/glm.hpp"
#include "Glm/ext.hpp"

里边包含了我们会使用到的头文件。

scene.h:

#pragma once
#include "ggl.h"
void Init();
void SetViewPortSize(float width, float height);
void Draw();

scene.cpp:

#include "scene.h"
#include "ggl.h"
#include "Utils.h"

GLuint vbo;
GLuint program;
GLint positionLocation, modelMatrixLocation, viewMatrixLocation, projectionMatrixLocation;
glm::mat4 modelMatrix, viewMatrix, projectionMatrix;

void Init()
{
	float data[] = {
		-0.2f,-0.2f,-0.6f,1.0f,
		0.2f,-0.2f,-0.6f,1.0f,
		0.0f,0.2f,-0.6f,1.0f
	};
	glGenBuffers(1, &vbo);
	glBindBuffer(GL_ARRAY_BUFFER, vbo);
	glBufferData(GL_ARRAY_BUFFER, sizeof(float) * 12, data, GL_STATIC_DRAW);
	glBindBuffer(GL_ARRAY_BUFFER, 0);
	int fileSize = 0;
	//读取shader代码
	unsigned char* shaderCode = LoadFileContent("Res/test.vs", fileSize);
	GLuint vsShader = CompileShader(GL_VERTEX_SHADER, (char*)shaderCode);
	delete shaderCode;

	shaderCode = LoadFileContent("Res/test.fs", fileSize);
	GLuint fsShader = CompileShader(GL_FRAGMENT_SHADER, (char*)shaderCode);
	delete shaderCode;
	
	program = CreateProgram(vsShader, fsShader);
	glDeleteShader(vsShader);
	glDeleteShader(fsShader);
	//获取shader中的变量
	positionLocation = glGetAttribLocation(program, "position");
	modelMatrixLocation = glGetUniformLocation(program, "ModelMatrix");
	viewMatrixLocation = glGetUniformLocation(program, "ViewMatrix");
	projectionMatrixLocation = glGetUniformLocation(program, "ProjectionMatrix");
}

void SetViewPortSize(float width, float height)
{
	projectionMatrix = glm::perspective(60.0f, width / height, 0.1f, 1000.0f);
}

void Draw()
{
	glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

	glUseProgram(program);
	glUniformMatrix4fv(modelMatrixLocation, 1, GL_FALSE, glm::value_ptr(modelMatrix));
	glUniformMatrix4fv(viewMatrixLocation, 1, GL_FALSE, glm::value_ptr(viewMatrix));
	glUniformMatrix4fv(projectionMatrixLocation, 1, GL_FALSE, glm::value_ptr(projectionMatrix));
	
	glBindBuffer(GL_ARRAY_BUFFER, vbo);
	glEnableVertexAttribArray(positionLocation);
	glVertexAttribPointer(positionLocation, 4, GL_FLOAT, GL_FALSE, sizeof(float) * 4, 0);
	glDrawArrays(GL_TRIANGLES, 0, 3);
	glBindBuffer(GL_ARRAY_BUFFER, 0);
	glUseProgram(0);


}

Unitls.h主要是编译shader已经创建程序的功能。

#pragma once
#include "ggl.h"
unsigned char* LoadFileContent(const char* path, int& filesize);

GLuint CompileShader(GLenum shaderType, const char* shaderCode);

GLuint CreateProgram(GLuint vsShader, GLuint fsShader);

Utils.cpp:

#include "Utils.h"

GLuint CompileShader(GLenum shaderType, const char* shaderCode)
{
	GLuint shader = glCreateShader(shaderType);
	glShaderSource(shader, 1, &shaderCode, nullptr);
	glCompileShader(shader);
	GLint compileResult = GL_TRUE;
	glGetShaderiv(shader, GL_COMPILE_STATUS, &compileResult);
	
	if (compileResult==GL_FALSE)
	{
		char szLog[1024] = { 0 };
		GLsizei logLen = 0;
		glGetShaderInfoLog(shader, 1024, &logLen, szLog);
		printf("Complie Shader fail error log: %s \nshader code: \n%s\n", szLog, shaderCode);
		glDeleteShader(shader);
		shader = 0;
	}
	return shader;
}

GLuint CreateProgram(GLuint vsShader, GLuint fsShader)
{
	GLuint program = glCreateProgram();
	glAttachShader(program, vsShader);
	glAttachShader(program, fsShader);
	glLinkProgram(program);
	glDetachShader(program, vsShader);
	glDetachShader(program, fsShader);
	GLint nResult;
	glGetProgramiv(program, GL_LINK_STATUS, &nResult);
	if (nResult == GL_FALSE)
	{
		char log[1024] = { 0 };
		GLsizei writed = 0;
		glGetProgramInfoLog(program, 1024, &writed, log);
		printf("create gpu program fail,link error: %s\n", log);
		glDeleteProgram(program);
		program = 0;
	}
	return program;
}

最后附上顶点和片元着色器,即test.vs和test.fs:

attribute vec4 position;
uniform mat4 ModelMatrix;
uniform mat4 ViewMatrix;
uniform mat4 ProjectionMatrix;

void main()
{
    gl_Position = ProjectionMatrix*ViewMatrix*ModelMatrix*position;
}
#ifdef GL_ES
precision mediump float;
#endif
void main()
{
    gl_FragColor = vec4(1.0,1.0,1.0,1.0);
}

最后来看下效果吧:

今天就写到这里了~

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

【OpenGL进阶】01.使用Shader绘制三角形 的相关文章

  • 在 Ubuntu 中与未编译的着色器链接

    我需要加载 glsl 来绘制一些东西 我的环境是Ubuntu 13 04 因此它不存在GLuint InitShader GLuint GLuint 这是我的对象创建 预链接步骤和链接的配置 不幸的是 它仍然出现错误 该错误与未编译的着色器
  • OpenGL:顶点越多,性能越慢

    我正在开发一个程序的一部分 其中给定 xyz 坐标集合 制作 3D 模型 我已经完成了这张图片所需的所有功能 即平移 旋转 缩放 但是给出的 xyz 坐标越多 程序运行速度就越慢 我的程序在处理 29 000 个坐标时运行得非常流畅 但当我
  • 为什么 OpenGL 有远裁剪平面,以及使用什么惯用法来处理这个问题?

    我一直在学习 OpenGL 持续困扰我的一个话题是远裁剪平面 虽然我可以理解近剪裁平面和侧剪裁平面 它们永远不会产生任何实际效果 因为它们之外的对象无论如何都不会被渲染 背后的推理 但远剪裁平面似乎只是一个烦恼 由于 OpenGL 背后的人
  • 如何在 SceneKit 中以编程方式将 png 纹理包裹在立方体周围

    我是 SceneKit 的新手 试图让一些基本的东西工作 但到目前为止还没有取得多大成功 由于某种原因 当我尝试将 png 纹理应用于 CNBox 时 我最终除了黑色之外什么也没有 这是我在 viewDidLoad 中的简单代码片段 let
  • 为什么我的 CAOpenGLLayer 更新速度比之前的 NSOpenGLView 慢?

    我有一个在 Mac OS X 上渲染 OpenGL 内容的应用程序 最初它渲染到 NSOpenGLView 然后我将其更改为渲染到 CAOpenGLLayer 子类 当我这样做时 我看到了巨大的性能损失 帧速率减半 鼠标响应能力降低 卡顿
  • 按像素值偏移 gl_Position 或 gl_Vertex

    我的属性包含像素值 我想用这个属性值来偏移我的 gl vertex 问题是我的 gl vertex 以世界单位为单位 而 offset attribute 以像素为单位 如果我将屏幕尺寸作为统一发送 然后将像素转换为 1 到 1 值 并将其
  • OpenGL - 自动生成 glDrawArrays 的索引/步幅参数

    我正在渲染一个包含大量数据点 gt 1M 的网格结构 我的数据结构如图所示 所以我的索引缓冲区的内容看起来像这样0 100 1 101 2 102 3 103 我对索引缓冲区的巨大尺寸有点恼火 我需要它来定义我的三角形带 是否有可能告诉 O
  • 实例着色器矩阵的设置

    我想绘制实例立方体 我可以打电话GL DrawArraysInstanced PrimitiveType Triangles 0 36 2 成功地 我的问题是所有立方体都绘制在相同的位置和相同的旋转 我如何为每个立方体单独更改它 要创建不同
  • matplotlib:渲染到缓冲区/访问像素数据

    我想使用 matplotlib 生成的图作为 OpenGL 中的纹理 到目前为止 我遇到的 matplotlib 的 OpenGL 后端要么不成熟 要么已经停止使用 所以我想避免使用它们 我当前的方法是将图形保存到临时 png 文件中 并从
  • 如何在OpenGL中像这样绘制连接的带状线

    我想用以下方式绘制一系列连接线 GL LINE STRIP 我尝试过自己编写代码 但没有得到想要的结果 所以我来到这里 帮助我找出我错在哪里 这里我只给出我的draw 函数 glBegin GL LINE STRIP glVertex2f
  • 如何在片段着色器中将 gl_FragCoord 转换为世界空间点?

    我的理解是 如果您有视图投影矩阵 屏幕宽度和屏幕高度的逆矩阵 则可以将 gl FragCoord 转换为片段着色器中世界坐标中的点 首先 你转换gl FragCoord x and gl FragCoord y通过分别除以宽度和高度 然后将
  • 使用普通画布/文本输出更新LayeredWindow

    有没有一种方法可以使用画布在表单上绘图 然后使用 updatelayeredwindow 这样表单就不可见 但文本可见 就像只显示文本的半透明表单一样 如果没有 那么有没有办法只用画布 opengl directx 制作某种半透明形式 我想
  • 为贝塞尔曲线中的每个点绘制切线

    我设法绘制了一条贝塞尔曲线 如下所示 glColor3f 0 1 0 glBegin GL LINE STRIP for int i 3 i lt nPt i 3 glColor3f 0 0 0 for float k 0 k lt NLI
  • 之前对 GL.Color3 的调用使我的纹理使用了错误的颜色

    制作 2D OpenGL 游戏 渲染帧时 我需要首先绘制一些计算的四边形几何体 然后绘制一些纹理精灵 当我的渲染方法主体仅绘制精灵时 一切正常 但是 当我尝试在精灵之前绘制几何四边形时 精灵的纹理会更改为之前使用的最后一个 GL Color
  • SDL 程序中颜色关闭

    我目前正在开发一个非常简单的游戏 使用纯 C 方法和 SDL 及其官方额外库 如 SDL image 和 OpenGL 现在 虽然我遇到了一些障碍 但我不知道为什么要这样做 绘制时颜色全部关闭 我目前在 Mac 上运行该程序 但如果我没记错
  • glTranslatef 不在 glBegin .. glEnd 中工作

    我正在尝试并排绘制不同颜色的两个方块 我的问题是我无法让 glTranslatef 将第二个方块向右移动 第二个方块只是绘制在第一个方块上 void display void glClear GL COLOR BUFFER BIT glMa
  • GLSL memoryBarrierShared() 有用吗?

    我想知道 memoryBarrierShared 的用处 事实上 当我查找屏障功能的文档时 我读到 对于计算着色器中任何给定的静态屏障实例 单个工作组内的所有调用都必须进入该实例 然后才能允许任何调用继续超出该实例 这确保了在给定的屏障静态
  • 如何连接重叠的圆圈?

    我想在视觉上连接两个重叠的圆圈 以便 becomes 我已经有部分圆的方法 但现在我需要知道每个圆的重叠角度有多大 但我不知道该怎么做 有人有主意吗 Phi ArcTan Sqrt 4 R 2 d 2 d HTH Edit 对于两个不同的半
  • 光照不适用于 gluSphere

    这是一个简单的问题 我有点羞于寻求帮助 我正在对 gluSphere 进行简单调用来渲染球体 但是 即使我很确定我正确添加了法线和照明 它也无法正确照亮 但是 如果我添加纹理 模型会正常点亮 但它似乎总是平滑的 并且我无法将其更改为平面 这
  • 并排显示图像的一半 - OpenGL

    我为两个图像创建了两个纹理 现在我想在opengl中按图像2的左侧部分 完整的图像1 图像2的右侧部分的顺序显示该纹理 我已经做了如下 Image1 显示在 opengl 屏幕的中央 但屏幕的左右部分不正确 应分别显示 image2 的左侧

随机推荐

  • redis概述-1

    视频链接 尚硅谷 Redis 6 入门到精通 超详细 教程 哔哩哔哩 bilibili 早期架构 随着web2 0 手机端和pc端的请求增加 应用服务器会有cpu及内存压力 数据服务器有IO压力 针对应用服务器 采用分布式 负载均衡的方式进
  • ILRuntime Unity热更新

    在新的项目中 使用到了ILRuntime的热更新方式 不同于XLua等 这种方式的热更新是由纯C 实现的 所以就不需要客户端懂Lua的代码 更详细的介绍可以看官方的文档 官方的介绍及文档为 http ourpalm github io IL
  • vcpkg安装和使用--学习入门

    前言 vcpkg是一个C 的包管理器 包管理器是专门管理一些代码库的 比如一些大佬们开源的一些NB的框架 我们可以用vcpkg将他们放到自己的项目中 然后就可以直接用了 我用的win10 vs2019 1 安装 1 先git clone下载
  • openwrt中计划任务的设置

    寝室的供网规则为周一到周五零点断网 六点开网 双休日通宵供网 故设置一套计划任务提高路由器使用效率 crontab命令常见于Unix和类Unix的操作系统之中 用于设置周期性被执行的指令 操作符号 在一个区域里填写多个数值的方法 逗号 分开
  • AcWing基础课题集汇总

    本篇博文是笔者归纳汇总的AcWing基础课题集 方便读者后期复盘巩固 PS 本篇文章只给出完整的算法实现 并没有讲解具体的算法思路 如果想看算法思路 可以阅读笔者往期写过的文章 或许会有 也可以移步AcWing官网看详情 本篇文章的特点 每
  • Qt应用开发(基础篇)——时间类 QDateTime、QDate、QTime

    一 前言 时间类QDateTime QDate QTime QTimeZone保存了Qt的时间 日期 时区信息 常用的时间类部件都会用到这些数据结构 常用概念有年 月 日 时 分 秒 毫秒和时区 时间和时区就关系到时间戳和UTC的概念 UT
  • Debian(Linux)系统Samba安装和配置

    samba安装 root用户下直接使用以下命令 apt get install samba 若是普通用户下使用以下命令 sudo apt get install samba samba配置 samba的配置文件在 etc samba 路径下
  • 1-2动态图

    文章目录 动态图 一 环境配置 二 基本用法 三 使用python的控制流 四 构建更加灵活的网络 控制流 五 构建更加灵活的网络 共享权重 The End 动态图 在这种模式下 每次执行一个运算 可以立即得到结果 而不是事先定义好网络结构
  • 基本数据类型的包装类

    本人之所以把包装类作为单独一篇博文来写 主要是因为这里知识比较冗杂 为了帮助大家比较好的理解深层次的东西而不是做一个搬砖的这里我有必要单开一篇博文来了解下 首先我们来分析一下基本数据类型和包装类 包装类是对象 拥有方法和字段 对象的调用都是
  • Python异常处理总结

    Python异常处理总结 这篇文章主要介绍了Python异常处理总结 需要的朋友可以参考下 本文较为详细的罗列了Python常见的异常处理 供大家参考 具体如下 1 抛出异常和自定义异常 Python用异常对象 exception obje
  • 《Java基础——制表符》

    Java基础 制表符 规则 若前面输出内容不为8的倍数 则通过空格补全 不足八位 补全八位 例一 不足八位 System out println 123456 t 空格补位 编译结果 123456 空格补位 例二 大于等于八位 System
  • 对高精度PWM(HRPWM)的理解

    传统PWM的精度 假定CPU工作频率为100MHz PWM模块的计数频率也一样 则计数周期为10ns 假设PWM的开关频率为1MHz 使用向上计数模式 那么 计数周期PRD等于100 此时 比较值只能在0 100里面选 占空比的精度只有1
  • mysql语法之update

    Update 语句 1 作用 Update 语句用于修改表中的数据 语法 UPDATE 表名称 SET 列名称 新值 WHERE 列名称 某值 1 建表语句 create table table1 idd varchar 10 val va
  • Python自学第十一天——Bug

    作为新手自学Python的第十一天 技术低微 希望可以通过这种方式督促自己学习 个人学习环境 python3 9 PyCharm 2021 3 2 Community Edition 本文仅做Bug基本知识梳理和简单解决方法简述 具体Bug
  • 解释二叉树深度和高度

    今天小伙伴在群里问到 面试官问这个问题 我第一印象 这不是一回事吗 去查了查 竟然还真有区别 所以在此记录一下 高度和深度是相反的表示 深度是从上到下数的 而高度是从下往上数 我们先来看看高度和深度的定义 某节点的深度是指从根节点到该节点的
  • vmware中虚拟机网络使用NAT模式,使外部主机可以连接

    将虚拟机网络类型配置成 注意 如果不知道什么原因无法访问网络 关闭所有虚拟机 点击还原默认设置 重置网络 vmware点击 编辑 gt 虚拟网络编辑器 点击NAT设置可以查看NAT网络的网关 点击DHCP设置 应该不需要 因为我用的是静态I
  • 【独家源码】ssm科普网站14o1y计算机毕业设计问题的解决方案与方法

    本项目包含程序 源码 数据库 LW 调试部署环境 文末可获取一份本项目的java源码和数据库参考 系统的选题背景和意义 选题背景 科学普及是推动科学知识传播和科学素养提升的重要途径 随着互联网的快速发展 科普网站成为了人们获取科学知识和信息
  • Mat使用笔记

    一 基本操作 1 1 创建 cv Mat初识和它的六种创建方法 cv Mat matDes nHEIGHT nWID CV 8UC1 cv Scalar 0 创建 row 高 col 宽 cv Mat matDes cv Mat zeros
  • 【pytorch优化器】Adam优化算法详解

    转载自 https blog csdn net weixin 39228381 article details 108548413 仅作学习记录 文章目录 一 说明 二 Adam原理 1 梯度滑动平均 2 偏差纠正 3 Adam计算过程 三
  • 【OpenGL进阶】01.使用Shader绘制三角形

    在前一个阶段的文章中 主要是使用OpenGL的固定管线来实现了一系列的操作 内容并不复杂 十分好理解 接下来的进阶系列中 我们将使用shader代码来实现一些效果 首先通过shader来实现一个三角形的绘制 首先来看main cs 创建窗口