2010-11-26 145 views
2

如何在OpenGL中渲染2D精靈,因爲我有一個精靈的PNG?將圖像作爲我希望達到的效果的示例。另外,我想在底部圖像上像步槍一樣在屏幕上疊加武器。有誰知道我會如何實現這兩個效果?任何幫助是極大的讚賞。渲染3D世界中的2D精靈?

alt text

alt text

+0

投票結束作爲交叉帖http://gamedev.stackexchange.com/questions/5959/rendering-2d-sprites-into-a-3d-world – 2016-04-12 06:39:16

回答

7

在3D方面,這就是所謂的 「廣告牌」。廣告牌是完全平坦的2D平面,上面有紋理,它總是面向相機。

在這裏看到一個純粹的OpenGL實現:http://nehe.gamedev.net/data/articles/article.asp?article=19

幾乎任何3D引擎應該能夠在默認情況下做到這些。例如,Ogre3D可以做到這一點。

+1

只有第二個例子可能是廣告牌。 – 2010-11-26 13:08:38

1

對於2D武器的覆蓋,您可以使用glOrtho作爲相機視圖。

1

您創建一個3d四邊形並將基於.png的紋理映射到它。您可以像第一張照片一樣製作四面朝向的任何方向,或使其始終朝向相機(如Svenstaro提到的廣告牌),就像您的第二張照片一樣。雖然,公平地說,我確信第二張照片直接在軟件創建的幀緩衝區(看起來像Wolf3d技術,軟件渲染)中直接映射圖像(有一些縮放比例)。

2

一)對於第一種情況:

這不是一個真正的2D精靈。這些男人似乎被渲染爲具有某種透明度(alpha測試或alpha混合)的紋理的單個四邊形。

無論如何,即使是一個四元組仍然可以被認爲是一個3D對象,所以對於這種情況,您可能希望將其視爲一個:跟蹤其翻譯和旋轉,並以與其他3D對象相同的方式呈現它。

b)對於第二種情況:

如果你想要槍(2D畫面,我pressume)在同一個地方被渲染沒有任何透視變換,那麼你可以使用相同的技術一個用於繪製GUI(等)。在這裏我的帖子看看:

2D overlay on a 3D scene

0

OpenGL的教程有:

截圖:

enter image description here

代碼:

#include <stdio.h> 
#include <stdlib.h> 

#include <vector> 
#include <algorithm> 

#include <GL/glew.h> 

#include <glfw3.h> 
GLFWwindow* window; 

#include <glm/glm.hpp> 
#include <glm/gtc/matrix_transform.hpp> 
#include <glm/gtx/norm.hpp> 
using namespace glm; 


#include <common/shader.hpp> 
#include <common/texture.hpp> 
#include <common/controls.hpp> 

#define DRAW_CUBE // Comment or uncomment this to simplify the code 

int main(void) 
{ 
    // Initialise GLFW 
    if(!glfwInit()) 
    { 
     fprintf(stderr, "Failed to initialize GLFW\n"); 
     getchar(); 
     return -1; 
    } 

    glfwWindowHint(GLFW_SAMPLES, 4); 
    glfwWindowHint(GLFW_RESIZABLE,GL_FALSE); 
    glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); 
    glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3); 
    glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE); // To make MacOS happy; should not be needed 
    glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); 

    // Open a window and create its OpenGL context 
    window = glfwCreateWindow(1024, 768, "Tutorial 18 - Billboards", NULL, NULL); 
    if(window == NULL){ 
     fprintf(stderr, "Failed to open GLFW window. If you have an Intel GPU, they are not 3.3 compatible. Try the 2.1 version of the tutorials.\n"); 
     getchar(); 
     glfwTerminate(); 
     return -1; 
    } 
    glfwMakeContextCurrent(window); 

    // Initialize GLEW 
    glewExperimental = true; // Needed for core profile 
    if (glewInit() != GLEW_OK) { 
     fprintf(stderr, "Failed to initialize GLEW\n"); 
     getchar(); 
     glfwTerminate(); 
     return -1; 
    } 

    // Ensure we can capture the escape key being pressed below 
    glfwSetInputMode(window, GLFW_STICKY_KEYS, GL_TRUE); 
    // Hide the mouse and enable unlimited mouvement 
    glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_DISABLED); 

    // Set the mouse at the center of the screen 
    glfwPollEvents(); 
    glfwSetCursorPos(window, 1024/2, 768/2); 

    // Dark blue background 
    glClearColor(0.0f, 0.0f, 0.4f, 0.0f); 

    // Enable depth test 
    glEnable(GL_DEPTH_TEST); 
    // Accept fragment if it closer to the camera than the former one 
    glDepthFunc(GL_LESS); 

    GLuint VertexArrayID; 
    glGenVertexArrays(1, &VertexArrayID); 
    glBindVertexArray(VertexArrayID); 


    // Create and compile our GLSL program from the shaders 
    GLuint programID = LoadShaders("Billboard.vertexshader", "Billboard.fragmentshader"); 

    // Vertex shader 
    GLuint CameraRight_worldspace_ID = glGetUniformLocation(programID, "CameraRight_worldspace"); 
    GLuint CameraUp_worldspace_ID = glGetUniformLocation(programID, "CameraUp_worldspace"); 
    GLuint ViewProjMatrixID = glGetUniformLocation(programID, "VP"); 
    GLuint BillboardPosID = glGetUniformLocation(programID, "BillboardPos"); 
    GLuint BillboardSizeID = glGetUniformLocation(programID, "BillboardSize"); 
    GLuint LifeLevelID = glGetUniformLocation(programID, "LifeLevel"); 

    GLuint TextureID = glGetUniformLocation(programID, "myTextureSampler"); 


    GLuint Texture = loadDDS("ExampleBillboard.DDS"); 

    // The VBO containing the 4 vertices of the particles. 
    static const GLfloat g_vertex_buffer_data[] = { 
     -0.5f, -0.5f, 0.0f, 
      0.5f, -0.5f, 0.0f, 
     -0.5f, 0.5f, 0.0f, 
      0.5f, 0.5f, 0.0f, 
    }; 
    GLuint billboard_vertex_buffer; 
    glGenBuffers(1, &billboard_vertex_buffer); 
    glBindBuffer(GL_ARRAY_BUFFER, billboard_vertex_buffer); 
    glBufferData(GL_ARRAY_BUFFER, sizeof(g_vertex_buffer_data), g_vertex_buffer_data, GL_DYNAMIC_DRAW); 

#ifdef DRAW_CUBE 
    // Everything here comes from Tutorial 4 
    GLuint cubeProgramID = LoadShaders("../tutorial04_colored_cube/TransformVertexShader.vertexshader", "../tutorial04_colored_cube/ColorFragmentShader.fragmentshader"); 
    GLuint cubeMatrixID = glGetUniformLocation(cubeProgramID, "MVP"); 
    static const GLfloat g_cube_vertex_buffer_data[] = { -1.0f,-1.0f,-1.0f,-1.0f,-1.0f, 1.0f,-1.0f, 1.0f, 1.0f,1.0f, 1.0f,-1.0f,-1.0f,-1.0f,-1.0f,-1.0f, 1.0f,-1.0f,1.0f,-1.0f, 1.0f,-1.0f,-1.0f,-1.0f,1.0f,-1.0f,-1.0f,1.0f, 1.0f,-1.0f,1.0f,-1.0f,-1.0f,-1.0f,-1.0f,-1.0f,-1.0f,-1.0f,-1.0f,-1.0f, 1.0f, 1.0f,-1.0f, 1.0f,-1.0f,1.0f,-1.0f, 1.0f,-1.0f,-1.0f, 1.0f,-1.0f,-1.0f,-1.0f,-1.0f, 1.0f, 1.0f,-1.0f,-1.0f, 1.0f,1.0f,-1.0f, 1.0f,1.0f, 1.0f, 1.0f,1.0f,-1.0f,-1.0f,1.0f, 1.0f,-1.0f,1.0f,-1.0f,-1.0f,1.0f, 1.0f, 1.0f,1.0f,-1.0f, 1.0f,1.0f, 1.0f, 1.0f,1.0f, 1.0f,-1.0f,-1.0f, 1.0f,-1.0f,1.0f, 1.0f, 1.0f,-1.0f, 1.0f,-1.0f,-1.0f, 1.0f, 1.0f,1.0f, 1.0f, 1.0f,-1.0f, 1.0f, 1.0f,1.0f,-1.0f, 1.0f}; 
    static const GLfloat g_cube_color_buffer_data[] = { 0.583f, 0.771f, 0.014f,0.609f, 0.115f, 0.436f,0.327f, 0.483f, 0.844f,0.822f, 0.569f, 0.201f,0.435f, 0.602f, 0.223f,0.310f, 0.747f, 0.185f,0.597f, 0.770f, 0.761f,0.559f, 0.436f, 0.730f,0.359f, 0.583f, 0.152f,0.483f, 0.596f, 0.789f,0.559f, 0.861f, 0.639f,0.195f, 0.548f, 0.859f,0.014f, 0.184f, 0.576f,0.771f, 0.328f, 0.970f,0.406f, 0.615f, 0.116f,0.676f, 0.977f, 0.133f,0.971f, 0.572f, 0.833f,0.140f, 0.616f, 0.489f,0.997f, 0.513f, 0.064f,0.945f, 0.719f, 0.592f,0.543f, 0.021f, 0.978f,0.279f, 0.317f, 0.505f,0.167f, 0.620f, 0.077f,0.347f, 0.857f, 0.137f,0.055f, 0.953f, 0.042f,0.714f, 0.505f, 0.345f,0.783f, 0.290f, 0.734f,0.722f, 0.645f, 0.174f,0.302f, 0.455f, 0.848f,0.225f, 0.587f, 0.040f,0.517f, 0.713f, 0.338f,0.053f, 0.959f, 0.120f,0.393f, 0.621f, 0.362f,0.673f, 0.211f, 0.457f,0.820f, 0.883f, 0.371f,0.982f, 0.099f, 0.879f}; 
    GLuint cubevertexbuffer; 
    glGenBuffers(1, &cubevertexbuffer); 
    glBindBuffer(GL_ARRAY_BUFFER, cubevertexbuffer); 
    glBufferData(GL_ARRAY_BUFFER, sizeof(g_cube_vertex_buffer_data), g_cube_vertex_buffer_data, GL_DYNAMIC_DRAW); 
    GLuint cubecolorbuffer; 
    glGenBuffers(1, &cubecolorbuffer); 
    glBindBuffer(GL_ARRAY_BUFFER, cubecolorbuffer); 
    glBufferData(GL_ARRAY_BUFFER, sizeof(g_cube_color_buffer_data), g_cube_color_buffer_data, GL_DYNAMIC_DRAW); 
#endif 

    double lastTime = glfwGetTime(); 
    do 
    { 
     // Clear the screen 
     glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); 

     double currentTime = glfwGetTime(); 
     double delta = currentTime - lastTime; 
     lastTime = currentTime; 


     computeMatricesFromInputs(); 
     glm::mat4 ProjectionMatrix = getProjectionMatrix(); 
     glm::mat4 ViewMatrix = getViewMatrix(); 



#ifdef DRAW_CUBE 
     // Again : this is just Tutorial 4 ! 
     glDisable(GL_BLEND); 
     glUseProgram(cubeProgramID); 
     glm::mat4 cubeModelMatrix(1.0f); 
     cubeModelMatrix = glm::scale(cubeModelMatrix, glm::vec3(0.2f, 0.2f, 0.2f)); 
     glm::mat4 cubeMVP = ProjectionMatrix * ViewMatrix * cubeModelMatrix; 
     glUniformMatrix4fv(cubeMatrixID, 1, GL_FALSE, &cubeMVP[0][0]); 
     glEnableVertexAttribArray(0); 
     glBindBuffer(GL_ARRAY_BUFFER, cubevertexbuffer); 
     glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, (void*)0 ); 
     glEnableVertexAttribArray(1); 
     glBindBuffer(GL_ARRAY_BUFFER, cubecolorbuffer); 
     glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 0, (void*)0 ); 
     glDrawArrays(GL_TRIANGLES, 0, 12*3); 
     glDisableVertexAttribArray(0); 
     glDisableVertexAttribArray(1); 
#endif 



     // We will need the camera's position in order to sort the particles 
     // w.r.t the camera's distance. 
     // There should be a getCameraPosition() function in common/controls.cpp, 
     // but this works too. 
     glm::vec3 CameraPosition(glm::inverse(ViewMatrix)[3]); 

     glm::mat4 ViewProjectionMatrix = ProjectionMatrix * ViewMatrix; 





     glEnable(GL_BLEND); 
     glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); 

     // Use our shader 
     glUseProgram(programID); 

     // Bind our texture in Texture Unit 0 
     glActiveTexture(GL_TEXTURE0); 
     glBindTexture(GL_TEXTURE_2D, Texture); 
     // Set our "myTextureSampler" sampler to user Texture Unit 0 
     glUniform1i(TextureID, 0); 

     // This is the only interesting part of the tutorial. 
     // This is equivalent to mlutiplying (1,0,0) and (0,1,0) by inverse(ViewMatrix). 
     // ViewMatrix is orthogonal (it was made this way), 
     // so its inverse is also its transpose, 
     // and transposing a matrix is "free" (inversing is slooow) 
     glUniform3f(CameraRight_worldspace_ID, ViewMatrix[0][0], ViewMatrix[1][0], ViewMatrix[2][0]); 
     glUniform3f(CameraUp_worldspace_ID , ViewMatrix[0][1], ViewMatrix[1][1], ViewMatrix[2][1]); 

     glUniform3f(BillboardPosID, 0.0f, 0.5f, 0.0f); // The billboard will be just above the cube 
     glUniform2f(BillboardSizeID, 1.0f, 0.125f);  // and 1m*12cm, because it matches its 256*32 resolution =) 

     // Generate some fake life level and send it to glsl 
     float LifeLevel = sin(currentTime)*0.1f + 0.7f; 
     glUniform1f(LifeLevelID, LifeLevel); 

     glUniformMatrix4fv(ViewProjMatrixID, 1, GL_FALSE, &ViewProjectionMatrix[0][0]); 

     // 1rst attribute buffer : vertices 
     glEnableVertexAttribArray(0); 
     glBindBuffer(GL_ARRAY_BUFFER, billboard_vertex_buffer); 
     glVertexAttribPointer(
      0,     // attribute. No particular reason for 0, but must match the layout in the shader. 
      3,     // size 
      GL_FLOAT,   // type 
      GL_FALSE,   // normalized? 
      0,     // stride 
      (void*)0   // array buffer offset 
     ); 


     // Draw the billboard ! 
     // This draws a triangle_strip which looks like a quad. 
     glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); 

     glDisableVertexAttribArray(0); 


     // Swap buffers 
     glfwSwapBuffers(window); 
     glfwPollEvents(); 

    } // Check if the ESC key was pressed or the window was closed 
    while(glfwGetKey(window, GLFW_KEY_ESCAPE) != GLFW_PRESS && 
      glfwWindowShouldClose(window) == 0); 


    // Cleanup VBO and shader 
    glDeleteBuffers(1, &billboard_vertex_buffer); 
    glDeleteProgram(programID); 
    glDeleteTextures(1, &TextureID); 
    glDeleteVertexArrays(1, &VertexArrayID); 
#ifdef DRAW_CUBE 
    glDeleteProgram(cubeProgramID); 
    glDeleteVertexArrays(1, &cubevertexbuffer); 
    glDeleteVertexArrays(1, &cubecolorbuffer); 
#endif 
    // Close OpenGL window and terminate GLFW 
    glfwTerminate(); 

    return 0; 
} 

測試在Ubuntu 15.10。

此問題的軸定向版本:https://gamedev.stackexchange.com/questions/35946/how-do-i-implement-camera-axis-aligned-billboards這裏我們已經完成了一個面向觀點的廣告牌。