0
点赞
收藏
分享

微信扫一扫

openGL绘制地球

openGL系列文章目录

前言

某些类型的对象(例如球体、圆锥体等)具有数学定义,这些定义有助于算法生成。例
如,对于半径为R 的圆,围绕其圆周的点的坐标可以被很好地定义
openGL绘制地球_glm
图1

我们可以系统地使用圆的几何知识来通过算法建立球体模型。我们的策略如下。
(1)在整个球体上,选择表示一系列圆形“水平切片”的精度。见图2 的左侧。
(2)将每个圆形切片的圆周细分为若干个点。见图6.2 的右侧。更多的点和水平切片可
以生成更精确、更平滑的球体模型。在我们的模型中,每个切片将具有相同数量的点。
(3)将顶点分组为三角形。一种方法是逐步遍历顶点,在每一步构建两个三角形。例如,
当我们沿着图6.3 中球体上5 个彩色顶点这一行移动时,对于这5 个顶点中的每一个,我们构建了以相应颜色显示的两个三角形

openGL绘制地球_openGL绘制地球_02

一、代码

#include "glew/glew.h"
#include "glfw/glfw3.h"
#include "glm/glm.hpp"
#include "glm/gtc/matrix_transform.hpp"
#include "glm/gtc/type_ptr.hpp"
#include "Sphere.h"
#include "Utils.h"
#include <iostream>
#include <fstream>
#include <string>

using namespace std;

static const int screen_width = 1920;
static const int screen_height = 1080;

int width = 0, height = 0;
float aspect = 0.f;
float cameraX = 0.f, cameraY = 0.f, cameraZ = 0.f;
float sphereLocX = 0.f, spherelocY = 0.f, sphereLocZ = 0.f;

GLuint renderingProgram = 0;
static const int numberVAOs = 1;
static const int numberVBOs = 3;
GLuint vao[numberVAOs] = { 0 };
GLuint vbo[numberVBOs] = { 0 };

glm::mat4 mMat(1.f), vMat(1.f), mvMat(1.f), pMat(1.f);
int mvLoc = 0;
int projLoc = 0;
float rotAmt = 0.f;

GLuint earthTextureId = 0;

Sphere earth = Sphere(48);

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

vector<float> pValues;
vector<float> tValues;
vector<float> nValues;

int numIndices = earth.getNumIndices();
for (int i=0; i<numIndices; i++)
{
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(numberVAOs, vao);
glBindVertexArray(vao[0]);

glGenBuffers(numberVBOs, 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);
}

void init(GLFWwindow* window)
{
renderingProgram = Utils::createShaderProgram("vertShader.glsl", "fragShader.glsl");
cameraX = 0.f, cameraY = 0.f, cameraZ = 6.f;
sphereLocX = 0.f, spherelocY = 0.f, sphereLocZ = 0.f;
glfwGetFramebufferSize(window, &width, &height);

//屏幕坐标和窗口的帧缓冲
/*GLFW在这里和这里解释文档中的两个坐标系。
简而言之,窗口坐标是相对于监视器和 / 或窗口的,并且以不一定对应于真实屏幕像素的人造单元给出。 当DPI缩放被激活时(例如,在带有视网膜显示器的Mac上),情况尤其如此。
与窗口坐标相比,帧缓冲区的大小与像素相关,以便与glViewport OpenGLs要求相匹配。
请注意,在某些系统上,窗口坐标和像素坐标可以相同,但这不一定是正确的。*/
aspect = (float)width / (float)height;
pMat = glm::perspective(glm::radians(45.f), aspect, 0.01f, 1000.f);

setupVertices();

earthTextureId = Utils::loadTexture("resource/earth.jpg");
}

void display(GLFWwindow* window, float currentTime)
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glClearColor(0.1f, 0.2f, 1.f, 1.f);

//必不可少!!!否则窗口是黑的,不会渲染任何东西
glUseProgram(renderingProgram);

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

//移动相机矩阵:这里必须是-cameraZ,否则相机看不到球体
vMat = glm::translate(glm::mat4(1.f), glm::vec3(cameraX, cameraY, -cameraZ));
mMat = glm::translate(glm::mat4(1.f), glm::vec3(sphereLocX, spherelocY, sphereLocZ));
mMat = glm::rotate(glm::mat4(1.f), currentTime * 0.5f, glm::vec3(0.f, 1.f, 0.f));


//右乘规则
//mvMat = mMat * vMat; //金字塔会离开视口
mvMat = vMat * mMat;

//更改一个uniform矩阵变量或数组的值。要更改的uniform变量的位置由location指定,location的值应该由glGetUniformLocation函数返回
// 将透视矩阵和MV 矩阵复制给相应的统一变量
/*通过一致变量(uniform修饰的变量)引用将一致变量值传入渲染管线。
location : uniform的位置。
count : 需要加载数据的数组元素的数量或者需要修改的矩阵的数量。
transpose : 指明矩阵是列优先(column major)矩阵(GL_FALSE)还是行优先(row major)矩阵(GL_TRUE)。
value : 指向由count个元素的数组的指针。
*/
glUniformMatrix4fv(mvLoc, 1, GL_FALSE, glm::value_ptr(mvMat));
glUniformMatrix4fv(projLoc, 1, GL_FALSE, glm::value_ptr(pMat));

//绑定到球体顶点缓冲区
glBindBuffer(GL_ARRAY_BUFFER, vbo[0]);
//指定了渲染时索引值为 index 的顶点属性数组的数据格式和位置
/*Parameters
index
指定要修改的顶点属性的索引值

size
指定每个顶点属性的组件数量。必须为1、2、3或者4。初始值为4。(梦维:如position是由3个(x, y, z)组成,而颜色是4个(r, g, b, a))

type
指定数组中每个组件的数据类型。可用的符号常量有GL_BYTE, GL_UNSIGNED_BYTE, GL_SHORT, GL_UNSIGNED_SHORT, GL_FIXED, 和 GL_FLOAT,初始值为GL_FLOAT。

normalized
指定当被访问时,固定点数据值是否应该被归一化(GL_TRUE)或者直接转换为固定点值(GL_FALSE)。

stride
指定连续顶点属性之间的偏移量。如果为0,那么顶点属性会被理解为:它们是紧密排列在一起的。初始值为0。

pointer
指定一个指针,指向数组中第一个顶点属性的第一个组件。初始值为0。*/
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0);
//启用或禁用通用顶点属性数组,参数0索引和着色器中的layout(location = 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, earthTextureId);

//背面剔除,默认情况下,背面剔除是关闭的
glEnable(GL_CULL_FACE);
glFrontFace(GL_CCW);

glDrawArrays(GL_TRIANGLES, 0, earth.getNumIndices());
//glDrawArrays(GL_TRIANGLES, 0, earth.getNumVertices());
}

void window_size_callback(GLFWwindow* window, int newWidth, int newHeight)
{
glViewport(0, 0, newWidth, newHeight);
aspect = (float)newWidth / (float)newHeight;
pMat = glm::perspective(glm::radians(45.f), aspect, 0.01f, 1000.f);
}

int main(int argc, char** argv)
{
int glfwState = glfwInit();
if (GLFW_FALSE == glfwState)
{
cout << "GLFW initialize failed,invoke glfwInit()......Error file:" << __FILE__ << "......Error line:" << __LINE__ << endl;
glfwTerminate();
exit(EXIT_FAILURE);
}

glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 6);
glfwWindowHint(GLFW_OPENGL_CORE_PROFILE, GLFW_OPENGL_PROFILE);
glfwWindowHint(GLFW_RESIZABLE, GL_TRUE);

GLFWwindow* window = glfwCreateWindow(screen_width, screen_height, "Sphere Draw", nullptr, nullptr);
if (!window)
{
cout << "GLFW create window failed,invoke glfwCreateWindow()......Error file:" << __FILE__ << "......Error line:" << __LINE__ << endl;
glfwTerminate();
exit(EXIT_FAILURE);
}

glfwMakeContextCurrent(window);

glfwSetWindowSizeCallback(window, window_size_callback);

glfwSwapInterval(1);

int glewState = glewInit();
if (GLEW_OK != glewState)
{
cout << "GLEW initialize failed,invoke glewInit()......Error file:" << __FILE__ << "......Error line:" << __LINE__ << endl;
glfwTerminate();
exit(EXIT_FAILURE);
}

init(window);

while (!glfwWindowShouldClose(window))
{
display(window, (float)glfwGetTime());
glfwSwapBuffers(window);
glfwPollEvents();
}

glfwDestroyWindow(window);
glfwTerminate();
exit(EXIT_SUCCESS);

return 0;
}

顶点着色器

#version 460 core

layout(location = 0) in vec3 position;
layout(location = 1) in vec2 texCoords;

uniform mat4 mv_matrix;
uniform mat4 proj_matrix;

//uniform sampler2D samp;
layout (binding = 0) uniform sampler2D samp;

//out vec4 color;
out vec2 tc;

void main()
{
gl_Position = proj_matrix * mv_matrix * vec4(position, 1.f);
tc = texCoords;
}

片元着色器

#version 460 core

in vec2 tc;
out vec4 color;

uniform mat4 mv_matrix;
uniform mat4 proj_matrix;

layout(binding = 0) uniform sampler2D samp;

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

二、运行效果

openGL绘制地球_#include_03

源码下载

​​源码工程下载​​


举报

相关推荐

0 条评论