OSG使用OpenGL(以及glad库)绘制自定义图形

简单记录一下在OSG中使用OpenGL函数(以及glad库)绘制自定义图形。

源码:

#include <osgViewer/viewer>
#include <osg/Geode>

#include "CustomDrawable.h"

int main()
{
    
    
    osg::ref_ptr<osg::Geode> root = new osg::Geode;
    root->addDrawable(new CustomDrawable);

    osgViewer::Viewer viewer;
    viewer.setSceneData(root);
    viewer.realize();
    viewer.getCamera()->getGraphicsContext()->getState()->resetVertexAttributeAlias(false);
    viewer.getCamera()->getGraphicsContext()->getState()->setUseModelViewAndProjectionUniforms(true);
    viewer.getCamera()->getGraphicsContext()->getState()->setUseVertexAttributeAliasing(true);
    return viewer.run();
}
#include <osg/Drawable>

class CustomDrawable:public osg::Drawable
{
    
    
public:
	CustomDrawable();
	~CustomDrawable();

protected:
	osg::BoundingBox computeBoundingBox() const override;
	void drawImplementation(osg::RenderInfo& renderInfo) const override;

private:
	GLfloat* vertices = nullptr;
	GLuint* indices = nullptr;

	mutable unsigned int vao;
	mutable unsigned int vbo;
	mutable unsigned int ebo;

	mutable bool doOnce = true;
};
#include "CustomDrawable.h"

CustomDrawable::CustomDrawable()
{
    
    
	this->setUseDisplayList(false);
	this->setUseVertexBufferObjects(true);

	vertices = new GLfloat[2 * 2 * 3];
	vertices[0] = 1.0;
	vertices[1] = 1.0;
	vertices[2] = 0.0;

	vertices[3] = 1.0;
	vertices[4] = -1.0;
	vertices[5] = 0.0;

	vertices[6] = -1.0;
	vertices[7] = -1.0;
	vertices[8] = 0.0;

	vertices[9] = -1.0;
	vertices[10] = 1.0;
	vertices[11] = 0.0;

	indices = new GLuint[6];
	indices[0] = 0;
	indices[1] = 1;
	indices[2] = 2;
	indices[3] = 2;
	indices[4] = 3;
	indices[5] = 0;
}

CustomDrawable::~CustomDrawable()
{
    
    
}

osg::BoundingBox CustomDrawable::computeBoundingBox() const
{
    
    
	return osg::BoundingBox(osg::Vec3f(-1.0, -1.0, -1.0), osg::Vec3f(1.0, 1.0, 1.0));
}

void CustomDrawable::drawImplementation(osg::RenderInfo& renderInfo) const
{
    
    
	auto ext = renderInfo.getState()->get<osg::GLExtensions>();

	if (doOnce) 
	{
    
    
		ext->glGenVertexArrays(1, &vao);
		ext->glBindVertexArray(vao);
		ext->glGenBuffers(1, &vbo);
		ext->glBindBuffer(GL_ARRAY_BUFFER_ARB, vbo);
		ext->glBufferData(GL_ARRAY_BUFFER_ARB, 2 * 2 * 3 * 4, vertices, GL_STATIC_DRAW);

		ext->glGenBuffers(1, &ebo);
		ext->glBindBuffer(GL_ELEMENT_ARRAY_BUFFER_ARB, ebo);
		ext->glBufferData(GL_ELEMENT_ARRAY_BUFFER_ARB, 6 * 4, indices, GL_STATIC_DRAW);

		ext->glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);
		ext->glEnableVertexAttribArray(0);

		doOnce = false;
	}

	ext->glBindVertexArray(vao);
	ext->glDrawElementsInstanced(GL_TRIANGLES, 6, GL_UNSIGNED_INT, (void*)0, 1);
}

运行效果:

在这里插入图片描述

--------------------------------------------------- 12月7日更新 ---------------------------------------------------
使用着色器:
主要是drawImplementation函数内的改动。
需要注意的是似乎这样直接调用OpenGL函数绘制,并使用着色器的话,内置的osg_ModelViewProjectionMatrix变量就失效了,需要自行获取ModelViewMatrix和ProjectionMatrix输入着色器。

void CustomDrawable::drawImplementation(osg::RenderInfo& renderInfo) const
{
    
    
	auto ext = renderInfo.getState()->get<osg::GLExtensions>();
	
	//获取ModelViewMatrix和ProjectionMatrix
	auto mvMatrix = renderInfo.getState()->getModelViewMatrix();
	auto proMatrix = renderInfo.getState()->getProjectionMatrix();
	auto mvValue = mvMatrix.ptr();
	auto proValue = proMatrix.ptr();
	float _mvMatrix[16];
	float _proMatrix[16];
	for (int i = 0; i < 16; i++) 
	{
    
    
		_mvMatrix[i] = (float)mvValue[i];
		_proMatrix[i] = (float)proValue[i];
	}

	if (doOnce) 
	{
    
    
		ext->glGenVertexArrays(1, &vao);
		ext->glBindVertexArray(vao);
		ext->glGenBuffers(1, &vbo);
		ext->glBindBuffer(GL_ARRAY_BUFFER_ARB, vbo);
		ext->glBufferData(GL_ARRAY_BUFFER_ARB, N * N * 3 * 4, vertices, GL_STATIC_DRAW);

		ext->glGenBuffers(1, &ebo);
		ext->glBindBuffer(GL_ELEMENT_ARRAY_BUFFER_ARB, ebo);
		ext->glBufferData(GL_ELEMENT_ARRAY_BUFFER_ARB, (N - 1) * (N - 1) * 6 * 4, indices, GL_STATIC_DRAW);

		ext->glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);
		ext->glEnableVertexAttribArray(0);
		
		//Shader为自己简单封装的一个类,内容跟OpenGL中使用Shader一致
		vfShader = new Shader(ext, "./Test.vert", "./Test.frag");

		doOnce = false;
	}

	vfShader->Bind();
	vfShader->SetMat4("modelViewMatrix", _mvMatrix);
	vfShader->SetMat4("projectionMatrix", _proMatrix);

	ext->glBindVertexArray(vao);
	ext->glDrawElementsInstanced(GL_TRIANGLES, (N - 1) * (N - 1) * 6, GL_UNSIGNED_INT, (void*)0, 1);
}

顶点着色器:

#version 430

layout(location = 0) in vec3 vPos;

//uniform mat4 osg_ModelViewProjectionMatrix;
uniform mat4 modelViewMatrix;
uniform mat4 projectionMatrix;

void main()
{
    
    
	gl_Position = projectionMatrix*modelViewMatrix*vec4(vPos,1.0);
}

片元着色器:

#version 430

out vec4 FragColor;

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

另外computeBoundingBox函数中设置的包围盒大小一定要大于等于图形的大小,不然会产生裁切问题,如下图,包围盒顶点的值是±1.0,图形顶点的值是±256.0,垂直在一定角度范围内是正常的,但是再继续倾斜就会发生裁切。另外,包围盒的大小也会影响程序刚运行时初始视角离图形的远近,例如包围盒设置±512.0就会比设置±256.0的初始视角要远。

在这里插入图片描述

嵌入glad库:(还在尝试)
glad+glfw库是很多OpenGL资料中非常常见的一种搭配,因为在查询OSG使用OpenGL绘制自定义图形的资料时,找到了在OSG中用glut库的glutSolidTeapot函数绘制teapot,所以想既然glut都能嵌入使用,那glad是不是也可以呢?因为很多OpenGL资料都是用的glad,如果能够找到办法嵌入使用,那么就可以直接挪到OSG中而不用想办法转换实现。

先说结论:理论上似乎是可以,但是glGetString不知道为什么获取不到,并且文件包含比较麻烦。 可以。

1、首先glad头文件的包含问题
因为OSG底层包含了系统的gl.h文件,其中当没有定义__gl_h_这个宏的时候会定义这个宏,所以当这个宏已经被定义了的时候,glad会报错:

在这里插入图片描述

然后就需要把glad.h的包含放在整个代码的最前面,像下面这样
在CustomDrawable.h中放在最前面

在这里插入图片描述

然后把CustomDrawable.h的包含放在main.cpp最前面

在这里插入图片描述

这样就不会报这个错了。

2、glad的初始化
glad库使用时先需要对glad进行初始化,在glad+glfw库的使用中,glad的初始化是由gladLoadGLLoader函数来完成的。

在这里插入图片描述

由glfwGetProcAddress的名称、注释以及接口参数可以得知,这是一个通过传入名称来获取函数地址的函数。
通过gladLoadGLLoader的源码可以得知,glad通过传入的glfwGetProcAddress函数来初始化自身的函数指针接口。
所以我需要在OSG中找到一个能够通过名称来获取函数地址的函数。
因为OSG的OpenGL相关函数主要都在GLExtensions类中,所以就先在它的头文件中寻找,然后发现有一个在类外的函数叫做getGLExtensionFuncPtr正好是我需要的,在doOnce中加入如下代码:

在这里插入图片描述

结果发现并不能初始化成功,单步跟入gladLoadGLLoader函数内,发现是在第一步获取glGetString时返回为空。

在这里插入图片描述

然后尝试单独调用getGLExtensionFuncPtr,发现确实无法获取到glGetString,但是像glGenBuffers什么的都是可以获取到的。
查看getGLExtensionFuncPtr的源码,发现它是通过调用wingdi.h中的wglGetProcAddress来获取函数地址,目前暂不清楚为什么wglGetProcAddress获取不到glGetString的函数地址…

--------------------------------------------------- 12月8日更新 ---------------------------------------------------
查找资料发现wglGetProcAddress这个函数只能获取OpenGL 1.1+的拓展,而glGetString是OpenGL 1.0的,所以这个函数无法获取到glGetString的函数地址。
接着在StackOverFlow上找到了关于wgl+glad的提问,里面提到了用gladLoadGL()进行初始化,这是glad的另一个初始化函数。
这里需要注意如果调用gladLoadGL()返回false有可能是因为没有添加opengl32.lib,需要在附加依赖项中添加这个lib,原因查看glad源码可知。

在这里插入图片描述

主要是drawImplementation函数内的改动。

void CustomDrawable::drawImplementation(osg::RenderInfo& renderInfo) const
{
    
    
	//获取ModelViewMatrix和ProjectionMatrix
	auto mvMatrix = renderInfo.getState()->getModelViewMatrix();
	auto proMatrix = renderInfo.getState()->getProjectionMatrix();
	auto mvValue = mvMatrix.ptr();
	auto proValue = proMatrix.ptr();
	float _mvMatrix[16];
	float _proMatrix[16];
	for (int i = 0; i < 16; i++) 
	{
    
    
		_mvMatrix[i] = (float)mvValue[i];
		_proMatrix[i] = (float)proValue[i];
	}

	if (doOnce) 
	{
    
    
		if (!gladLoadGL())
		{
    
    
			std::cout << "Failed to initialize GLAD" << std::endl;
		}

		glGenVertexArrays(1, &vao);
		glBindVertexArray(vao);
		glGenBuffers(1, &vbo);
		glBindBuffer(GL_ARRAY_BUFFER, vbo);
		glBufferData(GL_ARRAY_BUFFER, N * N * 3 * 4, vertices, GL_STATIC_DRAW);

		glGenBuffers(1, &ebo);
		glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebo);
		glBufferData(GL_ELEMENT_ARRAY_BUFFER, (N - 1) * (N - 1) * 6 * 4, indices, GL_STATIC_DRAW);

		glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);
		glEnableVertexAttribArray(0);

		vfShader = new Shader("./Test.vert", "./Test.frag");

		doOnce = false;
	}

	glUseProgram(vfShader->id);
	auto modelViewLoc = glGetUniformLocation(vfShader->id, "modelViewMatrix");
	auto projectionLoc = glGetUniformLocation(vfShader->id, "projectionMatrix");
	glUniformMatrix4fv(modelViewLoc, 1, GL_FALSE, _mvMatrix);
	glUniformMatrix4fv(projectionLoc, 1, GL_FALSE, _proMatrix);

	glBindVertexArray(vao);
	//glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
	glDrawElements(GL_TRIANGLES, (N - 1) * (N - 1) * 6, GL_UNSIGNED_INT, (void*)0);
}

运行效果:

在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/qq_45523399/article/details/128195741