OpenGL画圆环

代码主要由Torus.hpp、Torus.cpp、Utils.hpp构成,通过加载纹理图片和着色器文件Torus_Texture_frag.glsl、Torus_Texture_vert.glsl实现画出一个甜甜圈的效果。

主要用到的图形库有glew、glfw3、soil2、glm

实现如下:

Utils.hpp包含了加载纹理和glsl着色器文件的功能性程序

#include <GL/glew.h>
#include <GLFW/glfw3.h>
#include "SOIL2/SOIL2.h"
#include <string>
#include <iostream>
#include <fstream>
#include <cmath>
#include <glm/glm.hpp>
#include <glm/gtc/type_ptr.hpp> // glm::value_ptr
#include <glm/gtc/matrix_transform.hpp> // glm::translate, glm::rotate, glm::scale, glm::perspective
using namespace std;

class Utils
{
private:
	static GLuint prepareShader(int shaderTYPE, const char* shaderPath);

public:
	Utils(){};
	static GLuint createShaderProgram(const char* vp, const char* fp);
    static GLuint loadTexture(const char *texImagePath)
};

GLuint Utils::prepareShader(int shaderTYPE, const char* shaderPath)
{
	GLint shaderCompiled;
	string shaderStr = readShaderFile(shaderPath);
	const char* shaderSrc = shaderStr.c_str();
	GLuint shaderRef = glCreateShader(shaderTYPE);
	glShaderSource(shaderRef, 1, &shaderSrc, NULL);
	glCompileShader(shaderRef);
	checkOpenGLError();
	glGetShaderiv(shaderRef, GL_COMPILE_STATUS, &shaderCompiled);
	if (shaderCompiled != 1)
	{
		if (shaderTYPE == 35633) cout << "Vertex ";
		if (shaderTYPE == 36488) cout << "Tess Control ";
		if (shaderTYPE == 36487) cout << "Tess Eval ";
		if (shaderTYPE == 36313) cout << "Geometry ";
		if (shaderTYPE == 35632) cout << "Fragment ";
		cout << "shader compilation error." << endl;
		printShaderLog(shaderRef);
	}
	return shaderRef;
}

GLuint Utils::createShaderProgram(const char* vp, const char* fp) {
	GLuint vShader = prepareShader(GL_VERTEX_SHADER, vp);
	GLuint fShader = prepareShader(GL_FRAGMENT_SHADER, fp);
	GLuint vfprogram = glCreateProgram();
	glAttachShader(vfprogram, vShader);
	glAttachShader(vfprogram, fShader);
	finalizeShaderProgram(vfprogram);
	return vfprogram;
}

GLuint Utils::loadTexture(const char *texImagePath)
{
    GLuint textureRef;
    textureRef = SOIL_load_OGL_texture(texImagePath, SOIL_LOAD_AUTO, SOIL_CREATE_NEW_ID, SOIL_FLAG_INVERT_Y);
    if (textureRef == 0) cout << "didnt find texture file " << texImagePath << endl;
    // ----- mipmap/anisotropic section
    glBindTexture(GL_TEXTURE_2D, textureRef);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
    glGenerateMipmap(GL_TEXTURE_2D);
    if (glewIsSupported("GL_EXT_texture_filter_anisotropic")) {
        GLfloat anisoset = 0.0f;
        glGetFloatv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &anisoset);
        glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, anisoset);
    }
    // ----- end of mipmap/anisotropic section
    return textureRef;
}

主程序入口draw_Torus.cpp

#define GLEW_STATIC
#include<GL/glew.h>
#include<GLFW\glfw3.h>
#include<string>
#include<iostream>
#include<fstream>
#include<cmath>
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtc/type_ptr.hpp>
#include"SOIL2/SOIL2.h"
#include "Utils.hpp"
#include"Torus.hpp"

using namespace std;

#define numVAOs 1
#define numVBOs 4

float cameraX, cameraY, cameraZ;
float pyrLocX, pyrLocY, pyrLocZ;
GLuint renderingProgram;
GLuint vao[numVAOs];
GLuint vbo[numVBOs];

//allocate variables used in display() function, so that they won't need to be allocated during rendering
GLuint mvLoc, projLoc;
GLuint brickTexture;
int width, height;
float aspect, tf;
glm::mat4 pMat, vMat, mMat, mvMat;
Torus myTorus(1.8f, 1.0f, 48);
vector<int> ind;

void setupVertices(void) {
	ind = myTorus.getIndices();
	vector<glm::vec3> vert = myTorus.getVertices();
	vector<glm::vec2> tex = myTorus.getTexCoords();
	vector<glm::vec3> norm =myTorus.getNormals();

	vector<float> pvalues;
	vector<float> tvalues;
	vector<float> nvalues;
	int numVertices = myTorus.getNumVertices();
	for (int i = 0; i < numVertices; i++) {
		pvalues.push_back((vert[i]).x);
		pvalues.push_back((vert[i]).y);
		pvalues.push_back((vert[i]).z);

		tvalues.push_back((tex[i]).s);
		tvalues.push_back((tex[i]).t);

		nvalues.push_back((norm[i]).x);
		nvalues.push_back((norm[i]).y);
		nvalues.push_back((norm[i]).z);
	}

	glGenVertexArrays(1, vao);
	glBindVertexArray(vao[0]);
	//put the vertices into buffer #0
	glGenBuffers(4, vbo);
	glBindBuffer(GL_ARRAY_BUFFER, vbo[0]);
	glBufferData(GL_ARRAY_BUFFER, pvalues.size() * 4, &pvalues[0], GL_STATIC_DRAW);
	glBindBuffer(GL_ARRAY_BUFFER, vbo[1]);
	glBufferData(GL_ARRAY_BUFFER, tvalues.size() * 4, &tvalues[0], GL_STATIC_DRAW);
	glBindBuffer(GL_ARRAY_BUFFER, vbo[2]);
	glBufferData(GL_ARRAY_BUFFER, nvalues.size() * 4, &nvalues[0], GL_STATIC_DRAW);

	glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vbo[3]);
	glBufferData(GL_ELEMENT_ARRAY_BUFFER, ind.size() * 4, &ind[0], GL_STATIC_DRAW);
}

void init(GLFWwindow* window) {
	renderingProgram = Utils::createShaderProgram("Torus_Texture_vert.glsl", "Torus_Texture_frag.glsl");
	glfwGetFramebufferSize(window, &width, &height);
	aspect = (float)width / (float)height;
	pMat = glm::perspective(1.0472f, aspect, 0.1f, 1000.0f);//1.0472 radians=60degrees
	cameraX = 1.5f; cameraY = -3.6f; cameraZ = 10.0f;
	pyrLocX = -0.6f; pyrLocY = 0.7f; pyrLocZ = -5.0f;//注意方位设置的问题,很可能因为方位设置使得某物体在窗口不可见
	brickTexture = Utils::loadTexture("imgs/donut.jpg");
	setupVertices();
}

void  display(GLFWwindow* window, double currentTime)
{
	glClear(GL_DEPTH_BUFFER_BIT);
	glClearColor(0.0, 0.0, 0.0, 1.0);
	glClear(GL_COLOR_BUFFER_BIT);
	glUseProgram(renderingProgram);

	//get  the uniform variables for the MV and projection matrices
	mvLoc = glGetUniformLocation(renderingProgram, "mv_matrix");//get location of uniforms in the shader program
	projLoc = glGetUniformLocation(renderingProgram, "proj_matrix");


	//build view matrix,model matrix,and model-view matrix	
	vMat = glm::translate(glm::mat4(1.0f), glm::vec3(-cameraX, -cameraY, -cameraZ));
	//draw the cube(use buffer #0)

	mvMat = vMat * mMat;

	glEnable(GL_CULL_FACE);

	glUniformMatrix4fv(mvLoc, 1, GL_FALSE, glm::value_ptr(mvMat));
	glUniformMatrix4fv(projLoc, 1, GL_FALSE, glm::value_ptr(pMat));

	glBindBuffer(GL_ARRAY_BUFFER, vbo[0]);
	glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0);
	glEnableVertexAttribArray(0);

	glBindBuffer(GL_ARRAY_BUFFER, vbo[1]);
	glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 0, 0);
	glEnableVertexAttribArray(1);

	glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vbo[3]);	
	glBufferData(GL_ELEMENT_ARRAY_BUFFER, ind.size() * 4, &ind[0], GL_STATIC_DRAW);

	glActiveTexture(GL_TEXTURE0);
	glBindTexture(GL_TEXTURE_2D, brickTexture);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_MIRRORED_REPEAT);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_MIRRORED_REPEAT);

	glEnable(GL_DEPTH_TEST);
	glDepthFunc(GL_LEQUAL);

	glDrawElements(GL_TRIANGLES, myTorus.getNumIndices(), GL_UNSIGNED_INT, 0);
}

int main(void)
{
	if (!glfwInit()) {
		exit(EXIT_FAILURE);
	}
	glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4);
	glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);//use OpenGL version4.3
	GLFWwindow* window = glfwCreateWindow(2000, 2000, "Torus shadered by Donut Texture", NULL, NULL);//the last
	//two parameters allow for full screen mode and resource sharing
	glfwMakeContextCurrent(window);
	if (glewInit() != GLEW_OK) { exit(EXIT_FAILURE); }
	glfwSwapInterval(1);

	init(window);

	while (!glfwWindowShouldClose(window))
	{
		display(window, glfwGetTime());
		glfwSwapBuffers(window);
		glfwPollEvents();//handle other window related  events(such as the user clicking the "X"
		//in the upper right corner,the window module)
	}

	glfwDestroyWindow(window);
	glfwTerminate();
	exit(EXIT_SUCCESS);
	return 0;
}

Torus.hpp:

#pragma once
#include<cmath>
#include<vector>
#include<glm\glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtc/type_ptr.hpp>
class Torus
{
private:
	int numVertices;
	int numIndices;
	int prec;
	float inner;
	float outer;
	std::vector<int> indices;
	std::vector<glm::vec3> vertices;
	std::vector<glm::vec2> texCoords;
	std::vector<glm::vec3> normals;
	std::vector<glm::vec3> sTangents;
	std::vector<glm::vec3> tTangents;
	void init();
	float toRadians(float degrees);
public:
	Torus();
	Torus(float innerRadius, float outerRadius, int prec);
	int getNumVertices();
	int getNumIndices();
	std::vector<int> getIndices();
	std::vector<glm::vec3> getVertices();
	std::vector<glm::vec2> getTexCoords();
	std::vector<glm::vec3> getNormals();
	std::vector<glm::vec3> getStangents();
	std::vector<glm::vec3> getTtangents();
};

Torus.cpp:

#include<cmath>
#include<vector>
#include<iostream>
#include "Torus.hpp"
using namespace std;

Torus::Torus() {
	prec = 48;
	inner = 5.0f;
	outer = 2.0f;
	init();
}

Torus::Torus(float innerRadius, float outerRadius, int precIn) {
	prec = precIn;
	inner = innerRadius;
	outer = outerRadius;
	init();
}

inline float Torus::toRadians(float degrees) { return (degrees * 2.0f * 3.14159f) / 360.0f; }

void Torus::init() {
	numVertices = (prec + 1) * (prec + 1);
	numIndices = prec * prec * 6;

	for (int i = 0; i < numVertices; i++) {
		vertices.push_back(glm::vec3());
		texCoords.push_back(glm::vec2());
		normals.push_back(glm::vec3());
		sTangents.push_back(glm::vec3());
		tTangents.push_back(glm::vec3());
	}
	for (int i = 0; i < numIndices; i++) { indices.push_back(0); }
	for (int i = 0; i < prec + 1; i++) {
		float amt = toRadians(i * 360.0f / prec);
		//build the ring by rotating points around the origin,then moving them outward
		glm::mat4 rMat = glm::rotate(glm::mat4(1.0f), amt, glm::vec3(0.0f, 0.0f, 1.0f));
		glm::vec3 initPos(rMat * glm::vec4(outer, 0.0f, 0.0f, 1.0f));
		vertices[i] = glm::vec3(initPos+glm::vec3(inner,0.0f,0.0f));

		//compute texture coordinates for each vertex on the ring
		texCoords[i] = glm::vec2(0.0f, ((float)i / (float)prec));

		//compute tangents and noramals -- first tangent is Y-axis rotated around Z
		rMat = glm::rotate(glm::mat4(1.0f), amt, glm::vec3(0.0f, 0.0f, 1.0f));
		tTangents[i] = glm::vec3(rMat * glm::vec4(0.0f, -1.0f, 0.0f, 1.0f));
		sTangents[i] = glm::vec3(glm::vec3(0.0f, 0.0f, -1.0f));
		normals[i] = glm::cross(tTangents[i], sTangents[i]);

		for (int ring = 1; ring < prec + 1; ring++) {
			for (int vert = 0; vert < prec + 1; vert++) {
				//rotate the vertex position of the original ring around the Y axis
				float amt = (float)(toRadians(ring * 360.0f / prec));
				glm::mat4 rMat = glm::rotate(glm::mat4(1.0f), amt, glm::vec3(0.0f, 1.0f, 0.0f));
				vertices[ring * (prec + 1) + i] = glm::vec3(rMat * glm::vec4(vertices[i], 1.0f));

				//compute the texture coordinates for the vertices in the new rings
				texCoords[ring * (prec + 1) + vert] = glm::vec2((float)ring * 2.0f / (float)prec, texCoords[vert].t);
				if (texCoords[ring * (prec + 1) + i].s > 1.0) texCoords[ring * (prec + 1) + i].s -= 1.0f;

				//rotate the tangent and bitangent vectors around the Y axis
				rMat = glm::rotate(glm::mat4(1.0f), amt, glm::vec3(0.0f, 1.0f, 0.0f));
				sTangents[ring * (prec + 1) + i] = glm::vec3(rMat * glm::vec4(sTangents[i], 1.0f));
				rMat = glm::rotate(glm::mat4(1.0f), amt, glm::vec3(0.0f, 1.0f, 0.0f));
				tTangents[ring * (prec + 1) + i] = glm::vec3(rMat * glm::vec4(tTangents[i], 1.0f));

				//rotate the normal vector around the Y axis
				rMat = glm::rotate(glm::mat4(1.0f), amt, glm::vec3(0.0f, 1.0f, 0.0f));
				normals[ring * (prec + 1) + i] = glm::vec3(rMat * glm::vec4(normals[i], 1.0f));
			}
		}

		//calculate triangle indices corresponding to the two triangles built per vertex
		for (int ring = 0; ring < prec; ring++) {
			for (int vert = 0; vert < prec; vert++) {
				indices[((ring * prec + vert) * 2) * 3 + 0] = ring * (prec + 1) + vert;
				indices[((ring * prec + vert) * 2) * 3 + 1] = (ring + 1) * (prec + 1) + vert;
				indices[((ring * prec + vert) * 2) * 3 + 2] = ring * (prec + 1) + vert + 1;
				indices[((ring * prec + vert) * 2 + 1) * 3 + 0] = ring * (prec + 1) + vert + 1;
				indices[((ring * prec + vert) * 2 + 1) * 3 + 1] = (ring + 1) * (prec + 1) + vert;
				indices[((ring * prec + vert) * 2 + 1) * 3 + 2] = (ring + 1) * (prec + 1) + vert + 1;
			}
		}
	}
}

//accessors for the torus indices and vertices
int Torus::getNumVertices() { return numVertices; }
int Torus::getNumIndices() { return numIndices; }
std::vector<int> Torus::getIndices() { return indices; }
std::vector<glm::vec3> Torus::getVertices() { return vertices; }
std::vector<glm::vec2> Torus::getTexCoords() { return texCoords; }
std::vector<glm::vec3> Torus::getNormals() { return normals; }
std::vector<glm::vec3> Torus::getStangents() { return sTangents; }
std::vector<glm::vec3> Torus::getTtangents() { return tTangents; }

着色器Torus_Texture_frag.glsl

#version 430
in vec2 tc;
out vec4 color;
uniform mat4 mv_matrix;
uniform mat4 proj_matrix;
layout (binding=0) uniform sampler2D samp;

void main(void)
{
	color=texture(samp,tc);
}

着色器Torus_Texture_vert.glsl

#version 430
layout(location=0) in vec3 pos;
layout(location=1) in vec2 texCoord;
out vec2 tc;			//texture coordinate output to rasterizer for interpolation
uniform mat4 mv_matrix;
uniform mat4 proj_matrix;
layout (binding=0) uniform sampler2D samp;

void main(void)
{
	gl_Position = proj_matrix * mv_matrix * vec4(pos,1.0);
	tc= texCoord;
}

纹理图片在draw_Torus.cpp所在目录下的imgs文件夹下

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值