opengl球形网格生成
阅读原文时间:2023年07月11日阅读:3

效果如图

准备第三方库 glew、freeglut、glm

代码包括主程序源文件mainApp.cpp、顶点着色器shader.vs、片元着色器shader.fs

mainApp.cpp如下

#include
#include
#include
#include
#include
#include
#include
#include
#include

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

手机扫一扫

移动阅读更方便

阿里云服务器
腾讯云服务器
七牛云服务器

你可能感兴趣的文章