✠OpenGL-6-3D模型

Posted itzyjr

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了✠OpenGL-6-3D模型相关的知识,希望对你有一定的参考价值。

程序构建模型——构建一个球体

earth.jpg



直接给出完整代码:
Sphere.h

#include <cmath>
#include <vector>
#include <glm\\glm.hpp>
class Sphere {
private:
	int numVertices;
	std::vector<glm::vec3> vertices;
	std::vector<glm::vec2> texCoords;
	void init(float, float);
	float toRadians(float degrees);
public:
	Sphere();
	Sphere(float R, float prec);
	int getNumVertices();
	std::vector<glm::vec3> getVertices();
	std::vector<glm::vec2> getTexCoords();
};

Sphere.cpp

#include <cmath>
#include <vector>
#include <iostream>
#include <glm\\glm.hpp>
#include "Sphere.h"
using namespace std;

Sphere::Sphere() {
	init(1.0, 10.0);
}

Sphere::Sphere(float R, float angleSpan) {
	init(R, angleSpan);
}

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

int Sphere::getNumVertices() { return numVertices; }
std::vector<glm::vec3> Sphere::getVertices() { return vertices; }
std::vector<glm::vec2> Sphere::getTexCoords() { return texCoords; }

/*
* R:球半径,angleSpan:将球进行横向和纵向单位切分的角度
*/
void Sphere::init(float R, float angleSpan) {
	for (float vAngle = -90; vAngle < 90; vAngle = vAngle + angleSpan) { // 垂直方向angleSpan度一份
		for (float hAngle = 0; hAngle < 360; hAngle = hAngle + angleSpan) { // 水平方向angleSpan度一份
			float vAngleLen = 90 + vAngle;// [-90°-0-90°] == t[0-0.5-1]

			float x0 = (float)(R * cos(toRadians(vAngle)) * cos(toRadians(hAngle)));
			float y0 = (float)(R * cos(toRadians(vAngle)) * sin(toRadians(hAngle)));
			float z0 = (float)(R * sin(toRadians(vAngle)));

			float s0 = hAngle / 360;
			float t0 = vAngleLen / 180;

			float x1 = (float)(R * cos(toRadians(vAngle)) * cos(toRadians(hAngle + angleSpan)));
			float y1 = (float)(R * cos(toRadians(vAngle)) * sin(toRadians(hAngle + angleSpan)));
			float z1 = (float)(R * sin(toRadians(vAngle)));

			float s1 = (hAngle + angleSpan) / 360;
			float t1 = vAngleLen / 180;

			float x2 = (float)(R * cos(toRadians(vAngle + angleSpan)) * cos(toRadians(hAngle + angleSpan)));
			float y2 = (float)(R * cos(toRadians(vAngle + angleSpan)) * sin(toRadians(hAngle + angleSpan)));
			float z2 = (float)(R * sin(toRadians(vAngle + angleSpan)));

			float s2 = (hAngle + angleSpan) / 360;
			float t2 = (vAngleLen + angleSpan) / 180;

			float x3 = (float)(R * cos(toRadians(vAngle + angleSpan)) * cos(toRadians(hAngle)));
			float y3 = (float)(R * cos(toRadians(vAngle + angleSpan)) * sin(toRadians(hAngle)));
			float z3 = (float)(R * sin(toRadians(vAngle + angleSpan)));

			float s3 = hAngle / 360;
			float t3 = (vAngleLen + angleSpan) / 180;

			// 构建第一个三角形及相应纹理坐标
			vertices.push_back(glm::vec3(x1, y1, z1));
			vertices.push_back(glm::vec3(x3, y3, z3));
			vertices.push_back(glm::vec3(x0, y0, z0));
			texCoords.push_back(glm::vec2(s1, t1));
			texCoords.push_back(glm::vec2(s3, t3));
			texCoords.push_back(glm::vec2(s0, t0));

			// 构建第二个三角形及相应纹理坐标
			vertices.push_back(glm::vec3(x1, y1, z1));
			vertices.push_back(glm::vec3(x2, y2, z2));
			vertices.push_back(glm::vec3(x3, y3, z3));
			texCoords.push_back(glm::vec2(s1, t1));
			texCoords.push_back(glm::vec2(s2, t2));
			texCoords.push_back(glm::vec2(s3, t3));
		}
	}
	numVertices = vertices.size();
}

main.cpp

#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
#include "Sphere.h"
#include "Utils.h"
using namespace std;

#define numVAOs 1
#define numVBOs 2

float cameraX, cameraY, cameraZ;
float sphLocX, sphLocY, sphLocZ;
GLuint renderingProgram;
GLuint vao[numVAOs];
GLuint vbo[numVBOs];
GLuint earthTexture;

// variable allocation for display
GLuint mvLoc, projLoc;
int width, height;
float aspect;
glm::mat4 pMat, vMat, mMat, mvMat, rMat;

Sphere mySphere = Sphere();

void setupVertices(void) {
	std::vector<glm::vec3> vert = mySphere.getVertices();
	std::vector<glm::vec2> tex = mySphere.getTexCoords();

	std::vector<float> vertValues;
	std::vector<float> texValues;

	for (int i = 0; i < mySphere.getNumVertices(); i++) {
		vertValues.push_back(vert[i].x);
		vertValues.push_back(vert[i].y);
		vertValues.push_back(vert[i].z);
		texValues.push_back(tex[i].s);
		texValues.push_back(tex[i].t);
	}

	glGenVertexArrays(1, vao);
	glBindVertexArray(vao[0]);
	glGenBuffers(numVBOs, vbo);

	glBindBuffer(GL_ARRAY_BUFFER, vbo[0]);
	// 注意:sizeof(vector)返回的不是数据块大小,只是对于数组是的。但可通过&vector[0]起始位置访问连续向量空间,
	// 前提是vector中存储的是标量类型的数值,所以对于上面vert,是无法完成功能的,所以要转换为vertValues。
	glBufferData(GL_ARRAY_BUFFER, vertValues.size() * sizeof(float), &vertValues[0], GL_STATIC_DRAW);

	glBindBuffer(GL_ARRAY_BUFFER, vbo[1]);
	glBufferData(GL_ARRAY_BUFFER, texValues.size() * sizeof(float), &texValues[0], GL_STATIC_DRAW);
}

void init(GLFWwindow* window) {
	renderingProgram = Utils::createShaderProgram("vertShader.glsl", "fragShader.glsl");
	cameraX = 0.0f; cameraY = 0.0f; cameraZ = 2.0f;
	sphLocX = 0.0f; sphLocY = 0.0f; sphLocZ = -1.0f;

	glfwGetFramebufferSize(window, &width, &height);
	aspect = (float)width / (float)height;
	pMat = glm::perspective(1.0472f, aspect, 0.1f, 1000.0f);

	setupVertices();
	earthTexture = Utils::loadTexture("earth.jpg");
}

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);

	mvLoc = glGetUniformLocation(renderingProgram, "mv_matrix");
	projLoc = glGetUniformLocation(renderingProgram, "proj_matrix");

	vMat = glm::translate(glm::mat4(1.0f), glm::vec3(-cameraX, -cameraY, -cameraZ));
	mMat = glm::translate(glm::mat4(1.0f), glm::vec3(sphLocX, sphLocY, sphLocZ));
	mvMat = vMat * mMat;

	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);

	glActiveTexture(GL_TEXTURE0);
	glBindTexture(GL_TEXTURE_2D, earthTexture);

	glEnable(GL_CULL_FACE);
	glFrontFace(GL_CCW);

	glDrawArrays(GL_TRIANGLES, 0, mySphere.getNumVertices());
}

void window_size_callback(GLFWwindow* win, int newWidth, int newHeight) {
	aspect = (float)newWidth / (float)newHeight;
	glViewport(0, 0, newWidth, newHeight);
	pMat = glm::perspective(1.0472f, aspect, 0.1f, 1000.0f);
}
int main(void) {
	if (!glfwInit()) { exit(EXIT_FAILURE); }
	glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4);
	glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
	GLFWwindow* window = glfwCreateWindow(600, 600, "My Sphere", NULL, NULL);
	glfwMakeContextCurrent(window);
	if (glewInit() != GLEW_OK) { exit(EXIT_FAILURE); }
	glfwSwapInterval(1);
	glfwSetWindowSizeCallback(window, window_size_callback);
	init(window);
	while (!glfwWindowShouldClose(window)) {
		display(window, glfwGetTime());
		glfwSwapBuffers(window);
		glfwPollEvents();
	}
	glfwDestroyWindow(window);
	glfwTerminate();
	exit(EXIT_SUCCESS);
}

vertShader.glsl

#version 430
layout (location=0) in vec3 pos;
layout (location=1) in vec2 texCoord;
out vec2 tc;
uniform mat4 mv_matrix;
uniform mat4 proj_matrix;
void main(void) {
	gl_Position = proj_matrix * mv_matrix * vec4(pos, 1.0);
	tc = texCoord;
}

fragShader.glsl

#version 430
in vec2 tc;
out vec4 color;
layout (binding=0) uniform sampler2D samp;
void main(void){
	color = texture(samp, tc);
}

运行效果:

OpenGL中的索引

在 C++/OpenGL 中构建 Torus(环面) 类可以用与 Sphere 类几乎完全相同的方式完成。但是,我们有机会利用 OpenGL 对顶点索引的支持来利用我们在构建环面时创建的索引(我们也可以为球体做到这一点,但我们没有这样做)。对于具有数千个顶点的超大型模型,使用OpenGL 索引可以提高性能索引缓冲对象(Element Buffer Object, EBO)相当于OpenGL中的顶点数组的概念,是为了解决同一个顶点多次重复调用的问题,可以减少内存空间浪费,提高执行效率。当需要使用重复的顶点时,通过顶点的位置索引来调用顶点,而不是对重复的顶点信息重复记录,重复调用。我们使用传统的数组绘制(array drawing)方式绘制一个立方体时,可能

以上是关于✠OpenGL-6-3D模型的主要内容,如果未能解决你的问题,请参考以下文章

使用片段时 Intellij 无法正确识别 Thymeleaf 模型变量

php 一个自定义的try..catch包装器代码片段,用于执行模型函数,使其成为一个单行函数调用

如何防止在背面片段导航上再次设置视图模型

Cg入门19:Fragment shader - 片段级模型动态变色

Cg入门20:Fragment shader - 片段级模型动态变色(实现汽车动态换漆)

片段的视图模型