配置OpenGL环境看上一篇文章
效果图:
main.cpp:
#include "Dependencies/glew/glew.h"
#include "Dependencies/GLFW/glfw3.h"
#include "Dependencies/glm/glm.hpp"
#include "Dependencies/glm/gtc/matrix_transform.hpp"
#include <iostream>
#include <fstream>
#include <vector>
#include <math.h>
GLint programID;
unsigned int VBO, VAO, EBO;
const unsigned int SCR_WIDTH = 1200;
const unsigned int SCR_HEIGHT = 1200;
const GLfloat PI = 3.14159265358979323846f;
//将球横纵划分成50X50的网格
const int Y_SEGMENTS = 50;
const int X_SEGMENTS = 50;
void get_OpenGL_info() {
// OpenGL information
const GLubyte* name = glGetString(GL_VENDOR);
const GLubyte* renderer = glGetString(GL_RENDERER);
const GLubyte* glversion = glGetString(GL_VERSION);
std::cout << "OpenGL company: " << name << std::endl;
std::cout << "Renderer name: " << renderer << std::endl;
std::cout << "OpenGL version: " << glversion << std::endl;
}
bool checkStatus(
GLuint objectID,
PFNGLGETSHADERIVPROC objectPropertyGetterFunc,
PFNGLGETSHADERINFOLOGPROC getInfoLogFunc,
GLenum statusType)
{
GLint status;
objectPropertyGetterFunc(objectID, statusType, &status);
if (status != GL_TRUE)
{
GLint infoLogLength;
objectPropertyGetterFunc(objectID, GL_INFO_LOG_LENGTH, &infoLogLength);
GLchar* buffer = new GLchar[infoLogLength];
GLsizei bufferSize;
getInfoLogFunc(objectID, infoLogLength, &bufferSize, buffer);
std::cout << buffer << std::endl;
delete[] buffer;
return false;
}
return true;
}
bool checkShaderStatus(GLuint shaderID) {
return checkStatus(shaderID, glGetShaderiv, glGetShaderInfoLog, GL_COMPILE_STATUS);
}
bool checkProgramStatus(GLuint programID) {
return checkStatus(programID, glGetProgramiv, glGetProgramInfoLog, GL_LINK_STATUS);
}
std::string readShaderCode(const char* fileName) {
std::ifstream meInput(fileName);
if (!meInput.good()) {
std::cout << "File failed to load ... " << fileName << std::endl;
exit(1);
}
return std::string(
std::istreambuf_iterator<char>(meInput),
std::istreambuf_iterator<char>()
);
}
void installShaders() {
GLuint vertexShaderID = glCreateShader(GL_VERTEX_SHADER);
GLuint fragmentShaderID = glCreateShader(GL_FRAGMENT_SHADER);
const GLchar* adapter[1];
//adapter[0] = vertexShaderCode;
std::string temp = readShaderCode("VertexShaderCode.glsl");
adapter[0] = temp.c_str();
glShaderSource(vertexShaderID, 1, adapter, 0);
//adapter[0] = fragmentShaderCode;
temp = readShaderCode("FragmentShaderCode.glsl");
adapter[0] = temp.c_str();
glShaderSource(fragmentShaderID, 1, adapter, 0);
glCompileShader(vertexShaderID);
glCompileShader(fragmentShaderID);
if (!checkShaderStatus(vertexShaderID) || !checkShaderStatus(fragmentShaderID))
return;
programID = glCreateProgram();
glAttachShader(programID, vertexShaderID);
glAttachShader(programID, fragmentShaderID);
glLinkProgram(programID);
if (!checkProgramStatus(programID))
return;
glDeleteShader(vertexShaderID);
glDeleteShader(fragmentShaderID);
glUseProgram(programID);
}
void sendDataToOpenGL() {
// TODO:
// create 2D objects and 3D objects and/or lines (points) here and bind to VAOs & VBOs
std::vector<float> sphereVertices;
std::vector<int> sphereIndices;
// 生成球的顶点
for (int y = 0; y <= Y_SEGMENTS; y++)
{
for (int x = 0; x <= X_SEGMENTS; x++)
{
float xSegment = (float)x / (float)X_SEGMENTS;
float ySegment = (float)y / (float)Y_SEGMENTS;
float xPos = std::cos(xSegment * 2.0f * PI) * std::sin(ySegment * PI);
float yPos = std::cos(ySegment * PI);
float zPos = std::sin(xSegment * 2.0f * PI) * std::sin(ySegment * PI);
sphereVertices.push_back(xPos);
sphereVertices.push_back(yPos);
sphereVertices.push_back(zPos);
}
}
// 生成球的Indices
for (int i = 0; i < Y_SEGMENTS; i++)
{
for (int j = 0; j < X_SEGMENTS; j++)
{
sphereIndices.push_back(i * (X_SEGMENTS + 1) + j);
sphereIndices.push_back((i + 1) * (X_SEGMENTS + 1) + j);
sphereIndices.push_back((i + 1) * (X_SEGMENTS + 1) + j + 1);
sphereIndices.push_back(i * (X_SEGMENTS + 1) + j);
sphereIndices.push_back((i + 1) * (X_SEGMENTS + 1) + j + 1);
sphereIndices.push_back(i * (X_SEGMENTS + 1) + j + 1);
}
}
glGenVertexArrays(1, &VAO);
glGenBuffers(1, &VBO);
glGenBuffers(1, &EBO);
glBindVertexArray(VAO);
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glBufferData(GL_ARRAY_BUFFER, sphereVertices.size() * sizeof(float), &sphereVertices[0], GL_STATIC_DRAW);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0); // because the vertex data is tightly packed we can also specify 0 as the vertex attribute's stride to let OpenGL figure it out
glEnableVertexAttribArray(0);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sphereIndices.size() * sizeof(int), &sphereIndices[0], GL_STATIC_DRAW);
}
void paintGL(void) {
// always run
// TODO:
// render your objects and control the transformation here
glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glm::mat4 projection = glm::mat4(1.0f);
glm::mat4 model = glm::mat4(1.0f);
glm::mat4 view = glm::mat4(1.0f);
glUniformMatrix4fv(glGetUniformLocation(programID, "projection"), 1, GL_FALSE, &projection[0][0]);
glUniformMatrix4fv(glGetUniformLocation(programID, "view"), 1, GL_FALSE, &view[0][0]);
glUniformMatrix4fv(glGetUniformLocation(programID, "model"), 1, GL_FALSE, &model[0][0]);
glEnable(GL_CULL_FACE);
glCullFace(GL_BACK);
glBindVertexArray(VAO);
//使用线框模式绘制
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
glDrawElements(GL_TRIANGLES, X_SEGMENTS * Y_SEGMENTS * 6, GL_UNSIGNED_INT, 0);
}
void framebuffer_size_callback(GLFWwindow* window, int width, int height) {
glViewport(0, 0, width, height);
}
void initializedGL(void) {
// run only once
// TODO:
sendDataToOpenGL();
installShaders();
glEnable(GL_DEPTH_TEST);
}
int main(int argc, char* argv[]) {
GLFWwindow* window;
/* Initialize the glfw */
if (!glfwInit()) {
std::cout << "Failed to initialize GLFW" << std::endl;
return -1;
}
/* glfw: configure; necessary for MAC */
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
#ifdef __APPLE__
glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
#endif
/* do not allow resizing */
glfwWindowHint(GLFW_RESIZABLE, GL_FALSE);
/* Create a windowed mode window and its OpenGL context */
window = glfwCreateWindow(SCR_WIDTH, SCR_HEIGHT, "Assignment 1", NULL, NULL);
if (!window) {
std::cout << "Failed to create GLFW window" << std::endl;
glfwTerminate();
return -1;
}
/* Make the window's context current */
glfwMakeContextCurrent(window);
glfwSetFramebufferSizeCallback(window, framebuffer_size_callback);
/* Initialize the glew */
if (GLEW_OK != glewInit()) {
std::cout << "Failed to initialize GLEW" << std::endl;
return -1;
}
get_OpenGL_info();
initializedGL();
/* Loop until the user closes the window */
while (!glfwWindowShouldClose(window)) {
/* Render here */
paintGL();
/* Swap front and back buffers */
glfwSwapBuffers(window);
/* Poll for and process events */
glfwPollEvents();
}
glfwTerminate();
return 0;
}
顶点着色器:
#version 330 core
layout (location = 0) in vec3 aPos;
void main()
{
gl_Position = vec4(aPos, 1.0);
}
片段着色器:
#version 330 core
out vec4 FragColor;
void main()
{
FragColor = vec4(1.0,0.635,0.345,1.0);
}
想画的更圆可以通过增大全局变量Y_SEGMENTS和X_SEGMENTS
下面是100时的效果
要给球体上颜色的话,每次生成顶点时要压入三个颜色的比例值,同时在顶点着色器中加入颜色输入值,下面是修改部分:
for (int y = 0; y <= Y_SEGMENTS; y++)
{
for (int x = 0; x <= X_SEGMENTS; x++)
{
float xSegment = (float)x / (float)X_SEGMENTS;
float ySegment = (float)y / (float)Y_SEGMENTS;
float xPos = std::cos(xSegment * 2.0f * PI) * std::sin(ySegment * PI);
float yPos = std::cos(ySegment * PI);
float zPos = std::sin(xSegment * 2.0f * PI) * std::sin(ySegment * PI);
//压入顶点坐标
sphereVertices.push_back(xPos);
sphereVertices.push_back(yPos);
sphereVertices.push_back(zPos);
//压入颜色
sphereVertices.push_back(sin(xPos) / 2 + 0.5);
sphereVertices.push_back(sin(yPos) / 2 + 0.5);
sphereVertices.push_back(sin(zPos) / 2 + 0.5);
}
}
同时将颜色传入顶点着色器中,注意偏移值要改成6
glBindVertexArray(VAO);
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glBufferData(GL_ARRAY_BUFFER, sphereVertices.size() * sizeof(float), &sphereVertices[0], GL_STATIC_DRAW);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(float), (void*)0);
glEnableVertexAttribArray(0);
//新增两行
glEnableVertexAttribArray(1);
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(float), (char*)(3 * sizeof(float)));
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sphereIndices.size() * sizeof(int), &sphereIndices[0], GL_STATIC_DRAW);
绘线模式去除
glBindVertexArray(VAO);
glDrawElements(GL_TRIANGLES, X_SEGMENTS * Y_SEGMENTS * 6, GL_UNSIGNED_INT, 0);
顶点着色器:
#version 330 core
layout (location = 0) in vec3 aPos;
layout (location = 1) in vec3 aColor;
out vec3 ourColor;
void main()
{
gl_Position = vec4(aPos, 1.0);
ourColor = aColor ;
}
片段着色器:
#version 330 core
out vec4 FragColor;
in vec3 ourColor;
void main()
{
FragColor = vec4(ourColor,1.0);
}
效果图:
版权声明:本文为qq_51684393原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。