- 来源:《Computer Graphics Programming in OpenGL Using C++ 》by V Scott
Gordon John L Clevenger - 内容:程序6.1 Sphere,书P135页,PDF153/403
生成
以下将图片贴图到生成的球体形成效果
完整代码
一共有 8 个文件,名字如下:
- 220301 6.1 Sphere.cpp
- 6.1 Shpere.cpp
- 6.1 Shpere.h
- 5.2 Utils.cpp
- 5.2 Utils.h
- 5.2 vertShader.glsl
- 5.2 fragShader.glsl
- brick1.jpg
- 6.1 earth.jpg
220301 6.1 Sphere.cpp
#include <string>
#include <iostream>
#include <fstream>
#include <cmath>
#include "glm\glm.hpp"
#include "glm\gtc\type_ptr.hpp"
#include "glm\gtc\matrix_transform.hpp"
#include "Utils\6.1 Sphere.h"
#include "Utils\5.2 Utils.h"
using namespace std;
#define numVAOs 1
#define numVBOs 3
float cameraX, cameraY, cameraZ;
float pyrLocX, pyrLocY, pyrLocZ;
GLuint renderingProgram;
GLuint vao[numVAOs];
GLuint vbo[numVBOs];
GLuint brickTexture; // 纹理图片ID
// allocate variables used in display() function,
// so that they won’t need to be allocated during rendering
GLuint mvLoc, projLoc;
int width, height;
float aspect;
glm::mat4 pMat, vMat, mMat, mvMat;
Sphere mySphere(48); // 声明一个球的class
void setupVertices(void) {
std::vector<int> ind = mySphere.getIndices(); // 球体点的标注
std::vector<glm::vec3> vert = mySphere.getVertices(); // 球上的顶点
std::vector<glm::vec2> tex = mySphere.getTexCoords(); // 纹理坐标
std::vector<glm::vec3> norm = mySphere.getNormals(); // 球上法向量
std::vector<float> pvalues; // vertex positions 顶点位置
std::vector<float> tvalues; // texture coordinates 纹理坐标
std::vector<float> nvalues; // normal vectors 法向量
int numIndices = mySphere.getNumIndices();
for (int i = 0; i < numIndices; i++) { // 把每一个点上的坐标(x,y,z),纹理坐标(s,t),法向量(a,b,c)存储进对应数组
pvalues.push_back((vert[ind[i]]).x);
pvalues.push_back((vert[ind[i]]).y);
pvalues.push_back((vert[ind[i]]).z);
tvalues.push_back((tex[ind[i]]).s);
tvalues.push_back((tex[ind[i]]).t);
nvalues.push_back((norm[ind[i]]).x);
nvalues.push_back((norm[ind[i]]).y);
nvalues.push_back((norm[ind[i]]).z);
}
glGenVertexArrays(1, vao);
glBindVertexArray(vao[0]);
glGenBuffers(numVBOs, vbo);
// put the vertices into buffer #0 第一个是顶点放入缓存器中
glBindBuffer(GL_ARRAY_BUFFER, vbo[0]);
glBufferData(GL_ARRAY_BUFFER, pvalues.size() * 4, &pvalues[0], GL_STATIC_DRAW);
// put the texture coordinates into buffer #1 第二个是将纹理坐标放入缓存器中
glBindBuffer(GL_ARRAY_BUFFER, vbo[1]);
glBufferData(GL_ARRAY_BUFFER, tvalues.size() * 4, &tvalues[0], GL_STATIC_DRAW);
// put the normals into buffer #2 第三个是将法向量放入缓存器中
glBindBuffer(GL_ARRAY_BUFFER, vbo[2]);
glBufferData(GL_ARRAY_BUFFER, nvalues.size() * 4, &nvalues[0], GL_STATIC_DRAW);
}
void init(GLFWwindow* window) {
renderingProgram = createShaderProgram("add/5.2 vertShader.glsl", "add/5.2 fragShader.glsl");
cameraX = 0.0f; cameraY = 0.0f; cameraZ = 8.0f;
pyrLocX = 1.0f; pyrLocY = -1.0f; pyrLocZ = 0.0f; // shift down Y to reveal perspective
setupVertices();
brickTexture = loadTexture("add/6.1 earth.jpg"); // 加载纹理的图片
}
void display(GLFWwindow* window, double currentTime) {
glClear(GL_DEPTH_BUFFER_BIT);
glUseProgram(renderingProgram);
// get the uniform variables for the MV and projection matrices
mvLoc = glGetUniformLocation(renderingProgram, "mv_matrix");
projLoc = glGetUniformLocation(renderingProgram, "proj_matrix");
// build perspective matrix
glfwGetFramebufferSize(window, &width, &height);
aspect = (float)width / (float)height;
pMat = glm::perspective(1.0472f, aspect, 0.1f, 1000.0f); // 1.0472 radians = 60 degrees
// build view matrix, model matrix, and model-view matrix
vMat = glm::translate(glm::mat4(1.0f), glm::vec3(-cameraX, -cameraY, -cameraZ));
// vbo[0]
mMat = glm::translate(glm::mat4(1.0f), glm::vec3(pyrLocX, pyrLocY, pyrLocZ));
mvMat = vMat * mMat;
// copy perspective and MV matrices to corresponding uniform variables
glUniformMatrix4fv(mvLoc, 1, GL_FALSE, glm::value_ptr(mvMat));
glUniformMatrix4fv(projLoc, 1, GL_FALSE, glm::value_ptr(pMat));
// associate VBO with the corresponding vertex attribute in the vertex shader
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, brickTexture);
// adjust OpenGL settings and draw model
glEnable(GL_DEPTH_TEST);
glDepthFunc(GL_LEQUAL);
glFrontFace(GL_CCW);// 锥体的三角形是逆时针的面认为是正方向
glDrawArrays(GL_TRIANGLES, 0, mySphere.getNumIndices());
}
int main(void) { // main() is unchanged from before
if (!glfwInit()) { exit(EXIT_FAILURE); }
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
GLFWwindow* window = glfwCreateWindow(600, 600, "Chapter 6 - program 1", NULL, NULL);
glfwMakeContextCurrent(window);
if (glewInit() != GLEW_OK) { exit(EXIT_FAILURE); }
glfwSwapInterval(1);
init(window);
while (!glfwWindowShouldClose(window)) {
display(window, glfwGetTime());
glfwSwapBuffers(window);
glfwPollEvents();
}
glfwDestroyWindow(window);
glfwTerminate();
exit(EXIT_SUCCESS);
}
6.1 Shpere.cpp
#include <cmath>
#include <vector>
#include <iostream>
#include <glm\glm.hpp>
#include "6.1 Sphere.h"
using namespace std;
Sphere::Sphere() {
init(48);
}
Sphere::Sphere(int prec) { // prec is precision, or number of slices
init(prec);
}
float Sphere::toRadians(float degrees) { return (degrees * 2.0f * 3.14159f) / 360.0f; }
void Sphere::init(int prec) {
numVertices = (prec + 1) * (prec + 1);
numIndices = prec * prec * 6;
for (int i = 0; i < numVertices; i++) { vertices.push_back(glm::vec3()); } // std::vector::push_back()
for (int i = 0; i < numVertices; i++) { texCoords.push_back(glm::vec2()); } // inserts new element at
for (int i = 0; i < numVertices; i++) { normals.push_back(glm::vec3()); } // the end of a vector and
for (int i = 0; i < numIndices; i++) { indices.push_back(0); } // increases the vector size by 1
// calculate triangle vertices
for (int i = 0; i <= prec; i++) {
for (int j = 0; j <= prec; j++) {
float y = (float)cos(toRadians(180.0f - i * 180.0f / prec));
float x = -(float)cos(toRadians(j*360.0f / prec)) * (float)abs(cos(asin(y)));
float z = (float)sin(toRadians(j*360.0f / prec)) * (float)abs(cos(asin(y)));
vertices[i*(prec + 1) + j] = glm::vec3(x, y, z);
texCoords[i*(prec + 1) + j] = glm::vec2(((float)j / prec), ((float)i / prec));
normals[i*(prec + 1) + j] = glm::vec3(x, y, z);
}
}
// calculate triangle indices
for (int i = 0; i < prec; i++) {
for (int j = 0; j < prec; j++) {
indices[6 * (i*prec + j) + 0] = i * (prec + 1) + j;
indices[6 * (i*prec + j) + 1] = i * (prec + 1) + j + 1;
indices[6 * (i*prec + j) + 2] = (i + 1)*(prec + 1) + j;
indices[6 * (i*prec + j) + 3] = i * (prec + 1) + j + 1;
indices[6 * (i*prec + j) + 4] = (i + 1)*(prec + 1) + j + 1;
indices[6 * (i*prec + j) + 5] = (i + 1)*(prec + 1) + j;
}
}
}
// accessors
int Sphere::getNumVertices() { return numVertices; }
int Sphere::getNumIndices() { return numIndices; }
std::vector<int> Sphere::getIndices() { return indices; }
std::vector<glm::vec3> Sphere::getVertices() { return vertices; }
std::vector<glm::vec2> Sphere::getTexCoords() { return texCoords; }
std::vector<glm::vec3> Sphere::getNormals() { return normals; }
6.1 Shpere.h
#pragma once
#include <cmath>
#include <vector>
#include <glm\glm.hpp>
class Sphere
{
private:
int numVertices;
int numIndices;
std::vector<int> indices;
std::vector<glm::vec3> vertices;
std::vector<glm::vec2> texCoords;
std::vector<glm::vec3> normals;
void init(int);
float toRadians(float degrees);
public:
Sphere();
Sphere(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();
};
5.2 Utils.cpp
#include "Utils/5.2 Utils.h"
#include "GL/glew.h"
#include "GLFW/glfw3.h"
#include "SOIL2/SOIL2.h"
#include <iostream>
#include <string>
#include <fstream>
using namespace std;
GLuint createShaderProgram(const char* a_Path, const char* b_Path) {
GLint vertCompiled;
GLint fragCompiled;
GLint linked;
string vertShaderStr = readShaderSource(a_Path); // 文件在add文件夹中
string fragShaderStr = readShaderSource(b_Path);
const char *vertShaderSrc = vertShaderStr.c_str();
const char *fragShaderSrc = fragShaderStr.c_str();
GLuint vShader = glCreateShader(GL_VERTEX_SHADER);
GLuint fShader = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(vShader, 1, &vertShaderSrc, NULL);
glShaderSource(fShader, 1, &fragShaderSrc, NULL);
// 在编译着色器时,捕捉错误
glCompileShader(vShader);
checkOpenGLError();
glGetShaderiv(vShader, GL_COMPILE_STATUS, &vertCompiled);
if (vertCompiled != 1) {
cout << "vertex compilation failed" << endl;
printShaderLog(vShader);
}
glCompileShader(fShader);
checkOpenGLError();
glGetShaderiv(fShader, GL_COMPILE_STATUS, &fragCompiled);
if (fragCompiled != 1) {
cout << "fragment compilation failed" << endl;
printShaderLog(fShader);
}
GLuint vfProgram = glCreateProgram();
glAttachShader(vfProgram, vShader);
glAttachShader(vfProgram, fShader);
glLinkProgram(vfProgram);
checkOpenGLError();
glGetProgramiv(vfProgram, GL_LINK_STATUS, &linked);
if (linked != 1) {
cout << "linking failed" << endl;
printProgramLog(vfProgram);
}
return vfProgram;
}
string readShaderSource(const char *filePath) {
string content;
ifstream fileStream(filePath, ios::in);
string line = "";
while (!fileStream.eof()) {
getline(fileStream, line);
content.append(line + "\n");
}
fileStream.close();
return content;
}
bool checkOpenGLError() {
bool foundError = false;
int glErr = glGetError();
while (glErr != GL_NO_ERROR) {
cout << "glError: " << glErr << endl;
foundError = true;
glErr = glGetError();
}
return foundError;
}
void printProgramLog(int prog) {
int len = 0;
int chWrittn = 0;
char *log;
glGetProgramiv(prog, GL_INFO_LOG_LENGTH, &len);
if (len > 0) {
log = (char *)malloc(len);
glGetProgramInfoLog(prog, len, &chWrittn, log);
cout << "Program Info Log: " << log << endl;
free(log);
}
}
void printShaderLog(GLuint shader) {
int len = 0;
int chWrittn = 0;
char *log;
glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &len);
if (len > 0) {
log = (char *)malloc(len);
glGetShaderInfoLog(shader, len, &chWrittn, log);
cout << "Shader Info Log: " << log << endl;
free(log);
}
}
GLuint loadTexture(const char *texImagePath) {
GLuint textureID;
textureID = SOIL_load_OGL_texture(texImagePath,
SOIL_LOAD_AUTO, SOIL_CREATE_NEW_ID, SOIL_FLAG_INVERT_Y);
if (textureID == 0) cout << "could not find texture file" << texImagePath << endl;
// mipmaps
glBindTexture(GL_TEXTURE_2D, textureID);
不倒置也不镜像——多选一
//glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
//glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
倒置+镜像——多选一
//glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_MIRRORED_REPEAT);
//glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_MIRRORED_REPEAT);
仅有一个,其余颜色为红色——多选一
//glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER);
//glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER);
//float redColor[4] = { 1.0f, 0.0f, 0.0f, 1.0f };
//glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, redColor);
// 仅有一个,其余为图片最边缘一行一列的颜色拓展——多选一
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glGenerateMipmap(GL_TEXTURE_2D);
// if also anisotropic filtering
if (glewIsSupported("GL_EXT_texture_filter_anisotropic")) {
GLfloat anisoSetting = 0.0f;
glGetFloatv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &anisoSetting);
//glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, anisoSetting);
}
return textureID;
}
5.2 Utils.h
#pragma once
#ifndef UTILS_H
#define UTILS_H
#include <string>
#include "GL\glew.h"
#include "GLFW\glfw3.h"
using namespace std;
GLuint createShaderProgram(const char* a_Path, const char* b_Path);
string readShaderSource(const char *filePath);
bool checkOpenGLError();
void printProgramLog(int prog);
void printShaderLog(GLuint shader);
GLuint loadTexture(const char *texImagePath);
#endif // !UTILS_H
5.2 vertShader.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; // not used in vertex shader
void main(void)
{ gl_Position = proj_matrix * mv_matrix * vec4(pos,1.0);
tc = texCoord;
}
5.2 fragShader.glsl
#version 430
in vec2 tc; // interpolated incoming texture coordinate
out vec4 color;
uniform mat4 mv_matrix;
uniform mat4 proj_matrix;
layout (binding=0) uniform sampler2D samp;
void main(void)
{ color = texture(samp, tc);
}