对渲染相关操作封装的类库

github链接

开始准备做毕设了,利用周末的时间整理了一下图形学渲染相关的一些基础代码,尤其是opengl相关的,封装完后,如下只需简单几行就可以构建一个opengl框架。

#include <common/glfwApp.h>
#include <openglWrappers/DemoMeshes/BlinnPhongMesh.h>

//glfw setup
auto application = redips::glfw::getInstance(720, 720);

//standard pinhole camera
redips::PhC phc(60, 1.0f, 1.0f, 10000);

//load a obj and then wrap into a glMesh。
redips::BlinnPhongMesh mesh(new redips::Triangles("E:/Documents/models/maze_with_dragon.obj"));

void movement(){
	if (application->keydown(GLFW_KEY_F))
		application->showFps(false);
}

//need register a display-callback function to tell glfwApp what to render
void display(){
	mesh.uniformFloat3("lightColor", redips::float3(1, 1, 1));
	mesh.uniformFloat3("lightPos", phc.pos());
	mesh.uniformFloat3("cameraPos", phc.pos());
	mesh.uniformMat44f("projection", phc.glProjection().ptr());
	mesh.uniformMat44f("view", phc.glView().ptr());
	mesh.uniformMat44f("model", redips::Mat44f::eye().ptr());
	mesh.draw();

	movement();
}

void initialize(){
	//mesh center
	redips::float3 heart = mesh.model_ptr()->aabb_T().heart();
	//set up camera
	phc.lookAt(heart + redips::float3(0, 0, 200), heart, redips::float3(0, 1, 0));
}

int main(){
	initialize();
	application->registerDisplayCallback(display);
	application->bindCamera(&phc);
	application->loop();
	return 0;
}

简单介绍一下结构

1.依赖

需要FreeImage读/写图片,及glfw/glew。github链接里包含了所有代码及依赖的库文件。

不需要glm,assimp。

2. 环境搭建

a. 以VS2013为例,设置redips及GLEW/GLFW的头文件目录,库目录以及dll目录

X64 release

#include 
E:DocumentsCGCGLib
edips
E:DocumentsCGCGLib
edipsDependenciesGLEW_GLFW_X64include

#libs
E:DocumentsCGCGLib
edipsDependenciesFreeImagex64
E:DocumentsCGCGLib
edipsDependenciesGLEW_GLFW_X64libsglew_x64
E:DocumentsCGCGLib
edipsDependenciesGLEW_GLFW_X64libsglfw_64_lib-vc2013

FreeImage.lib
glew32.lib
opengl32.lib
glfw3.lib

#dlls
path=E:DocumentsCGCGLib
edipsDependenciesFreeImagex64;E:DocumentsCGCGLib
edipsDependenciesGLEW_GLFW_X64inx64;E:DocumentsCGCGLib
edipsDependenciesGLEW_GLFW_X64libsglfw_64_lib-vc2013

 b. 因为OpenglWrappersDemoMeshes下面提供了BlinnPhongMesh,gBufferMesh,PhongMesh三个mesh,每个mesh都提供了默认的shader文件,所以在Commonconstant.h里面定义了一个宏:_REDIPS_ROOT_PATH_。需要把其改为解压redips的根目录。

3. 类库

Cameras里面包括基类Camera以及派生类PhC,GLC,MPC,常用PhC(小孔相机)实现了getRay(uint x,uint y)[for raytracing];  glProjection()[for rasterization]等常用函数。

Common比较重要。里面包含了

  • constant.h => 包含一些常量、宏、枚举类的定义。
  • fImage.h  => 对FreeImage的封装。可以方便的读、写图片。
  • glfwApp.h   => 对GLFW的封装。仅需一句 auto application = redips::glfw::getInstance(); 就可以创建好一个GLFW环境。
  • rayTracer.h => 实现了一个简单的Ray Tracer。渲染一副图片并保存。
  • utils.h => 实现了一些工具类,如StringUtil类实现了部分对字符串的操作。
  • vec.h  => Vec2/Vec3/Vec4/Mat33/Mat44的常用操作,遵循 column-major。

Geometry里包含了几何相关的类。

  • geometry.h => 定义了简单常用的数据结构,如BOX,Light,Ray,HitRecord,以及一个工具类GeoUtil,提供如求重心坐标、三角形面积等工具函数
  • kdtree.h => 实现了一个简单的kdtree用于加速raytracing。
  • material.h => 定义了材质类Material以及MtlLib类用来load *.mtl文件。
  • model.h => 定义了模型类的基类Model,暂时只派生出Triangles和Partiles两个类。Model类主要定义了几个接口规范。比如virtual bool intersect(const Ray& ray, HitRecord& record) = 0;用来判断光线是否与模型相交。
  • triangles.h => 定义了Mesh类用来加载obj模型及存储相关信息。Triangles类是Model类的派生类。实现了Model的全部接口。还有 类似Triangles(const float3 &boxdim,float3 center = float3(0.0f,0.0f,0.0f))【快速创建一个正方体mesh。】的函数
  • particles.h => 一堆小球组成的例子系统。暂时还不完善。

OpenglWrappers里面封装了OpenGL相关的类。

  • glMeshWrapper.h => 用来将数据打包传到显卡,这包括材质中用到的纹理。实现了引用计数避免将同一个模型的数据多次传入显存。将Obj模型里使用相同material的group合并成一组放在一个Vbo里节约了资源。后面会介绍glMeshWrapper的使用。
  • glslShaderWrapper.h => 封装了glsl shader的相关操作。ShaderSource类用来说明shader的来源(from file or existed shader program)用来避免多次创建同一个shader。Shader类主要负责加载shader文件。ShaderManager类会自动加载一个指定文件夹下的所有shader文件,并重载了[]运算符。shaderManager["light"],即可获得light.vs/light.fs定义的shader。
  • glTextureWrapper.h => 封装了Texture的相关操作。
  • glHelper.h => 定义了opengl相关的辅助类:glImageRender用于显示一张2d图片到opengl窗口(可以用来显示raytracing的结果),glScreenCapture用于保存渲染的图片。

 4. glMeshWrapper的使用

glMeshWrapper只负责生成纹理、将数据绑定到VBO。而其派生类负责和shader交互,渲染等。所以glMeshWrapper的构造函数被定义成了protected不能创建对象。
其作为基类提供了一些常用操作及接口规范。定义一个glMeshWrapper派生类需要以下工作:

#pragma once
#include <openglWrappers/glMeshWrapper.h>
class LightMesh : public redips::glMeshWrapper{
public:
	LightMesh(const redips::Triangles* model, redips::ShaderSource shadersource = redips::ShaderSource(), unsigned int option = 1u) : glMeshWrapper(model, shadersource,option){
		bindVaoAttribData(0, 1, -1);
	};
	LightMesh(const glMeshWrapper& another, redips::ShaderSource shadersource = redips::ShaderSource()) : glMeshWrapper(another,shadersource){
		bindVaoAttribData(0, 1, -1);
	}
	~LightMesh(){};
};

1. 定义一个普通构造及一个拷贝构造函数,说明应该绑定哪些数据到vao。普通构造函数中的三个参数分别是:三角mesh、mesh使用的ShaderSource、打包mesh的option[传送模型数据时是以mtl为单位还是group为单位打包;是否要自动生成三角面片的法线]。ShaderSource有两个构造函数及一个默认构造,其中一个接受一个GLuint类型的参数[代表一个现有的shaderProgram],另外一个接受const char* 类型的参数[shader文件的路径]。所以可以像下面那样创建LightMesh.

    LightMesh* mesh1 = new LightMesh(new Triangles("obj/file/path"), "shader/path");
    LightMesh* mesh2 = new LightMesh(new Triangles("obj/file/path"), existedShader.Program);

    LightMesh* mesh3 = new LightMesh(new Triangles("obj/file/path"));
    mesh3->useShader(existedShader.Program);
    mesh3->useShader("shader/path");

也可以像mesh3那样后来再指定shader。

2. 重写glMeshWrapper的draw()函数用于定制化的渲染[比如激活纹理等操作]。LightMesh类没有重写,使用了glMeshWrapper提供的draw()函数。

原文地址:https://www.cnblogs.com/redips-l/p/8013138.html