✠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 - 片段级模型动态变色