细分曲面着色器

细分曲面分成了三部分,
首先是细分曲面控制着色器,这个着色器主要是设置细分因子,也就是细分的程度。
然后是固定的细分曲面引擎,将接收到的贴片(patch)细分成点、线或者三角形
最后是细分曲面评估着色器,这里进行细分算法的编写,并且输出

自己封装的shader类(改进中…)

shader.h

#pragma once
#include "sb7.h"
#include <string>
#include <fstream>
#include <sstream>
#include <iostream>
#include <exception>
class Shader
{public:Shader();Shader(const std::string vertexPath, const std::string fragmentPath);Shader(const std::string vertexPath, const std::string tescPath, const std::string tesePath, const std::string fragmentPath);//设置顶点着色器void setVertexShder(const std::string vertexPath);//设置曲面细分控制着色器void setTescShader(const std::string tescPath);//设置曲面细分评估着色器void setTeseShader(const std::string tesePath);//设置片段着色器void setFragmentShader(const std::string fragmentPath);//program对象使用void use();
private:GLuint program;//源代码std::string shaderString;const char* shaderSource;//用于读取shader文件std::ifstream shaderFile;//转换源码std::stringstream shaderSStream;private://查错程序,是否有编译错误void checkCompileErrors(unsigned int ID, std::string type);
};

Shader.cpp

#include "Shader.h"Shader::Shader(){}Shader::Shader(const std::string vertexPath, const std::string fragmentPath)
{//创建程序对象program = glCreateProgram();setVertexShder(vertexPath);setFragmentShader(fragmentPath);}Shader::Shader(const std::string vertexPath, const std::string tescPath, const std::string tesePath, const std::string fragmentPath)
{//创建程序对象program = glCreateProgram();setVertexShder(vertexPath);setFragmentShader(fragmentPath);setTescShader(tescPath);setTeseShader(tesePath);
}//设置顶点着色器
void Shader::setVertexShder(const std::string vertexPath)
{//将上一个shader的源码清理shaderSStream.str("");memset(&shaderSource, '\0', sizeof(shaderSource));//vertex shaderif (!vertexPath.empty())   //判断文件路径是否为空{//打开文件shaderFile.open(vertexPath);//检测文件是否有误shaderFile.exceptions(std::ifstream::badbit || std::ifstream::failbit);try{if (!shaderFile.is_open())  //判断文件是否打开{throw std::exception("open vertex shader file fail");}//读取源代码到字符串流shaderSStream << shaderFile.rdbuf();//读取完毕,可以关闭文件了shaderFile.close();//将源代码输入到字符串中去shaderString = shaderSStream.str();//由于读取的是const char*类型的,所以用一个string转换一下shaderSource = shaderString.c_str();//创建顶点着色器对象GLuint vertexShader;vertexShader = glCreateShader(GL_VERTEX_SHADER);//将shader的源代码传递给shader对象glShaderSource(vertexShader, 1, &shaderSource, NULL);//编译着色器中的源代码glCompileShader(vertexShader);//将shader对象附加到program对象上去glAttachShader(program, vertexShader);//连接program对象上的shader对象glLinkProgram(program);//查错checkCompileErrors(program, "VERTEX");//可以把已经附加并且链接好的shader对象删除了glDeleteShader(vertexShader);}catch (const std::exception& e){std::cout << e.what() << std::endl;}}
}//设置曲面细分控制着色器
void Shader::setTescShader(const std::string tescPath)
{//将上一个shader的源码清理shaderSStream.str("");memset(&shaderSource, '\0', sizeof(shaderSource));//fragment shaderif (!tescPath.empty())   //判断文件路径是否为空{//文件路径不为空,打开文件shaderFile.open(tescPath);shaderFile.exceptions(std::ifstream::badbit || std::ifstream::failbit);try{if (!shaderFile.is_open())   //文件打开失败{throw std::exception("open tesc shader file fail");}//文件成功打开//字符串流读取文件中的数据shaderSStream << shaderFile.rdbuf();//读完了,把文件关了shaderFile.close();//把源代码读入字符串中去shaderString = shaderSStream.str();//把string转成系数需要的const char *类型shaderSource = shaderString.c_str();//创建shader对象GLuint tescShader;tescShader = glCreateShader(GL_TESS_CONTROL_SHADER);//将源代码读入shader对象glShaderSource(tescShader, 1, &shaderSource, NULL);//编译shader对象中的源码glCompileShader(tescShader);//将shader对象附加到program对象上去glAttachShader(program, tescShader);//链接program对象上的shader对象glLinkProgram(program);//查错checkCompileErrors(program, "PROGRAM");//完事,可以把shader对象删了glDeleteShader(tescShader);}catch (const std::exception& e){std::cout << e.what() << std::endl;}}
}//设置曲面细分评估着色器
void Shader::setTeseShader(const std::string tesePath)
{//将上一个shader的源码清理shaderSStream.str("");memset(&shaderSource, '\0', sizeof(shaderSource));//fragment shaderif (!tesePath.empty())   //判断文件路径是否为空{//文件路径不为空,打开文件shaderFile.open(tesePath);shaderFile.exceptions(std::ifstream::badbit || std::ifstream::failbit);try{if (!shaderFile.is_open())   //文件打开失败{throw std::exception("open tese shader file fail");}//文件成功打开//字符串流读取文件中的数据shaderSStream << shaderFile.rdbuf();//读完了,把文件关了shaderFile.close();//把源代码读入字符串中去shaderString = shaderSStream.str();//把string转成系数需要的const char *类型shaderSource = shaderString.c_str();//创建shader对象GLuint teseShader;teseShader = glCreateShader(GL_TESS_EVALUATION_SHADER);//将源代码读入shader对象glShaderSource(teseShader, 1, &shaderSource, NULL);//编译shader对象中的源码glCompileShader(teseShader);//将shader对象附加到program对象上去glAttachShader(program, teseShader);//链接program对象上的shader对象glLinkProgram(program);//查错checkCompileErrors(program, "PROGRAM");//完事,可以把shader对象删了glDeleteShader(teseShader);}catch (const std::exception& e){std::cout << e.what() << std::endl;}}
}//设置片段着色器
void Shader::setFragmentShader(const std::string fragmentPath)
{//将上一个shader的源码清理shaderSStream.str("");memset(&shaderSource, '\0', sizeof(shaderSource));//fragment shaderif (!fragmentPath.empty())   //判断文件路径是否为空{//文件路径不为空,打开文件shaderFile.open(fragmentPath);shaderFile.exceptions(std::ifstream::badbit || std::ifstream::failbit);try{if (!shaderFile.is_open())   //文件打开失败{throw std::exception("open fragment shader file fail");}//文件成功打开//字符串流读取文件中的数据shaderSStream << shaderFile.rdbuf();//读完了,把文件关了shaderFile.close();//把源代码读入字符串中去shaderString = shaderSStream.str();//把string转成系数需要的const char *类型shaderSource = shaderString.c_str();//创建shader对象GLuint fragmentShader;fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);//将源代码读入shader对象glShaderSource(fragmentShader, 1, &shaderSource, NULL);//编译shader对象中的源码glCompileShader(fragmentShader);//将shader对象附加到program对象上去glAttachShader(program, fragmentShader);//链接program对象上的shader对象glLinkProgram(program);//查错checkCompileErrors(program, "PROGRAM");//完事,可以把shader对象删了glDeleteShader(fragmentShader);}catch (const std::exception& e){std::cout << e.what() << std::endl;}}
}void Shader::use()
{glUseProgram(program);
}/*
* 查错
*/
void Shader::checkCompileErrors(unsigned int ID, std::string type)
{int success;char infoLog[512];if (type != "PROGRAM"){glGetShaderiv(ID, GL_COMPILE_STATUS, &success);if (!success){glGetShaderInfoLog(ID, 512, NULL, infoLog);std::cout << "shader compile error: " << infoLog << std::endl;}}else{glGetProgramiv(ID, GL_LINK_STATUS, &success);if (!success){glGetProgramInfoLog(ID, 512, NULL, infoLog);std::cout << "program linking error: " << infoLog << std::endl;}}
}

shader

vertex shader

#version 450 core
//VAO的0个位置的数据
layout(location = 0) in vec4 offset;
layout(location = 1) in vec4 color;void main()
{const vec4 vertices[3] = vec4[3](vec4(0.25, -0.25, 0.5, 1.0),vec4(-0.25, -0.25, 0.5, 1.0),vec4(0.25, 0.25, 0.5, 1.0));gl_Position = vertices[gl_VertexID] + offset;
}
  • 相较于上一次的shader,没有啥变化

tess control shader(细分曲面控制着色器)

#version 450 core
//将输出顶点设置为3个
layout(vertices = 3) out;void main()
{if(gl_InvocationID == 0){//将细分因子写入这两个变量中,后面会详细讲什么意思gl_TessLevelInner[0] = 5.0;gl_TessLevelOuter[0] = 5.0;gl_TessLevelOuter[1] = 5.0;gl_TessLevelOuter[2] = 5.0;}//将输入的数据作为输出数据gl_out[gl_InvocationID].gl_Position = gl_in[gl_InvocationID].gl_Position;
}

tess evaluation shader(细分曲面评估着色器)

#version 450 core
//模式选择为三角形,顺时针为正面,
layout(triangles, equal_spacing, cw) in;
void main()
{//细分曲面单元生成的顶点重心坐标,gl_in是曲面细分控制着色器传进来的gl_outgl_Position = (gl_TessCoord.x * gl_in[0].gl_Position + gl_TessCoord.y * gl_in[1].gl_Position + gl_TessCoord.z * gl_in[2].gl_Position);
}

fragment shader

#version 450 coreout vec4 color;void main()
{color = vec4(1.0, 1.0, 1.0, 1.0);
}

源码

#include "sb7.h"
#include "Shader.h"
#include <math.h>
class my_application : public sb7::application
{void startup(){shader = new Shader("vertexShader.vert", "tcsShader.tesc", "tesShader.tese", "fragShader.frag");;//创建数组对象glCreateVertexArrays(2, vertex_arrays_object);//绑定array对象到OpenGL上下文,让OpenGL知道这些数据glBindVertexArray(vertex_arrays_object[0]);glBindVertexArray(vertex_arrays_object[1]);}void render(double currentTime){const GLfloat color[] = {0.0f + 0.0f,0.0f + 0.0f, 0.0f, 1.0f};glClearBufferfv(GL_COLOR, 0, color);shader->use();GLfloat attrib[]{0.0f,0.0f, 0.0, 0.0f};GLfloat triangleColor[] = {1.0f,1.0f, 1.0f, 1.0f};glVertexAttrib4fv(0, attrib);glVertexAttrib4fv(1, triangleColor);//贴片的控制单数量设置glPatchParameteri(GL_PATCH_VERTICES, 3);//仅绘制三角形的轮廓glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);glDrawArrays(GL_PATCHES, 0, 3);}void shutdown() {}private:Shader* shader;//顶点数组对象GLuint vertex_arrays_object[2];
};DECLARE_MAIN(my_application);

出现过的问题

传入的基元与着色器中的不一致导致的错误

错误信息:
GL_INVALID_OPERATION error generated. State(s) are invalid: primitive mode match.
导致的后果:
无法绘制出图形
解决方案:
使用了曲面细分着色器时,查看glDrawArraws(GLenum mode, GLuint first, GLuint count)函数的第一个参数是否GL_PATCHS,如果不是的话,就会产生上述的问题。

stringstream清空的问题

在我自己封装的Shader类中,只使用了一个stringstream读取shader文件,所以每次使用之前要避免上一个shader的数据还存在流中,就需要清空流
使用clear()函数,无法达到清空流的效果
需要使用str("")才能成功的清空当前的stringstream

效果

OpenGL超级宝典 渲染管线(二)相关推荐

  1. OpenGL超级宝典(第7版)之第十二章管线监控

    OpenGL超级宝典(第7版)之第十二章管线监控 前言 一.查询 1.遮挡查询 二.OpenGL同步 前言 查询命令在图形管线中的执行进程 测量命令执行时间 同步应用程序与OpenGL以及同步多重Op ...

  2. OpenGL超级宝典(第7版)笔记4 渲染管线介绍 清单2.3-2.7

    OpenGL超级宝典(第7版)笔记4 渲染管线介绍 清单2.3-2.7 文章目录 OpenGL超级宝典(第7版)笔记4 渲染管线介绍 清单2.3-2.7 1 OpenGL简介 2 OpenGL渲染管线 ...

  3. OpenGL超级宝典(第7版)笔记11 帧缓存运算 计算着色器 清单 3.13

    OpenGL超级宝典(第7版)笔记11 帧缓存运算 计算着色器 清单 3.13 文章目录 OpenGL超级宝典(第7版)笔记11 帧缓存运算 计算着色器 清单 3.13 1 帧缓存运算 1.1 裁剪测 ...

  4. OpenGL超级宝典(第7版)笔记20 统一变量 一致区块 uniform相关内容 清单5.9-5.28

    OpenGL超级宝典(第7版)笔记20 统一变量 一致区块 uniform相关内容 清单5.9-5.28 文章目录 OpenGL超级宝典(第7版)笔记20 统一变量 一致区块 uniform相关内容 ...

  5. OpenGL超级宝典学习笔记——操作矩阵

    为了更强大的功能和灵活性,我们有时需要直接操作矩阵.在OpenGL中4x4的矩阵用包含16个浮点数值的一维数组来表示,而不是用二维的4x4的数组来表示.OpenGL之所以这么做,因为使用一维数组更高效 ...

  6. OpenGL超级宝典(第7版)笔记13 前三章实例 下个五子棋 (上)

    OpenGL超级宝典(第7版)笔记13 前三章实例 下个五子棋 (上) 文章目录 OpenGL超级宝典(第7版)笔记13 前三章实例 下个五子棋 (上) 前言 1 初构建 2 构建数据结构 3 绘制 ...

  7. OpenGL超级宝典(第7版)之第十一章高级数据管理

    提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 OpenGL超级宝典(第7版)之第十一章高级数据管理 前言 一.取消绑定 二.稀疏纹理 三.压缩纹理 四.压缩数据格式 五.高质量纹理 ...

  8. 《OpenGL超级宝典(第5版)》——第1章,第1.1节计算机图形的简单历史回顾

    本节书摘来自异步社区<OpenGL超级宝典(第5版)>一书中的第1章,第1.1节计算机图形的简单历史回顾,作者 [美]Richard S. Wright , Jr.Nicholas Hae ...

  9. 《OpenGL超级宝典》编程环境配置

    最近在接触OpenGL,使用的书籍就是那本<OpenGL超级宝典>,不过编程环境的搭建和设置还是比较麻烦的,在网上找了很多资料,找不到GLTools.lib这个库.没办法自己就借助源码自己 ...

  10. [转]OpenGL超级宝典 5e 环境配置

    OpenGL超级宝典(第五版)环境配置 1.各种库的配置 (1)glew 下载:https://sourceforge.net/projects/glew/files/glew/1.7.0/glew- ...

最新文章

  1. mpls ***简介
  2. oracle怎么判断主库还是备库,Oracle查看归档是否被备库应用
  3. 防火墙(14)——实现路由转发功能(2)
  4. 分享个 之前写好的 android 文件流缓存类,专门处理 ArrayList、bean。
  5. 持续集成部署Jenkins工作笔记0006---运行Jenkins主体程序并初始化
  6. OpenCV 2.4.8 or OpenCV 2.4.9组件结构全解析
  7. 吴恩达机器学习练习2:Regularized logistic regression
  8. Genome2D官方博客及教程
  9. 【java学习之路】(java SE篇)011.线程池
  10. 使用w3m访问页面执行函数
  11. 简单理解三种工厂模式(简单工厂模式,工厂方法模式和抽象工厂模式)
  12. 图解三代测序(Nanopore)
  13. AD破解后在同一局域网内许可证冲突
  14. 差分信号,共模与差模,共模滤波,差模滤波
  15. 开源项目——寝室助手
  16. 视频背景不好看?想要给视频里的人物抠出来换背景?教你轻松实现
  17. 【Redis之ZSet类型的详解ZSet类型中常用命令的实践】
  18. matlab建立学生档案,matlab程序设计入门20PPT18档案读写 .pptx
  19. yii2教程-登录与自动登录机制解析
  20. tsc2007电阻触摸屏调试

热门文章

  1. 基于MATLAB的无线视频传输
  2. 遗传算法原理及代码讲解
  3. eda多功能数字钟课程设计_eda课程设计——多功能数字钟.doc
  4. ASP.NET WebAPI导入EXCEL数据
  5. java定义时钟类clock_Java 编程题,定义一个时钟类(Clock)
  6. SAP ALV 负号前置
  7. java基础练习题(含答案)
  8. apex创建快捷方式_盖伦下载的Origin平台、Apex游戏手动添加快捷方式
  9. wps linux 在线安装程序,WPS Office 2019 For Linux下载及安装教程
  10. 怎样制作动图gif?GIF生成器帮你一键制作gif