我正在用OpenGL绘制3D场景。允许用户环绕场景。除了场景中的对象,我想在右上角或左下角绘制一个轴指示器来显示当前的旋转状态。
类似于搅拌机右上角的视窗小工具。
有人能告诉我做这件事的方向吗?
v1l68za41#
我的方法是:第一次渲染场景;第二次将轴指示器(视图立方体)本身渲染到帧缓冲区中的纹理附件。第三,将生成的纹理渲染到屏幕右上角的四边形中。类似以下内容:https://learnopengl.com/Advanced-OpenGL/Framebuffers
pdkcd3nj2#
非常简单地解释一下,一旦你有了3D axis,你就开始在camera.Position + camera.Front * smallDist绘制3D轴,所以它总是在屏幕的中心绘制。
camera.Position + camera.Front * smallDist
然后,使用glViewport(...)将视口设为屏幕的一角,并绘制轴。你也可以用例如。glLineWidth(3.0f),使线条更加突出。
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); }
结果:
2条答案
按热度按时间v1l68za41#
我的方法是:第一次渲染场景;第二次将轴指示器(视图立方体)本身渲染到帧缓冲区中的纹理附件。第三,将生成的纹理渲染到屏幕右上角的四边形中。类似以下内容:https://learnopengl.com/Advanced-OpenGL/Framebuffers
pdkcd3nj2#
非常简单地解释一下,一旦你有了3D axis,你就开始在
camera.Position + camera.Front * smallDist
绘制3D轴,所以它总是在屏幕的中心绘制。然后,使用
glViewport(...)
将视口设为屏幕的一角,并绘制轴。你也可以用例如。glLineWidth(3.0f)
,使线条更加突出。这里有一个粗略的想法:
结果: