opengl球形网格生成

效果如图
准备第三方库 glew、freeglut、glm
代码包括主程序源文件mainApp.cpp、顶点着色器shader.vs、片元着色器shader.fs
 
mainApp.cpp如下
#include <stdio.h>
#include <string.h> 
#include <iostream>
#include <fstream> 
#include <sstream>
#include <GL/glew.h>  
#include <GL/freeglut.h>   
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp> 

using namespace std; 
using namespace glm;

//shader文件
const char* vsShaderName = "shader.vs";//顶点着色器
const char* fsShaderName = "shader.fs";//片元着色器

GLuint VBO;//顶点缓冲对象
GLuint IBO;//索引缓冲对象
 
static  GLfloat *vertices;//顶点数组
static unsigned int *indices; //索引数组
GLuint ShaderProgram;
GLuint MatrixID; 
int windowWidth = 800;
int windowHeight = 800;
//球体参数
float radius=5.0f;//半径
int longPart=19;//经线数
int latPart=18;//纬线数
int verticeNum = longPart * latPart + 2 * longPart;

//相机参数
glm::mat4 ViewMatrix;//视图矩阵
glm::mat4 ProjectionMatrix; //投影矩阵
glm::mat4 MVP;//模型视图矩阵
glm::mat4 ModelMatrix;//模型矩阵
glm::vec3 position = glm::vec3(5, 5, 5); //相机位置
float horizontalAngle = 3.14f;
float verticalAngle = 0.0f;
float initialFoV = 45.0f; //相机视场角
float speed = 0.05f; //平移速度
float mouseSpeed = 0.05f;
int mouseX, mouseY;//鼠标位置 窗口坐标

// 传递键盘事件
static void SpecialKeyboardCB(int Key, int x, int y)
{
	glm::vec3 direction(
		cos(verticalAngle) * sin(horizontalAngle),
		sin(verticalAngle),
		cos(verticalAngle) * cos(horizontalAngle)
	);
	glm::vec3 right = glm::vec3(
		sin(horizontalAngle - 3.14f / 2.0f),
		0,
		cos(horizontalAngle - 3.14f / 2.0f)
	);
	glm::vec3 up = glm::cross(right, direction);

	switch (Key) {
	case GLUT_KEY_UP:
		position += direction  * speed;
		fprintf(stderr, "up key\n");
		break;
	case GLUT_KEY_RIGHT:
		position += right  * speed;
		fprintf(stderr, "right key\n");
		break;
	case GLUT_KEY_DOWN:
		position -= direction  * speed;
		fprintf(stderr, "down key\n");
		break;
	case GLUT_KEY_LEFT:
		position -= right  * speed;
		fprintf(stderr, "left key\n");
		break;
	case GLUT_KEY_F4:
		exit(1);
	default:
		fprintf(stderr, "Unimplemented GLUT key\n");
		//exit(1); 
	}

	float FoV = initialFoV;
	ProjectionMatrix = glm::perspective(glm::radians(FoV), 4.0f / 3.0f, 0.1f, 100.0f);
	ViewMatrix = glm::lookAt(
		position,
		position + direction,
		up
	);
	ModelMatrix = glm::mat4(1.0);
	MVP = ProjectionMatrix * ViewMatrix * ModelMatrix;
	glutPostRedisplay();//设置窗口重绘
}
//传递鼠标事件
static void PassiveMouseCB(int x, int y)
{
	horizontalAngle += mouseSpeed * float(x - mouseX);
	verticalAngle += mouseSpeed * float(y - mouseY);
	mouseX = x;
	mouseY = y;
	SpecialKeyboardCB(0, 0, 0);
}

//渲染回调函数 
void RenderScenceCB() {
	// 清空颜色缓存 
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
	glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);//线框模式
	//传递mvp
	glUniformMatrix4fv(MatrixID, 1, GL_FALSE, &MVP[0][0]);
	//传递顶点、索引
	glEnableVertexAttribArray(0); 
	glBindBuffer(GL_ARRAY_BUFFER, VBO); 
	glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0); 
	glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, IBO);
	////test
	//glDrawElements(GL_TRIANGLES, 3*4, GL_UNSIGNED_SHORT, 0);
	glDrawElements(GL_TRIANGLES_ADJACENCY, (longPart - 1)* latPart * 3 * 2 * 4, GL_UNSIGNED_SHORT, 0);
	glDisableVertexAttribArray(0); 
	//交换前后缓存
	glutSwapBuffers();
} 

//创建顶点
static void CreateVertexBuffer()
{ 
	////test
	//vertices = new GLfloat[3* 3];
	//vertices[0] = -1.0f;
	//vertices[1] = -1.0f;
	//vertices[2] = -1.0f;
	//vertices[3] = -1.0f;
	//vertices[4] = -1.0f;
	//vertices[5] = 1.0f;
	//vertices[6] = -1.0f;
	//vertices[7] = 1.0f;
	//vertices[8] = 1.0f;    
	
	vertices= new GLfloat[verticeNum * 3];
	for (int i = 0; i < longPart; i++)
	{
		vertices[i * 3] = 0;
		vertices[i * 3 + 1] = 0;
		vertices[i * 3 + 2] = radius;
	}     
	float degreesToRadians = 3.141593f/ 180.0f; //弧度转换
	float deltaLong = 360.0f / (longPart - 1);//经度每份对应度数
	float deltaLat = 180.0f / (latPart + 2);//纬度每份对应度数  
	for (int tempLat = 0; tempLat < latPart; tempLat++)
	{
		float tempAngle1 = ((tempLat + 1)* deltaLat) * degreesToRadians;
		for (int tempLong = 0; tempLong < longPart; tempLong++)
		{
			float tempAngle2 = (tempLong*deltaLong) * degreesToRadians;
			int tempIndex = tempLong + tempLat* longPart + longPart; 
			vertices[tempIndex * 3] = sin(tempAngle1) * cos(tempAngle2)* radius;
			vertices[tempIndex * 3 + 1] = sin(tempAngle1) * sin(tempAngle2)* radius;
			vertices[tempIndex * 3 + 2] = cos(tempAngle1)* radius; 
		}
	}
	for (int i = 0; i < longPart; i++)
	{
		vertices[(verticeNum - 1 - i) * 3] = 0;
		vertices[(verticeNum - 1 - i) * 3 + 1] = 0;
		vertices[(verticeNum - 1 - i) * 3 + 2] = -1.0f*radius;
	} 
	glGenBuffers(1, &VBO);
	glBindBuffer(GL_ARRAY_BUFFER, VBO); 
	////test
	//glBufferData(GL_ARRAY_BUFFER, 3 * 3 * sizeof(GLfloat), vertices, GL_STATIC_DRAW);
	glBufferData(GL_ARRAY_BUFFER, verticeNum * 3 * sizeof(GLfloat), vertices, GL_STATIC_DRAW);
}
//创建索引
static void CreateIndexBuffer()
{
	////test
	//indices = new unsigned int[3]; 
	//indices[0] = 2;
	//indices[1] = 1;
	//indices[2] = 0; 

	indices = new unsigned int[(longPart - 1)* latPart * 3 * 2];
	int k = 0;
	for (int i = 0; i < longPart - 1; i++)
	{
		indices[k++] = i;
		indices[k++] = i + longPart;
		indices[k++] = i + longPart + 1;
	} 
	for (int tempLat = 0; tempLat < latPart-1; tempLat++)
	{ 
		for (int tempLong = 0; tempLong < longPart - 1; tempLong++)
		{
			indices[k++] = tempLong + tempLat * longPart + longPart;
			indices[k++] = tempLong + tempLat * longPart + 2 * longPart;
			indices[k++] = tempLong + tempLat * longPart + longPart + 1;

			indices[k++] = tempLong + tempLat * longPart + 2 * longPart;
			indices[k++] = tempLong + tempLat * longPart + 1 + 2 * longPart;
			indices[k++] = tempLong + tempLat * longPart + 1 + longPart;
		}
	}
	for (int i = 0; i < longPart - 1; i++)
	{
		indices[k++] = verticeNum - 1 - i;
		indices[k++] = verticeNum - 1 - i - longPart;
		indices[k++] = verticeNum - 2 - i - longPart;
	}  
	glGenBuffers(1, &IBO);
	glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, IBO);
	////test
	//glBufferData(GL_ELEMENT_ARRAY_BUFFER, 3* sizeof(unsigned int), indices, GL_STATIC_DRAW);

	glBufferData(GL_ELEMENT_ARRAY_BUFFER, (longPart - 1)* latPart * 3 * 2 * sizeof(unsigned int), indices, GL_STATIC_DRAW);
} 

// 使用shader文本编译shader对象,并绑定shader到着色器程序中
static void AddShader(GLuint ShaderProgram, const char* pShaderText, GLenum ShaderType)
{
	// 根据shader类型参数定义两个shader对象
	GLuint ShaderObj = glCreateShader(ShaderType);
	// 检查是否定义成功
	if (ShaderObj == 0) {
		fprintf(stderr, "Error creating shader type %d\n", ShaderType);
		exit(0);
	}
	// 定义shader的代码源
	const GLchar* p[1];
	p[0] = pShaderText;
	GLint Lengths[1];
	Lengths[0] = strlen(pShaderText);
	glShaderSource(ShaderObj, 1, p, Lengths);
	glCompileShader(ShaderObj);// 编译shader对象 
							   // 检查和shader相关的错误
	GLint success;
	glGetShaderiv(ShaderObj, GL_COMPILE_STATUS, &success);
	if (!success) {
		GLchar InfoLog[1024];
		glGetShaderInfoLog(ShaderObj, 1024, NULL, InfoLog);
		fprintf(stderr, "Error compiling shader type %d: '%s'\n", ShaderType, InfoLog);
		exit(1);
	}
	// 将编译好的shader对象绑定到program object程序对象上
	glAttachShader(ShaderProgram, ShaderObj);
}

// 编译着色器函数
static void CompileShaders()
{
	// 创建着色器程序
	ShaderProgram = glCreateProgram();
	// 检查是否创建成功
	if (ShaderProgram == 0) {
		fprintf(stderr, "Error creating shader program\n");
		exit(1);
	}
	// 存储着色器文本的字符串
	string vs, fs;
	// 分别读取着色器文件中的文本到字符串
	std::ifstream VertexShaderStream(vsShaderName, std::ios::in);
	if (VertexShaderStream.is_open()) {
		std::stringstream sstr;
		sstr << VertexShaderStream.rdbuf();
		vs = sstr.str();
		VertexShaderStream.close();
	}
	else {
		printf("Error to open %s\n", vsShaderName);
		getchar();
		exit(0);
	}
	std::ifstream FragmentShaderStream(fsShaderName, std::ios::in);
	if (FragmentShaderStream.is_open()) {
		std::stringstream sstr;
		sstr << FragmentShaderStream.rdbuf();
		fs = sstr.str();
		FragmentShaderStream.close();
	}

	// 添加顶点着色器和片段着色器
	AddShader(ShaderProgram, vs.c_str(), GL_VERTEX_SHADER);
	AddShader(ShaderProgram, fs.c_str(), GL_FRAGMENT_SHADER);
	// 链接shader着色器程序,并检查程序相关错误
	GLint Success = 0;
	GLchar ErrorLog[1024] = { 0 };
	glLinkProgram(ShaderProgram);
	glGetProgramiv(ShaderProgram, GL_LINK_STATUS, &Success);
	if (Success == 0) {
		glGetProgramInfoLog(ShaderProgram, sizeof(ErrorLog), NULL, ErrorLog);
		fprintf(stderr, "Error linking shader program: '%s'\n", ErrorLog);
		exit(1);
	}
	// 检查验证在当前的管线状态程序是否可以被执行
	glValidateProgram(ShaderProgram);
	glGetProgramiv(ShaderProgram, GL_VALIDATE_STATUS, &Success);
	if (!Success) {
		glGetProgramInfoLog(ShaderProgram, sizeof(ErrorLog), NULL, ErrorLog);
		fprintf(stderr, "Invalid shader program: '%s'\n", ErrorLog);
		exit(1);
	}
	// 设置到管线声明中来使用上面成功建立的shader程序
	glUseProgram(ShaderProgram);
	MatrixID = glGetUniformLocation(ShaderProgram, "gWVP");
}

int main(int argc, char ** argv) {
	// 初始化GLUT
	glutInit(&argc, argv);
	// 显示模式:双缓冲、RGBA
	glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA);  
	glutInitWindowSize(windowWidth, windowHeight);      
	glutInitWindowPosition(100, 100);   
	glutCreateWindow("sphere");  
	GLenum res = glewInit();
	if (res != GLEW_OK) {
		fprintf(stderr, "Error: '%s'\n", glewGetErrorString(res));
		return 1;
	} 
	// 开始渲染
	glutDisplayFunc(RenderScenceCB);
	// 注册键盘事件
	glutSpecialFunc(SpecialKeyboardCB);
	//注册鼠标事件
	glutPassiveMotionFunc(PassiveMouseCB);
	mouseX = windowWidth / 2;
	mouseY = windowHeight / 2;
	// 缓存清空后的颜色值
	glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
	//创建顶点
	CreateVertexBuffer();
	//创建索引
	CreateIndexBuffer(); 
	// 编译着色器
	CompileShaders(); 
	//开启深度测试
	glEnable(GL_DEPTH_TEST);
	// 通知开始GLUT的内部循环
	glutMainLoop();
	delete vertices;
	return 0;
}
shader.vs如下
#version 330 
layout (location = 0) in vec3 Position; 
// WVP标准
uniform mat4 gWVP;  
void main()
{
    gl_Position = gWVP * vec4(Position, 1.0); 
}
shader.fs如下
#version 330 
out vec3 FragColor;  
void main()
{
    FragColor = vec3(1.0, 0.0, 0.0);
}

本文链接https://www.cnblogs.com/gucheng/p/10134582.html

猜你喜欢

转载自www.cnblogs.com/gucheng/p/10134582.html