• 将对象从3D坐标系转换为2D显示空间(立方体)


    将对象从3D坐标系转换为2D显示空间(立方体)

    现在,我们将研究如何将对象的顶点从其本地3D坐标系转换为2D屏幕显示空间。多个对象位于3D世界坐标空间中。单个顶点具有X,Y,Z坐标。这些必须从3D世界空间转换为正在看它们的相机的3D坐标空间。从这里,将顶点从相机空间(也称为视图空间)转换为3D屏幕空间,然后最终在2D屏幕显示空间中显示。形成三角形的三个顶点的组在此过程的早期阶段保持“连接”,直到将它们双线插值进行双线插值,以产生代表三角形以显示在屏幕上的三角形的单个片段的集合。每个片段都有一个3D屏幕X,Y,Z坐标,可用于隐藏表面拆卸等物品。要从3D对象空间移动到3D屏幕空间,使用了模型视图投影矩阵。这些阶段中的每个阶段将在以下小节中更详细地探讨。

    我们将从一个由两个三角形组成的对象开始,然后是一个涉及立方体的示例,然后是一组立方体。

    两个三角形对象

    // ***************************************************
      /* THE DATA
       */
      // anticlockwise/counterclockwise ordering
      private float[] vertices = {      
        // position (x,y,z), colour (r,g,b),    tex coords (s,t)
        -0.5f,  0.5f, 0.0f,  1.0f, 0.0f, 0.0f,  0.0f, 1.0f,  // top left
        -0.5f, -0.5f, 0.0f,  0.0f, 1.0f, 0.0f,  0.0f, 0.0f,  // bottom left
         0.5f, -0.5f, 0.0f,  0.0f, 0.0f, 1.0f,  1.0f, 0.0f,  // bottom right
         0.5f,  0.5f, 0.0f,  1.0f, 1.0f, 1.0f,  1.0f, 1.0f   // top right
      };
      
      private int vertexStride = 8;        // 8 floats per vertex
      private int vertexXYZFloats = 3;     // 3 floats for the position
      private int vertexColourFloats = 3;  // 3 flopats for the colour
      private int vertexTexFloats = 2;     // 2 floats for the texture coordinates
      
      private int[] indices = {            // Note that we start from 0
          0, 1, 2,                         // Triangle 1 is made up of vertices 0, 1 and 2
                                           // in anticlockwise ordering
          0, 2, 3                          // Triangle 2 is made up of vertices 0, 2 and 3 
                                           // in anticlockwise ordering
      };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    上述代码给出数据结构和下一个代码给出了渲染方法。绘制了两个三角形,并用瓦特(Watt)书的前盖绘制纹理。这两个三角形已从观看者旋转,因此从观看者中看到。

    public void render(GL3 gl) {
        gl.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT);
      
        double elapsedTime = getSeconds()-startTime;
        
        Mat4 projectionMatrix = Mat4Transform.perspective(45, aspect);
        
        float zposition = 2f;
        //float zposition = 2f+(float)(Math.sin(Math.toRadians(elapsedTime*50)));
        Vec3 position = new Vec3(0,0,zposition);
        Mat4 viewMatrix = Mat4Transform.lookAt(position, new Vec3(0,0,0), new Vec3(0,1,0));
        
        float angle = -55f;
        //float angle = (float)(-115*Math.sin(Math.toRadians(elapsedTime*50)));
        Mat4 modelMatrix = Mat4Transform.rotateAroundX(angle);
        
        Mat4 mvpMatrix = Mat4.multiply(viewMatrix, modelMatrix);
        mvpMatrix = Mat4.multiply(projectionMatrix, mvpMatrix);
        
        shader.use(gl);
        shader.setFloatArray(gl, "model", modelMatrix.toFloatArrayForGLSL());
        shader.setFloatArray(gl, "view", viewMatrix.toFloatArrayForGLSL());
        shader.setFloatArray(gl, "projection", projectionMatrix.toFloatArrayForGLSL());
        shader.setFloatArray(gl, "mvpMatrix", mvpMatrix.toFloatArrayForGLSL());
        
        gl.glActiveTexture(GL.GL_TEXTURE0);
        gl.glBindTexture(GL.GL_TEXTURE_2D, textureId1[0]);
      
        gl.glBindVertexArray(vertexArrayId[0]);
        gl.glDrawElements(GL.GL_TRIANGLES, indices.length, GL.GL_UNSIGNED_INT, 0);
        gl.glBindVertexArray(0);
      }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32

    使用静态方法mat4transform.perspective()创建投影矩阵。然后使用静态方法mat4transform.lookat(从,到,向上)创建视图矩阵。这需要三个参数:相机位置,相机正在看的目标以及世界的名义向量;在此示例中,摄像机处于位置(0,0,2),着眼于世界原产地,最初的向量(0,1,0)。革兰氏– SCHMIDT过程(如讲座中所述)用于为视图创建坐标框架(即相机)。

    选择–55度的角度将两个三角形旋转X轴旋转,该轴将旋转远离观看器的顶部。静态方法mat4transform.rotatearoundx()用于设置所需的模型转换矩阵。

    在下一步中,计算模型视图投影矩阵。重要的是:请记住,矩阵在它们正在转换的顶点之前。因此,它们是按照投影,视图,模型的,因此模型矩阵是第一个应用于顶点的。

    然后,使用单独的统一制度将ModelMatrix,ViewMatrix,IdjotectionMatrix和MVPMATRIX的每一个都传递到顶点着色器。为此,必须首先将4x4矩阵转换为浮子数组。方法Mat4.tofloatarrayforglsl()用于执行此操作。它将行柱有序的矩阵转换为存储在浮子数组中的列有序矩阵,这是顶点着色器中使用的数据类型中所需的内容。还将一种新方法添加到着色器类中,以在顶点着色器中设置相关的统一。

    在此示例中,我已经将所有4个矩阵传递给着色器,以证明我们可以(i)将模型,视图和投影矩阵分别传递到着色器,或者(ii)将它们组合到CPU上的模型视频预测矩阵中。然后将其传递给着色器,或(iii)同时使用。我们还可以将单个矩阵传递,并将其组合成GPU上的模型观察矩阵 - 这就是Joey在他的教程中所做的。在顶点着色器中编写模型视图预测矩阵的问题是,然后重复对象中每个顶点的相同计算。但是,这对于某些程序可能是必要的,具体取决于所需的内容。在将来的程序中,我们将仅通过模型矩阵和模型视图预测矩阵。原因将在稍后进行解释。

    接下来要看的是顶点着色器,该阴影器在下一个代码中给出。大多数应该对您熟悉。新的制服被称为MAT4型,例如统一MAT4 MVPMATRIX,其中包含从主程序发送的模型视图投影矩阵。这用于乘以顶点的位置,以将其转换为3D屏幕空间(或已知的剪辑空间)。评论的输出线显示,可以在顶点着色器中计算模型观看预测矩阵。

    #version 330 core
    
    layout (location = 0) in vec3 position;
    layout (location = 1) in vec3 color;
    layout (location = 2) in vec2 texCoord;
    
    out vec3 aColor;
    out vec2 aTexCoord;
    
    uniform mat4 model;
    uniform mat4 view;
    uniform mat4 projection;
    uniform mat4 mvpMatrix;
    
    void main() {
      //mat4 mvpMatrix2 = projection * view * model;
      //gl_Position = mvpMatrix2 * vec4(position, 1.0);
      
      gl_Position = mvpMatrix * vec4(position, 1.0);
      
      aColor = color;
      aTexCoord = texCoord;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    顶点着色器的每个实例在不同的顶点上执行相同的操作。 所有顶点都发送到管道的下一个阶段,在那里它们被重新连接在一起以制作三角形,然后将其栅格隔开以产生一组由片段着色器处理的片段。 片段着色器不需要从我们以前的程序中更改。 它只是使用相关纹理坐标来算出片段的颜色。 我们在三角数据结构中使用的颜色属性被忽略(因此可以从示例中删除)。

    我们现在有一个工作的3D世界。

    (1) 一个立方体对象
    立方体的每个面都有纹理坐标在0.0,0.0至1.0,1.0的范围内

    // ***************************************************
      /* THE DATA
       */
      // anticlockwise/counterclockwise ordering
      
       private float[] vertices = new float[] {  // x,y,z, colour, s,t
          -0.5f, -0.5f, -0.5f,  1.0f, 0.0f, 0.0f,  0.0f, 0.0f,  // 0
          -0.5f, -0.5f,  0.5f,  1.0f, 0.0f, 0.0f,  1.0f, 0.0f,  // 1
          -0.5f,  0.5f, -0.5f,  1.0f, 0.0f, 0.0f,  0.0f, 1.0f,  // 2
          -0.5f,  0.5f,  0.5f,  1.0f, 0.0f, 0.0f,  1.0f, 1.0f,  // 3
           0.5f, -0.5f, -0.5f,  1.0f, 0.0f, 0.0f,  1.0f, 0.0f,  // 4
           0.5f, -0.5f,  0.5f,  1.0f, 0.0f, 0.0f,  0.0f, 0.0f,  // 5
           0.5f,  0.5f, -0.5f,  1.0f, 0.0f, 0.0f,  1.0f, 1.0f,  // 6
           0.5f,  0.5f,  0.5f,  1.0f, 0.0f, 0.0f,  0.0f, 1.0f,  // 7
    
          -0.5f, -0.5f, -0.5f,  0.0f, 1.0f, 0.0f,  1.0f, 0.0f,  // 8
          -0.5f, -0.5f,  0.5f,  0.0f, 1.0f, 0.0f,  0.0f, 0.0f,  // 9
          -0.5f,  0.5f, -0.5f,  0.0f, 1.0f, 0.0f,  1.0f, 1.0f,  // 10
          -0.5f,  0.5f,  0.5f,  0.0f, 1.0f, 0.0f,  0.0f, 1.0f,  // 11
           0.5f, -0.5f, -0.5f,  0.0f, 1.0f, 0.0f,  0.0f, 0.0f,  // 12
           0.5f, -0.5f,  0.5f,  0.0f, 1.0f, 0.0f,  1.0f, 0.0f,  // 13
           0.5f,  0.5f, -0.5f,  0.0f, 1.0f, 0.0f,  0.0f, 1.0f,  // 14
           0.5f,  0.5f,  0.5f,  0.0f, 1.0f, 0.0f,  1.0f, 1.0f,  // 15
    
          -0.5f, -0.5f, -0.5f,  0.0f, 0.0f, 1.0f,  0.0f, 0.0f,  // 16
          -0.5f, -0.5f,  0.5f,  0.0f, 0.0f, 1.0f,  0.0f, 1.0f,  // 17
          -0.5f,  0.5f, -0.5f,  0.0f, 0.0f, 1.0f,  0.0f, 1.0f,  // 18
          -0.5f,  0.5f,  0.5f,  0.0f, 0.0f, 1.0f,  0.0f, 0.0f,  // 19
           0.5f, -0.5f, -0.5f,  0.0f, 0.0f, 1.0f,  1.0f, 0.0f,  // 20
           0.5f, -0.5f,  0.5f,  0.0f, 0.0f, 1.0f,  1.0f, 1.0f,  // 21
           0.5f,  0.5f, -0.5f,  0.0f, 0.0f, 1.0f,  1.0f, 1.0f,  // 22
           0.5f,  0.5f,  0.5f,  0.0f, 0.0f, 1.0f,  1.0f, 0.0f   // 23
         };
        
         private int[] indices =  new int[] {
          0,1,3, // x -ve 
          3,2,0, // x -ve
          4,6,7, // x +ve
          7,5,4, // x +ve
          9,13,15, // z +ve
          15,11,9, // z +ve
          8,10,14, // z -ve
          14,12,8, // z -ve
          16,20,21, // y -ve
          21,17,16, // y -ve
          23,22,18, // y +ve
          18,19,23  // y +ve
        };
        
      private int vertexStride = 8;
      private int vertexXYZFloats = 3;
      private int vertexColourFloats = 3;
      private int vertexTexFloats = 2;
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53

    给出渲染方法和随附的方法,用于防止渲染方法变得混乱。 getModelMatrix()返回模型变换矩阵。 在这里,它只是返回身份矩阵。 GetViewMatrix()将相机设置为位置(2,3,4),查看原点(0,0,0),名义上向量为(0,1,0)。

     public void render(GL3 gl) {
        gl.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT);
    
        Mat4 projectionMatrix = Mat4Transform.perspective(45, aspect);
        Mat4 viewMatrix = getViewMatrix();
        Mat4 modelMatrix = getModelMatrix();
        Mat4 mvpMatrix = Mat4.multiply(projectionMatrix, Mat4.multiply(viewMatrix, modelMatrix));
        
        shader.use(gl);
        shader.setFloatArray(gl, "model", modelMatrix.toFloatArrayForGLSL());
        shader.setFloatArray(gl, "view", viewMatrix.toFloatArrayForGLSL());
        shader.setFloatArray(gl, "projection", projectionMatrix.toFloatArrayForGLSL());
        shader.setFloatArray(gl, "mvpMatrix", mvpMatrix.toFloatArrayForGLSL());
        
        gl.glActiveTexture(GL.GL_TEXTURE0);
        gl.glBindTexture(GL.GL_TEXTURE_2D, textureId1[0]);
      
        gl.glBindVertexArray(vertexArrayId[0]);
        gl.glDrawElements(GL.GL_TRIANGLES, indices.length, GL.GL_UNSIGNED_INT, 0);
        gl.glBindVertexArray(0);
      }
      
      private Mat4 getModelMatrix() {
        double elapsedTime = getSeconds()-startTime;
        //float angle = -55;
        //float angle = (float)(-115*Math.sin(Math.toRadians(elapsedTime*50)));
        Mat4 modelMatrix = new Mat4(1);
        //modelMatrix = Mat4.multiply(Mat4Transform.rotateAroundY(angle), modelMatrix);
        //modelMatrix = Mat4.multiply(Mat4Transform.rotateAroundX(angle), modelMatrix);
        return modelMatrix;
      }
      
      private Mat4 getViewMatrix() {
        double elapsedTime = getSeconds()-startTime;
        float xposition = 2;
        float yposition = 3;
        float zposition = 4;
        //float xposition = 3.0f*(float)(Math.sin(Math.toRadians(elapsedTime*50)));
        //float zposition = 3.0f*(float)(Math.cos(Math.toRadians(elapsedTime*50)));
        Mat4 viewMatrix = Mat4Transform.lookAt(new Vec3(xposition,yposition,zposition), 
                                               new Vec3(0,0,0), new Vec3(0,1,0));
        return viewMatrix;
      }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43

    练习
    首先尝试GetViewMatrix()中的评论线。 这些将使围绕世界轴的相机位置旋转,以便相机一直在看世界的起源。 只有一个物体以屏幕上的世界来源为中心,它可以(令人困惑)看起来像对象正在旋转,而不是摄像机旋转。
    在更改GetModelMatrix()之前,将视图位置设置回2,3,4的固定值。 现在,在GetModelMatrix()中评论一些行。 在运行程序之前尝试猜测效果。

    (2)一群立方体
    多维数据集数据结构中使用的纹理坐标已更改,以便每个面使用纹理的一部分。 您应该在v03_gleventlistener.java中检查此数据结构。

    Rendering a 5x5 grid of cubes

    public void render(GL3 gl) {
        gl.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT);
    
        Mat4 projectionMatrix = Mat4Transform.perspective(45, aspect);
        Mat4 viewMatrix = getViewMatrix();
        
        shader.use(gl);
        shader.setFloatArray(gl, "view", viewMatrix.toFloatArrayForGLSL());
        shader.setFloatArray(gl, "projection", projectionMatrix.toFloatArrayForGLSL());
        
        gl.glActiveTexture(GL.GL_TEXTURE0);
        gl.glBindTexture(GL.GL_TEXTURE_2D, textureId1[0]);
      
        for (int i=-2; i<3; ++i) {
          for (int j=-2; j<3; ++j) {
            Mat4 modelMatrix = getModelMatrix(2f*i, 2f*j);
            Mat4 mvpMatrix = Mat4.multiply(projectionMatrix, Mat4.multiply(viewMatrix, modelMatrix));
    
            shader.setFloatArray(gl, "model", modelMatrix.toFloatArrayForGLSL());
            shader.setFloatArray(gl, "mvpMatrix", mvpMatrix.toFloatArrayForGLSL());
    
            gl.glBindVertexArray(vertexArrayId[0]);
            gl.glDrawElements(GL.GL_TRIANGLES, indices.length, GL.GL_UNSIGNED_INT, 0);
            gl.glBindVertexArray(0);
          }
        }
      }
        
      private Mat4 getModelMatrix(float i, float j) {
        double elapsedTime = getSeconds()-startTime;
        float angle = (float)(elapsedTime*50);
        Mat4 modelMatrix = new Mat4(1);    
        //modelMatrix = Mat4.multiply(modelMatrix, Mat4Transform.rotateAroundY(angle));
        modelMatrix = Mat4.multiply(modelMatrix, Mat4Transform.translate(i, 0, j));
        //modelMatrix = Mat4.multiply(modelMatrix, Mat4Transform.rotateAroundX(angle));
        modelMatrix = Mat4.multiply(modelMatrix, Mat4Transform.rotateAroundY(angle));
        return modelMatrix;
      }
      
      private Mat4 getViewMatrix() {
        double elapsedTime = getSeconds()-startTime;
        Vec3 pos = new Vec3(4,6,10);
        Mat4 viewMatrix = Mat4Transform.lookAt(pos, new Vec3(0,0,0), new Vec3(0,1,0));
        return viewMatrix;
      }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45

    (3)更多的立方体
    此示例显示了100个随机定位的立方体。该程序类似于v03.java,其中一个主要区别。 立方体位于随机位置,而不是正常网格的一部分。 每次渲染场景时,都必须生成相同的随机位置。 这是使用程序运行后一次创建的随机数的全局数组来完成的。

     public void render(GL3 gl) {
        gl.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT);
    
        Mat4 projectionMatrix = Mat4Transform.perspective(45, aspect);
        Mat4 viewMatrix = getViewMatrix();
        
        shader.use(gl);
        shader.setFloatArray(gl, "view", viewMatrix.toFloatArrayForGLSL());
        shader.setFloatArray(gl, "projection", projectionMatrix.toFloatArrayForGLSL());
        
        gl.glActiveTexture(GL.GL_TEXTURE0);
        gl.glBindTexture(GL.GL_TEXTURE_2D, textureId1[0]);
      
        for (int i=0; i<100; ++i) {
          Mat4 modelMatrix = getModelMatrix(i);
          Mat4 mvpMatrix = Mat4.multiply(projectionMatrix, Mat4.multiply(viewMatrix, modelMatrix));
            
          shader.setFloatArray(gl, "model", modelMatrix.toFloatArrayForGLSL());
          shader.setFloatArray(gl, "mvpMatrix", mvpMatrix.toFloatArrayForGLSL());
          
          gl.glBindVertexArray(vertexArrayId[0]);
          gl.glDrawElements(GL.GL_TRIANGLES, indices.length, GL.GL_UNSIGNED_INT, 0);
          gl.glBindVertexArray(0);
        }
      }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
  • 相关阅读:
    重数和众数问题——C语言实现
    【JDBC篇】 preparedStatement和Statement区别
    【摘抄】quant4j
    Golang 互斥锁
    十二、Django之模板的继承+用户列表
    使用 OpenCV 进行图像投影变换
    【滤波】概率、高斯和贝叶斯
    【C语言】深入浅出理解指针及内存与指针的关系(详细讲解+代码展示)
    hadoop生态圈面试精华之Yarn
    视频编解码 — 码控算法
  • 原文地址:https://blog.csdn.net/kirsten111111/article/details/127896359