openGL绘制带纹理太阳、地球、月亮,并且地球自转并且围绕太阳旋转。月亮自转也会围绕地球旋转

openGL系列文章目录

前言

  使用openGL绘制太阳、地球、月亮,太阳自转,地球自转并且围绕太阳旋转。月亮自转也会围绕地球旋转,其实月亮也会围绕太阳旋转的。

一、效果

在这里插入图片描述
还是有不满意的地方:
1.没有添加星空盒子
如果加上星空背景效果会好很多
2.贴图是我自己ps的,在太阳和月亮上有重合问题

二、实现思路

1.太阳、地球、月亮使用球体代替
2.我们的行星地球围绕太阳旋转的方式,以及月球围绕地球旋转的方式。
使用矩阵堆栈轻松地完成此操作。顾名思义,矩阵堆栈是一堆变换
矩阵。正如我们将看到的,矩阵堆栈使得创建和管理复杂的分层对象和场景变得容易,它
使得变换可以构建在其他变换之上(或者从其他变换中被移除)。
3. 太阳、地球、月亮纹理贴图

主要代码

main.cpp主程序


#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 "Utils.h"
#include "Sphere.h"
#include "camera.h"
#include <iostream>
#include <string>
#include <fstream>
#include <vector>
#include <stack>

using namespace std;

static const int screen_width = 1920;
static const int screen_height = 1080;
int width = 0;
int height = 0;

GLuint renderingProgram = 0;

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

float cameraLocX = 0.f, cameraLocY = 0.f, cameraLocZ = 0.f;
float sunLocX = 0.f, sunLocY = 0.f, sunLocZ = 0.f;
float earthLocX = 0.f, earthLocY = 0.f, earthLocZ = 0.f;
float moonLocX = 0.f, moonLocY = 0.f, moonLocZ = 0.f;
float aspect = 0.f;
int mvLoc = 0;
int projLoc = 0;
float rotAmt = 0.f;

glm::mat4 mMat(1.f), vMat(1.f), pMat(1.f), mvMat(1.f);

//vector<glm::mat4> mvStack;

GLuint sunTextureId = 0, earthTextureId = 0, moonTextureId = 0;

Sphere sun = Sphere(48);
Sphere earth = Sphere(48);
Sphere moon = Sphere(48);

GLboolean keys[1024] = { GL_FALSE };

Camera camera(glm::vec3(0.f, 0.f, 5.f));
GLfloat lastFrame = 0.0f;
GLfloat deltaTime = 0.0f;

GLboolean firstMouse = GL_TRUE;
GLfloat lastX = 0.f;
GLfloat lastY = 0.f;

std::stack<glm::mat4> mvStack;  //注意不要和vsctor<glm::mat4>相混淆


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

	vector<float> pValues;   //顶点位置
	vector<float> tValues;   //纹理坐标
	vector<float> nValues;   //法线向量

	int numIndices = sun.getNumIndices();
	for (int i = 0; i < numIndices; i++)
	{
		//pValues.push_back(vert[ind[i]].x);
		pValues.push_back((vert[ind[i]]).x);
		pValues.push_back((vert[ind[i]]).y);
		pValues.push_back((vert[ind[i]]).z);

		tValues.push_back((text[ind[i]]).s);
		tValues.push_back((text[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]);
	size_t sizeFloat = sizeof(float);
	glBufferData(GL_ARRAY_BUFFER, pValues.size() * sizeof(float), &(pValues[0]), GL_STATIC_DRAW);

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

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

void press_key_callback(GLFWwindow* window, int key, int scancode, int action, int mode)
{
	if ((key == GLFW_KEY_ESCAPE) && (action == GLFW_PRESS))
	{
		glfwSetWindowShouldClose(window, GL_TRUE);
	}
	if (action == GLFW_PRESS)
	{
		keys[key] = GL_TRUE;
	}
	else if (action == GLFW_RELEASE)
	{
		//glfwSetWindowShouldClose(window, GL_FALSE);
		keys[key] = GL_FALSE;
	}
}

void key_movement_callback()
{
	if (keys[GLFW_KEY_W])
	{
		camera.ProcessKeyboard(FORWARD, deltaTime);
	}
	if (keys[GLFW_KEY_S])
	{
		camera.ProcessKeyboard(BACKWARD, deltaTime);
	}
	if (keys[GLFW_KEY_A])
	{
		camera.ProcessKeyboard(LEFT, deltaTime);
	}
	if (keys[GLFW_KEY_D])
	{
		camera.ProcessKeyboard(RIGHT, deltaTime);
	}
}

void mouse_move_callback(GLFWwindow* window, double xPos, double yPos)
{
	if (firstMouse)
	{
		lastX = xPos;
		lastY = yPos;
		firstMouse = GL_FALSE;
	}

	GLfloat xOffset = xPos - lastX;
	GLfloat yOffset = lastY - yPos;

	lastX = xPos;
	lastY = yPos;

	camera.ProcessMouseMovement(xOffset, yOffset);
}

void scroll_callback(GLFWwindow* window, double xPos, double yPos)
{
	camera.ProcessMouseScroll(xPos);
}

void init(GLFWwindow* window)
{
	renderingProgram = Utils::createShaderProgram("vertShader.glsl", "fragShader.glsl");
	glfwGetFramebufferSize(window, &width, &height);
	aspect = (float)width / (float)height;
	pMat = glm::perspective(glm::radians(45.f), aspect, 0.01f, 1000.f);
	glfwGetFramebufferSize(window, &width, &height);


	setupVertices();

	sunTextureId = Utils::loadTexture("resource/shining.jpg");
	earthTextureId = Utils::loadTexture("resource/earth.jpg");
	moonTextureId = Utils::loadTexture("resource/moon.jpg");
}


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

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

	GLfloat currentTimeFrame = glfwGetTime();
	deltaTime = currentTimeFrame - lastFrame;
	lastFrame = currentTimeFrame;

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

	key_movement_callback();

	//移动相机矩阵:这里必须是-cameraZ,否则相机看不到球体
	//vMat = glm::translate(glm::mat4(1.f), glm::vec3(cameraX, cameraY, -cameraZ));
	vMat = camera.GetViewMatrix();
	/*sunLocZ = -6.f;*/
	mMat = glm::translate(glm::mat4(1.f), glm::vec3(sunLocX, sunLocY, sunLocZ));
	mMat = glm::rotate(glm::mat4(1.f), currentTime * 0.1f, glm::vec3(0.f, 1.f, 0.f));
	pMat = glm::perspective(camera.Zoom, (GLfloat)screen_width / (GLfloat)screen_height, 0.01f, 1000.f);

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

	//将视图矩阵压入堆栈
	mvStack.push(vMat);

	//更改一个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));

	// ----------------------  sun
	/*堆栈顶部的矩阵复制一份,并和其他的变换结合,然后再利用这个命令把新的矩阵副本推入堆栈中。
	*/
	mvStack.push(mvStack.top());
	//向矩阵堆栈顶部的矩阵添加平移
	mvStack.top() *= glm::translate(glm::mat4(1.f), glm::vec3(0.f, 0.f, 0.f));
	mvStack.push(mvStack.top());
	//在不移除的情况下,返回堆栈最顶部旋转矩阵(绕X轴)的引用。
	mvStack.top() *= glm::rotate(glm::mat4(1.f), (float)glfwGetTime() * 0.4f, glm::vec3(0.f, 1.f, 0.f));
	glUniformMatrix4fv(mvLoc, 1, GL_FALSE, glm::value_ptr(mvStack.top()));

	//绑定到太阳顶点缓冲区
	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, sunTextureId);

	/*glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_NEAREST_MIPMAP_NEAREST);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_NEAREST_MIPMAP_NEAREST);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_R, GL_NEAREST_MIPMAP_NEAREST);
	glBindTexture(GL_TEXTURE_2D, sunTextureId);*/

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

	glDrawArrays(GL_TRIANGLES, 0, sun.getNumIndices());
	mvStack.pop();


	/**********************************   earth           */
	//复制一份堆栈顶部矩阵压入堆栈
	/*push():在堆栈顶部创建一个新的条目。我们通常会把目前在堆栈顶部的矩阵复制一份,
	  并和其他的变换结合,然后再利用这个命令把新的矩阵副本推入堆栈中。
	*/
	//top():在不移除的情况下,返回堆栈最顶部矩阵的引用。
	mvStack.push(mvStack.top());
	mvStack.top() *= glm::translate(glm::mat4(1.f), glm::vec3(glm::sin((float)currentTime) * 2.5f, glm::cos((float)currentTime) * 0.4, glm::cos((float)currentTime) * 0.5f));
	mvStack.push(mvStack.top());
	//地球绕太阳旋转,即绕Y轴旋转
	mvStack.top() *= glm::rotate(glm::mat4(1.f), (float)currentTime, glm::vec3(0.f, 1.f, 0.f));
	mvStack.top() *= glm::scale(glm::mat4(1.f), glm::vec3(0.4f));
	//更改一个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(mvStack.top()));
	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);

	//绑定到地球纹理坐标缓冲区
	glActiveTexture(GL_TEXTURE0);
	glBindTexture(GL_TEXTURE_2D, earthTextureId);
	//背面剔除,默认情况下,背面剔除是关闭的
	glEnable(GL_CULL_FACE);
	glFrontFace(GL_CCW);

	glEnable(GL_DEPTH_TEST);
	glDepthFunc(GL_LEQUAL);
	glDrawArrays(GL_TRIANGLES, 0, earth.getNumIndices());
	mvStack.pop();
	mvStack.pop();


	/****************************************   moon */
	//复制一份堆栈顶部矩阵压入堆栈
	/*push():在堆栈顶部创建一个新的条目。我们通常会把目前在堆栈顶部的矩阵复制一份,
	  并和其他的变换结合,然后再利用这个命令把新的矩阵副本推入堆栈中。
	*/
	//top():在不移除的情况下,返回堆栈最顶部矩阵的引用。
	mvStack.push(mvStack.top());
	mvStack.top() *= glm::translate(glm::mat4(1.f), glm::vec3(glm::sin((float)currentTime) * 3.f, glm::cos((float)currentTime) * 0.8f, glm::cos((float)currentTime) * 3.0f));
	mvStack.push(mvStack.top());
	//月球绕地球旋转,即绕Y轴旋转
	mvStack.top() *= glm::rotate(glm::mat4(1.f), (float)currentTime * 4.f, glm::vec3(0.f, 1.f, 0.f));
	mvStack.top() *= glm::scale(glm::mat4(1.f), glm::vec3(0.2f));
	//更改一个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(mvStack.top()));
	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);
	//绑定到地球纹理坐标缓冲区
	glActiveTexture(GL_TEXTURE0);
	glBindTexture(GL_TEXTURE_2D, moonTextureId);

	//背面剔除,默认情况下,背面剔除是关闭的
	glEnable(GL_CULL_FACE | GL_DEPTH_TEST);
	glFrontFace(GL_CCW);
	glDepthFunc(GL_LEQUAL);
	glDrawArrays(GL_TRIANGLES, 0, moon.getNumIndices());
	mvStack.pop();
	mvStack.pop();
	mvStack.pop();


	星空盒
	//GLfloat skyboxVertices[] = {
	//	// Positions          
	//	-1.0f,  1.0f, -1.0f,
	//	-1.0f, -1.0f, -1.0f,
	//	1.0f, -1.0f, -1.0f,
	//	1.0f, -1.0f, -1.0f,
	//	1.0f,  1.0f, -1.0f,
	//	-1.0f,  1.0f, -1.0f,

	//	-1.0f, -1.0f,  1.0f,
	//	-1.0f, -1.0f, -1.0f,
	//	-1.0f,  1.0f, -1.0f,
	//	-1.0f,  1.0f, -1.0f,
	//	-1.0f,  1.0f,  1.0f,
	//	-1.0f, -1.0f,  1.0f,

	//	1.0f, -1.0f, -1.0f,
	//	1.0f, -1.0f,  1.0f,
	//	1.0f,  1.0f,  1.0f,
	//	1.0f,  1.0f,  1.0f,
	//	1.0f,  1.0f, -1.0f,
	//	1.0f, -1.0f, -1.0f,

	//	-1.0f, -1.0f,  1.0f,
	//	-1.0f,  1.0f,  1.0f,
	//	1.0f,  1.0f,  1.0f,
	//	1.0f,  1.0f,  1.0f,
	//	1.0f, -1.0f,  1.0f,
	//	-1.0f, -1.0f,  1.0f,

	//	-1.0f,  1.0f, -1.0f,
	//	1.0f,  1.0f, -1.0f,
	//	1.0f,  1.0f,  1.0f,
	//	1.0f,  1.0f,  1.0f,
	//	-1.0f,  1.0f,  1.0f,
	//	-1.0f,  1.0f, -1.0f,

	//	-1.0f, -1.0f, -1.0f,
	//	-1.0f, -1.0f,  1.0f,
	//	1.0f, -1.0f, -1.0f,
	//	1.0f, -1.0f, -1.0f,
	//	-1.0f, -1.0f,  1.0f,
	//	1.0f, -1.0f,  1.0f
	//};

	//GLuint skyboxVAO, skyboxVBO;
	//glGenVertexArrays(1, &skyboxVAO);
	//glGenBuffers(1, &skyboxVBO);
	//glBindVertexArray(skyboxVAO);
	//glBindBuffer(GL_ARRAY_BUFFER, skyboxVBO);
	//glBufferData(GL_ARRAY_BUFFER, sizeof(skyboxVertices), &skyboxVertices, GL_STATIC_DRAW);

	//glEnableVertexAttribArray(0);
	//glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(GLfloat), (GLvoid*)0);
	//glBindVertexArray(0);

	//vector<const GLchar*> faces;
	//faces.push_back("resource/right.jpg");
	//faces.push_back("resource/left.jpg");
	//faces.push_back("resource/top.jpg");
	//faces.push_back("resource/bottom.jpg");
	//faces.push_back("resource/front.jpg");
	//faces.push_back("resource/back.jpg");

}

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

// Loads a cubemap texture from 6 individual texture faces
// Order should be:
// +X (right)
// -X (left)
// +Y (top)
// -Y (bottom)
// +Z (front)
// -Z (back)
GLuint loadCubemap(vector<const GLchar*> faces)
{
	GLuint textureId;
	glGenTextures(1, &textureId);
	glBindTexture(GL_TEXTURE_CUBE_MAP, textureId);
	int width, height;
	unsigned char* image = nullptr;

	for (GLuint i = 0; i < faces.size(); i++)
	{
		image = SOIL_load_image(faces[i], &width, &height, 0, SOIL_LOAD_RGB);
		glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, image);
		SOIL_free_image_data(image);
	}

	glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
	glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
	glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
	glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
	glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
	glBindTexture(GL_TEXTURE_CUBE_MAP, 0);

	return textureId;

}

// This function loads a texture from file. Note: texture loading functions like these are usually 
// managed by a 'Resource Manager' that manages all resources (like textures, models, audio). 
// For learning purposes we'll just define it as a utility function.
GLuint loadTexture(GLchar* path, GLboolean alpha /* = GL_FALSE */)
{
	GLuint textureId;
	glGenTextures(1, &textureId);
	glBindTexture(GL_TEXTURE_2D, textureId);


	int width, height;
	unsigned char* image = SOIL_load_image(path, &width, &height, 0, SOIL_LOAD_RGB);
	glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, image);
	glGenerateMipmap(GL_TEXTURE_2D);

	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_MAG_FILTER, GL_LINEAR);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
	glBindTexture(GL_TEXTURE_2D, 0);
	SOIL_free_image_data(image);

	return textureId;
}

int main()
{
	int glfwState = glfwInit();
	if (glfwState == GLFW_FALSE)
	{
		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, "Sun earth moon", 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);
	glfwSetKeyCallback(window, press_key_callback);
	glfwSetCursorPosCallback(window, mouse_move_callback);
	glfwSetScrollCallback(window, scroll_callback);

	//一定要初始化glew,否则,无法创建着色器句柄
	int glewState = glewInit();
	if (glewState != GLEW_OK)
	{
		cout << "GLEW initialize failed,invoke glewInit()......Error file:" << __FILE__ << "......Error line:" << __LINE__ << endl;
		glfwTerminate();
		exit(EXIT_FAILURE);
	}


	const GLubyte* renderer = glGetString(GL_RENDERER);
	const GLubyte* vendor = glGetString(GL_VENDOR);
	const GLubyte* version = glGetString(GL_VERSION);
	const GLubyte* glslVersion = glGetString(GL_SHADING_LANGUAGE_VERSION);
	GLint major, minor;
	glGetIntegerv(GL_MAJOR_VERSION, &major);
	glGetIntegerv(GL_MINOR_VERSION, &minor);
	printf("GL Vendor : %s\n", vendor);
	printf("GL Renderer : %s\n", renderer);
	printf("GL Version (string) : %s\n", version);
	printf("GL Version (integer) : %d.%d\n", major, minor);
	printf("GLSL Version : %s\n", glslVersion);

	glfwSwapInterval(1);

	init(window);

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


	return 0;
}

vertShader.glsl 顶点着色器

#version 460 core

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

uniform mat4 mv_matrix;
uniform mat4 proj_matrix;

layout(binding = 0) uniform sampler2D samp;

out vec2 tc;

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

fragShader.glsl片元着色器

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

源码下载

源码下载地址

  • 7
    点赞
  • 63
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
OpenGL是一种图形库,我们可以使用它来实现三维场景的渲染。下面我将提供一些实现太阳地球月球公转与自转的思路和代码示例。 首先,我们需要定义三个球体模型,分别代表太阳地球月球。这里我们可以使用glutSolidSphere函数来创建简单的球体模型。 ``` void drawSphere(float radius, int slices, int stacks) { GLUquadric *quad = gluNewQuadric(); gluSphere(quad, radius, slices, stacks); gluDeleteQuadric(quad); } ``` 然后,我们需要定义三个变量,分别表示太阳地球月球旋转角度。这些变量将在每帧更新时被增加,从而使球体模型旋转。 ``` float sunRotation = 0.0f; float earthRotation = 0.0f; float moonRotation = 0.0f; ``` 接下来,我们需要在每帧更新时更新旋转角度,并重新绘制场景。我们可以使用glPushMatrix和glPopMatrix函数来保存和恢复矩阵状态,以便我们可以在每个球体的本地坐标系中进行旋转。 ``` void display() { glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glLoadIdentity(); // 太阳自转 glPushMatrix(); glRotatef(sunRotation, 0.0f, 0.0f, 1.0f); glColor3f(1.0f, 1.0f, 0.0f); drawSphere(1.0f, 32, 32); glPopMatrix(); // 地球公转和自转 glPushMatrix(); glRotatef(earthRotation, 0.0f, 0.0f, 1.0f); glTranslatef(5.0f, 0.0f, 0.0f); glRotatef(earthRotation, 0.0f, 0.0f, 1.0f); glColor3f(0.0f, 0.0f, 1.0f); drawSphere(0.5f, 16, 16); // 月球公转和自转 glPushMatrix(); glRotatef(moonRotation, 0.0f, 0.0f, 1.0f); glTranslatef(1.0f, 0.0f, 0.0f); glRotatef(moonRotation, 0.0f, 0.0f, 1.0f); glColor3f(0.7f, 0.7f, 0.7f); drawSphere(0.2f, 8, 8); glPopMatrix(); glPopMatrix(); sunRotation += 0.2f; earthRotation += 0.5f; moonRotation += 1.0f; glutSwapBuffers(); } ``` 最后,我们需要在主函数中初始化OpenGL和GLUT,并启动主循环。在每个循环中,我们将调用display函数来更新场景。 ``` int main(int argc, char **argv) { glutInit(&argc, argv); glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE | GLUT_DEPTH); glutInitWindowSize(640, 480); glutCreateWindow("Solar System"); glutDisplayFunc(display); glutIdleFunc(display); glEnable(GL_DEPTH_TEST); glutMainLoop(); return 0; } ``` 这样我们就完成了太阳地球月球的公转和自转的实现。当我们运行程序时,我们将看到一个简单的太阳系模型,其中太阳地球月球围绕它们的轨道旋转

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值