OpenGL:如何在右上角绘制轴指示器

hgc7kmma  于 2022-09-26  发布在  其他
关注(0)|答案(2)|浏览(167)

我正在用OpenGL绘制3D场景。允许用户环绕场景。除了场景中的对象,我想在右上角或左下角绘制一个轴指示器来显示当前的旋转状态。

类似于搅拌机右上角的视窗小工具。

有人能告诉我做这件事的方向吗?

v1l68za4

v1l68za41#

我的方法是:第一次渲染场景;第二次将轴指示器(视图立方体)本身渲染到帧缓冲区中的纹理附件。第三,将生成的纹理渲染到屏幕右上角的四边形中。类似以下内容:https://learnopengl.com/Advanced-OpenGL/Framebuffers

pdkcd3nj

pdkcd3nj2#

非常简单地解释一下,一旦你有了3D axis,你就开始在camera.Position + camera.Front * smallDist绘制3D轴,所以它总是在屏幕的中心绘制。

然后,使用glViewport(...)将视口设为屏幕的一角,并绘制轴。你也可以用例如。glLineWidth(3.0f),使线条更加突出。

这里有一个粗略的想法:


# include <iostream>

# include <vector>

# include <math.h>

# include <glad/glad.h>

# include <GLFW/glfw3.h>

# define GLM_ENABLE_EXPERIMENTAL

# include <glm/glm.hpp>

# include <glm/gtc/matrix_transform.hpp>

# include <glm/ext.hpp>

// camera.h is from basic camera learnopengl tutorial

# include "camera.h"

using glm::mat4;
using glm::vec3;
using glm::radians;
using glm::lookAt;
using std::vector;

void processInput(GLFWwindow *window);
void mouse_callback(GLFWwindow* window, double xpos, double ypos);

// settings
const unsigned int SCR_WIDTH = 800;
const unsigned int SCR_HEIGHT = 600;

float lastX = SCR_WIDTH / 2.0f;
float lastY = SCR_HEIGHT / 2.0f;
bool firstMouse = true;

// timing
float deltaTime = 0.0f; // time between current frame and last frame
float lastFrame = 0.0f;

Camera camera(glm::vec3(0.0f, 0.0f, 3.0f));

class Line {
    int shaderProgram;
    unsigned int VBO, VAO;
    vector<float> vertices;
    vec3 startPoint;
    vec3 endPoint;
    mat4 MVP = mat4(1.0);
    vec3 lineColor;
public:
    Line(vec3 start, vec3 end) {

        startPoint = start;
        endPoint = end;
        lineColor = vec3(1,1,1);

        const char *vertexShaderSource = "#version 330 coren"
            "layout (location = 0) in vec3 aPos;n"
            "uniform mat4 MVP;n"
            "void main()n"
            "{n"
            "   gl_Position = MVP * vec4(aPos.x, aPos.y, aPos.z, 1.0);n"
            "}0";
        const char *fragmentShaderSource = "#version 330 coren"
            "out vec4 FragColor;n"
            "uniform vec3 color;n"
            "void main()n"
            "{n"
            "   FragColor = vec4(color, 1.0f);n"
            "}n0";

        // vertex shader
        int vertexShader = glCreateShader(GL_VERTEX_SHADER);
        glShaderSource(vertexShader, 1, &vertexShaderSource, NULL);
        glCompileShader(vertexShader);
        // check for shader compile errors

        // fragment shader
        int fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
        glShaderSource(fragmentShader, 1, &fragmentShaderSource, NULL);
        glCompileShader(fragmentShader);
        // check for shader compile errors

        // link shaders
        shaderProgram = glCreateProgram();
        glAttachShader(shaderProgram, vertexShader);
        glAttachShader(shaderProgram, fragmentShader);
        glLinkProgram(shaderProgram);
        // check for linking errors

        glDeleteShader(vertexShader);
        glDeleteShader(fragmentShader);

        vertices = {
             start.x, start.y, start.z,
             end.x, end.y, end.z,

        };

        glGenVertexArrays(1, &VAO);
        glGenBuffers(1, &VBO);
        glBindVertexArray(VAO);

        glBindBuffer(GL_ARRAY_BUFFER, VBO);
        glBufferData(GL_ARRAY_BUFFER, sizeof(vertices)*vertices.size(), vertices.data(), GL_STATIC_DRAW);

        glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);
        glEnableVertexAttribArray(0);

        glBindBuffer(GL_ARRAY_BUFFER, 0); 
        glBindVertexArray(0); 

    }

    int setMVP(mat4 mvp) {
        MVP = mvp;
        return 1;
    }

    int setColor(vec3 color) {
        lineColor = color;
        return 1;
    }

    int draw() {
        glUseProgram(shaderProgram);

        glUniformMatrix4fv(glGetUniformLocation(shaderProgram, "MVP"), 1, GL_FALSE, &MVP[0][0]);
        glUniform3fv(glGetUniformLocation(shaderProgram, "color"), 1, &lineColor[0]);

        glBindVertexArray(VAO);
        glDrawArrays(GL_LINES, 0, 2);
        return 1;
    }

    ~Line() {
        glDeleteVertexArrays(1, &VAO);
        glDeleteBuffers(1, &VBO);
        glDeleteProgram(shaderProgram);
    }
};

int main()
{
    // glfw: initialize and configure
    // ------------------------------
    glfwInit();
    glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
    glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
    glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);

# ifdef __APPLE__

    glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);

# endif

    // glfw window creation
    // --------------------
    GLFWwindow* window = glfwCreateWindow(SCR_WIDTH, SCR_HEIGHT, "drawing lines", NULL, NULL);
    if (window == NULL)
    {
        std::cout << "Failed to create GLFW window" << std::endl;
        glfwTerminate();
        return -1;
    }
    glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_DISABLED);  
    glfwMakeContextCurrent(window);
    glfwSetCursorPosCallback(window, mouse_callback);

    // glad: load all OpenGL function pointers
    // ---------------------------------------
    if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress))
    {
        std::cout << "Failed to initialize GLAD" << std::endl;
        return -1;
    }
    camera.Position = vec3(0,0,3);
    camera.MovementSpeed = 0.01f;

    // 3d lines example
    Line line1(vec3(0,0,0), vec3(0.04,0,0));
    line1.setColor(vec3(1,0,0));
    Line line2(vec3(0,0,0), vec3(0,0.04,0));
    line2.setColor(vec3(0,1,0));
    Line line3(vec3(0,0,0), vec3(0,0,0.04));
    line3.setColor(vec3(0,0,1));
    Line line4(vec3(0,0,0), vec3(10,0,0));
    line4.setColor(vec3(1,0,0));
    Line line5(vec3(0,0,0), vec3(0,10,0));
    line5.setColor(vec3(0,1,0));
    Line line6(vec3(0,0,0), vec3(0,0,10));
    line6.setColor(vec3(0,0,1));

    glm::mat4 projection = glm::perspective(glm::radians(45.0f), (float) SCR_WIDTH / (float)SCR_HEIGHT, 0.01f, 1000.0f);

    // render loop
    // -----------
    while (!glfwWindowShouldClose(window))
    {
        float currentFrame = glfwGetTime();
        deltaTime = currentFrame - lastFrame;
        // input
        // -----
        processInput(window);

        // render
        // ------
        glClearColor(0.0, 0.0, 0.0, 1.0);
        glClear(GL_COLOR_BUFFER_BIT);

        glm::mat4 projection = glm::perspective(glm::radians(camera.Zoom), (float)SCR_WIDTH / (float)SCR_HEIGHT, 0.01f, 1000.0f);
        glm::mat4 view = camera.GetViewMatrix();

        float ar = (float)SCR_WIDTH / (float)SCR_HEIGHT;
        float fov = 45.0f;
        float nearDist = 0.01f;
        float Hnear = 2.0f * tan(glm::radians(fov/2)) * nearDist;
        float Wnear = Hnear * ar;
        glm::vec3 axisPosition = camera.Position + glm::normalize(camera.Front) * 0.2f;

        line1.setMVP(projection * view * glm::translate(glm::mat4(1.0f), axisPosition));
        line2.setMVP(projection * view * glm::translate(glm::mat4(1.0f), axisPosition));
        line3.setMVP(projection * view * glm::translate(glm::mat4(1.0f), axisPosition));

        glViewport(SCR_WIDTH-SCR_WIDTH/10.0f,SCR_HEIGHT-SCR_HEIGHT/10.0f,SCR_WIDTH/10.0f,SCR_HEIGHT/10.0f);
        glLineWidth(3.0f);
        line1.draw();
        line2.draw();
        line3.draw();
        glLineWidth(1.0f);
        glViewport(0,0,SCR_WIDTH, SCR_HEIGHT);

        line4.setMVP(projection * view);
        line5.setMVP(projection * view);
        line6.setMVP(projection * view);

        line4.draw();
        line5.draw();
        line6.draw();

        // glfw: swap buffers and poll IO events (keys pressed/released, mouse moved etc.)
        // -------------------------------------------------------------------------------
        glfwSwapBuffers(window);
        glfwPollEvents();
    }

    // glfw: terminate, clearing all previously allocated GLFW resources.
    // ------------------------------------------------------------------
    glfwTerminate();
    return 0;
}

// process all input: query GLFW whether relevant keys are pressed/released this frame and react accordingly
// ---------------------------------------------------------------------------------------------------------
void processInput(GLFWwindow *window)
{
    if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS)
        glfwSetWindowShouldClose(window, true);

    if (glfwGetKey(window, GLFW_KEY_W) == GLFW_PRESS)
        camera.ProcessKeyboard(FORWARD, deltaTime);
    if (glfwGetKey(window, GLFW_KEY_S) == GLFW_PRESS)
        camera.ProcessKeyboard(BACKWARD, deltaTime);
    if (glfwGetKey(window, GLFW_KEY_A) == GLFW_PRESS)
        camera.ProcessKeyboard(LEFT, deltaTime);
    if (glfwGetKey(window, GLFW_KEY_D) == GLFW_PRESS)
        camera.ProcessKeyboard(RIGHT, deltaTime);
}

// glfw: whenever the mouse moves, this callback is called
// -------------------------------------------------------
void mouse_callback(GLFWwindow* window, double xpos, double ypos)
{
    if (firstMouse)
    {
        lastX = xpos;
        lastY = ypos;
        firstMouse = false;
    }

    float xoffset = xpos - lastX;
    float yoffset = lastY - ypos; // reversed since y-coordinates go from bottom to top

    lastX = xpos;
    lastY = ypos;

    camera.ProcessMouseMovement(xoffset, yoffset);
}

结果:

相关问题