以下是一个简单的例子,展示如何使用OpenGL绘制一个山:

首先,我们需要一个高度图,可以使用任何图片编辑器来创建。在这个例子中,我们将使用一个简单的黑白图像,其中黑色表示低海拔,白色表示高海拔。

然后,我们需要使用OpenGL载入这个高度图,并根据其像素值计算山的顶点位置和颜色。具体步骤如下:

  1. 载入高度图并转换为灰度图像
unsigned char* image = SOIL_load_image("heightmap.png", &width, &height, 0, SOIL_LOAD_L);
  1. 对每个灰度像素值计算相应的顶点高度和颜色
for (int z = 0; z < height; z++) {
    for (int x = 0; x < width; x++) {
        float height = (float)image[(z * width + x)] / 255.0f * MAX_HEIGHT;
        float r = height / MAX_HEIGHT;
        float g = height / MAX_HEIGHT;
        float b = height / MAX_HEIGHT;
        vertices.push_back(glm::vec3(x, height, z));
        colors.push_back(glm::vec3(r, g, b));
    }
}
  1. 根据相邻顶点计算三角形索引
for (int z = 0; z < height - 1; z++) {
    for (int x = 0; x < width - 1; x++) {
        int i1 = z * width + x;
        int i2 = i1 + 1;
        int i3 = (z + 1) * width + x;
        int i4 = i3 + 1;
        indices.push_back(i1);
        indices.push_back(i3);
        indices.push_back(i2);
        indices.push_back(i2);
        indices.push_back(i3);
        indices.push_back(i4);
    }
}
  1. 将顶点位置和颜色数据传递给OpenGL
glGenBuffers(1, &vertexBuffer);
glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer);
glBufferData(GL_ARRAY_BUFFER, vertices.size() * sizeof(glm::vec3), &vertices[0], GL_STATIC_DRAW);

glGenBuffers(1, &colorBuffer);
glBindBuffer(GL_ARRAY_BUFFER, colorBuffer);
glBufferData(GL_ARRAY_BUFFER, colors.size() * sizeof(glm::vec3), &colors[0], GL_STATIC_DRAW);

glGenBuffers(1, &indexBuffer);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBuffer);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, indices.size() * sizeof(unsigned int), &indices[0], GL_STATIC_DRAW);
  1. 绘制山
glEnableVertexAttribArray(0);
glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0);

glEnableVertexAttribArray(1);
glBindBuffer(GL_ARRAY_BUFFER, colorBuffer);
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 0, 0);

glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBuffer);
glDrawElements(GL_TRIANGLES, indices.size(), GL_UNSIGNED_INT, 0);

glDisableVertexAttribArray(0);
glDisableVertexAttribArray(1);

完整的代码如下:

#include <GL/glew.h>
#include <GLFW/glfw3.h>
#include <SOIL/SOIL.h>
#include <glm/glm.hpp>
#include <glm/gtx/transform.hpp>
#include <glm/gtc/type_ptr.hpp>
#include <iostream>
#include <vector>

const int WIDTH = 800;
const int HEIGHT = 600;
const float MAX_HEIGHT = 50.0f;

GLFWwindow* window;
GLuint program;
GLuint vertexBuffer;
GLuint colorBuffer;
GLuint indexBuffer;
int width, height;

std::vector<glm::vec3> vertices;
std::vector<glm::vec3> colors;
std::vector<unsigned int> indices;

void init() {
    glfwInit();
    glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
    glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
    glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
    window = glfwCreateWindow(WIDTH, HEIGHT, "Mountain", NULL, NULL);
    glfwMakeContextCurrent(window);
    glewExperimental = GL_TRUE;
    glewInit();
}

void loadHeightmap() {
    unsigned char* image = SOIL_load_image("heightmap.png", &width, &height, 0, SOIL_LOAD_L);
    for (int z = 0; z < height; z++) {
        for (int x = 0; x < width; x++) {
            float height = (float)image[(z * width + x)] / 255.0f * MAX_HEIGHT;
            float r = height / MAX_HEIGHT;
            float g = height / MAX_HEIGHT;
            float b = height / MAX_HEIGHT;
            vertices.push_back(glm::vec3(x, height, z));
            colors.push_back(glm::vec3(r, g, b));
        }
    }
    SOIL_free_image_data(image);
}

void calculateIndices() {
    for (int z = 0; z < height - 1; z++) {
        for (int x = 0; x < width - 1; x++) {
            int i1 = z * width + x;
            int i2 = i1 + 1;
            int i3 = (z + 1) * width + x;
            int i4 = i3 + 1;
            indices.push_back(i1);
            indices.push_back(i3);
            indices.push_back(i2);
            indices.push_back(i2);
            indices.push_back(i3);
            indices.push_back(i4);
        }
    }
}

void loadBuffers() {
    glGenBuffers(1, &vertexBuffer);
    glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer);
    glBufferData(GL_ARRAY_BUFFER, vertices.size() * sizeof(glm::vec3), &vertices[0], GL_STATIC_DRAW);

    glGenBuffers(1, &colorBuffer);
    glBindBuffer(GL_ARRAY_BUFFER, colorBuffer);
    glBufferData(GL_ARRAY_BUFFER, colors.size() * sizeof(glm::vec3), &colors[0], GL_STATIC_DRAW);

    glGenBuffers(1, &indexBuffer);
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBuffer);
    glBufferData(GL_ELEMENT_ARRAY_BUFFER, indices.size() * sizeof(unsigned int), &indices[0], GL_STATIC_DRAW);
}

void setupShaders() {
    GLuint vertexShader = glCreateShader(GL_VERTEX_SHADER);
    GLuint fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);

    const char* vertexShaderSource =
        "#version 330 core\n"
        "layout (location = 0) in vec3 position;\n"
        "layout (location = 1) in vec3 color;\n"
        "out vec3 fColor;\n"
        "uniform mat4 model;\n"
        "uniform mat4 view;\n"
        "uniform mat4 projection;\n"
        "void main() {\n"
        "    gl_Position = projection * view * model * vec4(position, 1.0);\n"
        "    fColor = color;\n"
        "}\n";

    const char* fragmentShaderSource =
        "#version 330 core\n"
        "in vec3 fColor;\n"
        "out vec4 color;\n"
        "void main() {\n"
        "    color = vec4(fColor, 1.0);\n"
        "}\n";

    glShaderSource(vertexShader, 1, &vertexShaderSource, NULL);
    glShaderSource(fragmentShader, 1, &fragmentShaderSource, NULL);
    glCompileShader(vertexShader);
    glCompileShader(fragmentShader);

    GLint success;
    GLchar infoLog[512];
    glGetShaderiv(vertexShader, GL_COMPILE_STATUS, &success);
    if (!success) {
        glGetShaderInfoLog(vertexShader, 512, NULL, infoLog);
        std::cout << "Vertex shader compilation failed: " << infoLog << std::endl;
    }
    glGetShaderiv(fragmentShader, GL_COMPILE_STATUS, &success);
    if (!success) {
        glGetShaderInfoLog(fragmentShader, 512, NULL, infoLog);
        std::cout << "Fragment shader compilation failed: " << infoLog << std::endl;
    }

    program = glCreateProgram();
    glAttachShader(program, vertexShader);
    glAttachShader(program, fragmentShader);
    glLinkProgram(program);

    glGetProgramiv(program, GL_LINK_STATUS, &success);
    if (!success) {
        glGetProgramInfoLog(program, 512, NULL, infoLog);
        std::cout << "Shader program linking failed: " << infoLog << std::endl;
    }

    glDeleteShader(vertexShader);
    glDeleteShader(fragmentShader);
}

void render() {
    glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    glEnable(GL_DEPTH_TEST);

    glUseProgram(program);

    glm::mat4 view = glm::lookAt(glm::vec3(50, 50, 50), glm::vec3(0, 0, 0), glm::vec3(0, 1, 0));
    glm::mat4 projection = glm::perspective(glm::radians(45.0f), (float)WIDTH / HEIGHT, 0.1f, 1000.0f);
    glm::mat4 model = glm::mat4(1.0f);

    glUniformMatrix4fv(glGetUniformLocation(program, "model"), 1, GL_FALSE, glm::value_ptr(model));
    glUniformMatrix4fv(glGetUniformLocation(program, "view"), 1, GL_FALSE, glm::value_ptr(view));
    glUniformMatrix4fv(glGetUniformLocation(program, "projection"), 1, GL_FALSE, glm::value_ptr(projection));

    glEnableVertexAttribArray(0);
    glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer);
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0);

    glEnableVertexAttribArray(1);
    glBindBuffer(GL_ARRAY_BUFFER, colorBuffer);
    glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 0, 0);

    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBuffer);
    glDrawElements(GL_TRIANGLES, indices.size(), GL_UNSIGNED_INT, 0);

    glDisableVertexAttribArray(0);
    glDisableVertexAttribArray(1);

    glfwSwapBuffers(window);
}

int main() {
    init();

    loadHeightmap();
    calculateIndices();
    loadBuffers();
    setupShaders();

    while (!glfwWindowShouldClose(window)) {
        render();
        glfwPollEvents();
    }

    glDeleteBuffers(1, &vertexBuffer);
    glDeleteBuffers(1, &colorBuffer);
    glDeleteBuffers(1, &indexBuffer);
    glDeleteProgram(program);

    glfwTerminate();

    return 0;
}
如何利用opengl代码画一座山

原文地址: http://www.cveoy.top/t/topic/bHjo 著作权归作者所有。请勿转载和采集!

免费AI点我,无需注册和登录