精华内容
下载资源
问答
  • OPENGL 纹理正射投影

    2015-04-01 10:39:54
    我现在要用opengl读取一个obj文件(已用glm实现),然后对模型纹理进行正射投影(投影到z值为0的平面上),导出投影纠正过的纹理图(tiff格式)。 接到任务说要写一个投影纠正的小工具才接触opengl,纹理投影的坐标...
  • 上节谈到投影变换分为透视投影(perspective projection)和正射投影(orthographic projection)两种. 透视投影我们已经介绍过了, 现在谈谈正视投影. 正射投影,又叫平行投影.这种投影是一个矩形长方体的平行管道. 它...

     

    上节谈到投影变换分为透视投影(perspective projection)和正射投影(orthographic projection)两种.

    透视投影我们已经介绍过了, 现在谈谈正视投影.

    正射投影,又叫平行投影.这种投影是一个矩形长方体的平行管道. 它最大的特点是, 无论物体距离相机多远投影后的物体大小尺寸不变.

     正视投影函数有两个, 一个是Ortho, 原形如下:

    Ortho(double left, double right, double bottom, double top, double near, double far)

    其参数 left,right,bottom, top的意义见下图所示. 

    near, far 可以认为是Z轴方向上的近裁剪平面和远裁剪平面.

     

     下面这张示意图是把三维体放置在视景体中, 看上去更形象些.

     

     

    笔者为了理解什么是正射投影以及Ortho函数的效果, 在网上翻遍了资料, 都是笼统的文字叙述, 或者是表达有误. 甚至找不到一个直观示意效果图.

    后来还是在3dsmax的摄像机属性中看到了"正交投影" 这个属性.  在3dsmax和autoCAD中, Ortho这个单词都被翻译为"正交". 因此"正交"和"正射"表达的是一个东西.

     

    事实证明, 有了3dsmax这样的工具, 可以有效的实践一些原理上的东西, 确实对学习OpenGL很有帮助. 

    请看下面的实验, 它帮助笔者理解了什么是正射投影? 它的效果是怎么样的? 这样的疑惑.

     

     下图是在3dsmax创建的一个场景:
     注意其Camera01视图,  它显示的是摄像机在透视投影下看到一个立方体(线框显示)

     

    同样的场景, 把摄像机改为"正交投影", 可以看到现在的立方体完全没有了透视效果. 这是因为这立方体相当于放置在一个矩形长方体管道中, 投影完全平行, 没有了像透视投影那样的角度发散的效果.

    这就是正射投影的最大特点: 无论物体距离相机有多远投影后的物体大小尺寸不变.

     

     

    下面我们用代码来继续讨论一下Ortho() 函数.

    先上个透视投影的效果图, 如下:

    这个三角形是画在Z为0的世界坐标系平面上的, 因此LookAt的前三个参数设置0,0,1, 表示摄像机xy指向世界坐标系原点, 摄像机的Z向世界坐标系统的Z正方向走1个单位, 即远离了三角形一个单位, 因此我们能看到三角形了.

     

    现在我们把Perspective改为Ortho.

    gl.Ortho(-2, 2, -3,3, -2, -5);
    gl.LookAt(0, 0, 1, 0, 0, -10, 0, 1, 0);

    跑起来, 屏幕上什么都没有.

    这是因为LookAt的第三个参数eyez, 没有位于Ortho参数near和far(即-2, -5)之间的原因. 

    gl.LookAt(0, 0, -3, 0, 0, -10, 0, 1, 0);

    eyez改为-3就可以看到三角形了.

     

    我来总结一下:

    经过 gl.Ortho(-2, 2, -3,3, -2, -5) 正射投影之后, 三角形就被置于这个矩形长方体(-2, 2, -3,3, -2, -5)的视景体中了, 以后LooAt 就是在看这个视影体中的内容, 如果摄像机的视点设置有超出这视景体的部分将看不到, 相当于被剪切了.

     

    另外一个函数是 Ortho2D(), 它和Ortho不同的是缺少最后两上参数Near, Far, 这个Ortho2D()实际上是默认near为-1, far为1的Ortho()函数. 

    笔者并不清楚它有什么作用, 如果以后遇到好的例子, 我会在这里续写这个知识点.

     

     

    本节源代码直接使用上节的源码

     

    原创文章,出自"博客园, 猪悟能'S博客" : http://www.cnblogs.com/hackpig/

     

    转载于:https://www.cnblogs.com/hackpig/p/5790379.html

    展开全文
  • 前言 OpenGLES Android篇零基础系统前面已经写了三篇了,因为OpenGL里面的水着实是深,所以里面好多的概念都没有去查资料,如果一碰到不会的就去查,就感觉没有连贯性。...而转变的方式有透视、正射,首先我们

    前言

     OpenGLES Android篇零基础系统前面已经写了三篇了,因为OpenGL里面的水着实是深,所以里面好多的概念都没有去查资料,如果一碰到不会的就去查,就感觉没有连贯性。所以就只能是先一笔带过,然后再慢慢研究。
    

    正文

    前面我们已经了解到,OpenGL其实是把物体从世界坐标系通过各种复杂的转变,计算等变成屏幕坐标系,显示在视口中。即:把三维物体转变为二维图像。而转变的方式有透视、正射,

    首先我们看下何谓视景体
    视景体:就是一个可以观看投影物体的可视区域,由近平面,远平面,左,上,右,下各面组成。
    只有在可视区域内才可见,区域外会被裁剪。

    透视投影

    假设有一个视点E(Xp,Yp,Zp),以及世界坐标系中任意一点X(Xa,Ya,Za),还有置于E与X之间的一个视平面P(或近平面)。然后以X为起点,向视点E做射线,与视平面相交于点S。点S即为我们看到的点。下面我偷个图一看就明白了:
    这里写图片描述

    这种投影就与我们现实生活中用肉眼看东西时很接近了,很逼真。
    用一个有照相机的图如下 :
    这里写图片描述

    在OpenGLES2.x中我们这样用PerspectiveProjection透视投影:

    //定义一个16x16的透视矩阵
    private final float[] mProjMatrix = new float[16];
    //视图矩阵
    private final float[] mVMatrix= new float[16];
    //透视矩阵与视图矩阵变换后的总矩阵
    private final float[] mMVPMatrix= new float[16];
    /**
    *横竖屏切换时调用
    *
    **/
    public void onSurfaceChanged(GL10 gl, int width, int height) {
     float ratio = (float) width / height;
            // this projection matrix is applied to object coordinates
            // in the onDrawFrame() method
            //创建一个透视视景体
            //注意:near,far都必须大于0,且二者不能相等,
            Matrix.frustumM(mProjMatrix, 0, -ratio, ratio, -1, 1, 3, 7);
    }
    
    
     public void onDrawFrame(GL10 gl) {
      Matrix.setLookAtM(mVMatrix, 0, 0, 0, -3, 0f, 0f, 0f, 0f, 1f, 0f);
            // Calculate the projection and view transformation
            Matrix.multiplyMM(mMVPMatrix, 0, mProjMatrix, 0, mVMatrix, 0);
     }

    如上,当我们拿到顶点的变化总矩阵后,就可以为GLSL中的MVPMatrix索引赋值,那样最终得到的gl_Position就能正确在屏幕上展示:

     /**
         * 顶点着色器的语句
         */
        private final String mVertexShader =
                "attribute vec4 position;\n" +
                        "uniform mat4 uMVPMatrix;" +
                        "void main(){\n" +
                        "gl_Position = uMVPMatrix * position ;\n" +
                        "};\n"

    正射投影

    正射投影又称正交投影,其视景体为长方体,投影物体的大小不会随视点与远平面之间的距离而变化,
    这也是与透视投影最大的区别。见下图:
    这里写图片描述

    突然来任务了,来不及往下写,思绪也被打乱了,只能把任务完成,然后再续

    展开全文
  • WebGL 三维正射投影

    2019-08-01 20:35:53
    上一篇文章概述了二维矩阵的工作原理,我们讲到了如何平移, 旋转,缩放甚至从像素空间投影到裁剪空间,并且将这些操作通过一个矩阵实现, 做三维只需要再迈出一小步。 二维例子中的二维点 (x, y) 与 3x3 的矩阵...

    本文来自:https://webglfundamentals.org/webgl/lessons/zh_cn/webgl-3d-orthographic.html

    --------------------------------

    此文上接一系列相关文章,首先是基础概念,上一篇是 二维矩阵运算,如果没读过请从那里开始。

    上一篇文章概述了二维矩阵的工作原理,我们讲到了如何平移, 旋转,缩放甚至从像素空间投影到裁剪空间,并且将这些操作通过一个矩阵实现, 做三维只需要再迈出一小步。

    二维例子中的二维点 (x, y) 与 3x3 的矩阵相乘, 在三维中我们需要三维点 (x, y, z) 与 4x4 的矩阵相乘。

    让我们将上个例子改成三维的,这里会继续使用 F ,但是这次是三维的 'F' 。

    首先需要修改顶点着色器以支持三维处理,这是原顶点着色器,

    <script id="2d-vertex-shader" type="x-shader/x-vertex">
    attribute vec2 a_position;
    
    uniform mat3 u_matrix;
    
    void main() {
      // 将位置和矩阵相乘
      gl_Position = vec4((u_matrix * vec3(a_position, 1)).xy, 0, 1);
    }
    </script>
    

    这是新着色器

    <script id="3d-vertex-shader" type="x-shader/x-vertex">
    attribute vec4 a_position;
    
    uniform mat4 u_matrix;
    
    void main() {
      // 将位置和矩阵相乘
      gl_Position = u_matrix * a_position;
    }
    </script>
    

    它甚至变简单了!在二维中我们提供xy并设置z为1, 在三维中我们将提供xyz,然后将w设置为1, 而在属性中w的默认值就是1,我们可以利用这点不用再次设置。

    然后提供三维数据。

    // 告诉属性怎么从 positionBuffer (ARRAY_BUFFER) 中读取位置
      var size = 3;          // 每次迭代使用 3 个单位的数据
      var type = gl.FLOAT;   // 单位数据类型是32位的浮点型
      var normalize = false; // 不需要归一化数据
      var stride = 0;        // 0 = 移动距离 * 单位距离长度sizeof(type)  每次迭代跳多少距离到下一个数据
      var offset = 0;        // 从绑定缓冲的起始处开始
      gl.vertexAttribPointer(
          positionAttributeLocation, size, type, normalize, stride, offset);
    
      ...
    
    // 填充当前 ARRAY_BUFFER 缓冲
    // 使用组成 'F' 的数据填充缓冲.
    function setGeometry(gl) {
      gl.bufferData(
          gl.ARRAY_BUFFER,
          new Float32Array([
               // 左竖
                0,   0,  0,
               30,   0,  0,
                0, 150,  0,
                0, 150,  0,
               30,   0,  0,
               30, 150,  0,
    
               // 上横
               30,   0,  0,
              100,   0,  0,
               30,  30,  0,
               30,  30,  0,
              100,   0,  0,
              100,  30,  0,
    
               // 下横
               30,  60,  0,
               67,  60,  0,
               30,  90,  0,
               30,  90,  0,
               67,  60,  0,
               67,  90,  0]),
          gl.STATIC_DRAW);
    }
    

    接下来把二维矩阵方法改成三维的

    这是二维(之前的)版本的 m3.translation, m3.rotation, 和 m3.scaling 方法

    var m3 = {
      translation: function translation(tx, ty) {
        return [
          1, 0, 0,
          0, 1, 0,
          tx, ty, 1
        ];
      },
    
      rotation: function rotation(angleInRadians) {
        var c = Math.cos(angleInRadians);
        var s = Math.sin(angleInRadians);
        return [
          c,-s, 0,
          s, c, 0,
          0, 0, 1
        ];
      },
    
      scaling: function scaling(sx, sy) {
        return [
          sx, 0, 0,
          0, sy, 0,
          0, 0, 1
        ];
      },
    };
    

    这是升级到三维的版本。

    var m4 = {
      translation: function(tx, ty, tz) {
        return [
           1,  0,  0,  0,
           0,  1,  0,  0,
           0,  0,  1,  0,
           tx, ty, tz, 1,
        ];
      },
    
      xRotation: function(angleInRadians) {
        var c = Math.cos(angleInRadians);
        var s = Math.sin(angleInRadians);
    
        return [
          1, 0, 0, 0,
          0, c, s, 0,
          0, -s, c, 0,
          0, 0, 0, 1,
        ];
      },
    
      yRotation: function(angleInRadians) {
        var c = Math.cos(angleInRadians);
        var s = Math.sin(angleInRadians);
    
        return [
          c, 0, -s, 0,
          0, 1, 0, 0,
          s, 0, c, 0,
          0, 0, 0, 1,
        ];
      },
    
      zRotation: function(angleInRadians) {
        var c = Math.cos(angleInRadians);
        var s = Math.sin(angleInRadians);
    
        return [
           c, s, 0, 0,
          -s, c, 0, 0,
           0, 0, 1, 0,
           0, 0, 0, 1,
        ];
      },
    
      scaling: function(sx, sy, sz) {
        return [
          sx, 0,  0,  0,
          0, sy,  0,  0,
          0,  0, sz,  0,
          0,  0,  0,  1,
        ];
      },
    };
    

    注意到我们现在有三个旋转方法,在二维中只需要一个是因为我们只需要绕 Z 轴旋转,现在在三维中还可以绕 X 轴和 Y 轴旋转。它们看起来还是很简单, 如果使用它们后你会发现和之前一样

    绕 Z 轴旋转

    newX = x * c + y * s;

    newY = x * -s + y * c;

    绕 Y 轴旋转

    newX = x * c + z * s;

    newZ = x * -s + z * c;

    绕 X 轴旋转

    newY = y * c + z * s;

    newZ = y * -s + z * c;

    它们提供这些旋转方式。

    同样的我们将实现一些简单的方法

    translate: function(m, tx, ty, tz) {
        return m4.multiply(m, m4.translation(tx, ty, tz));
      },
    
      xRotate: function(m, angleInRadians) {
        return m4.multiply(m, m4.xRotation(angleInRadians));
      },
    
      yRotate: function(m, angleInRadians) {
        return m4.multiply(m, m4.yRotation(angleInRadians));
      },
    
      zRotate: function(m, angleInRadians) {
        return m4.multiply(m, m4.zRotation(angleInRadians));
      },
    
      scale: function(m, sx, sy, sz) {
        return m4.multiply(m, m4.scaling(sx, sy, sz));
      },
    

    我们还需要更新投影方法,这是原代码

      projection: function (width, height) {
        // 注意:这个矩阵翻转了 Y 轴,所以 0 在上方
        return [
          2 / width, 0, 0,
          0, -2 / height, 0,
          -1, 1, 1
        ];
      },
    }
    

    它将像素坐标转换到裁剪空间,在初次尝试三维时我们将这样做

      projection: function(width, height, depth) {
        // 注意:这个矩阵翻转了 Y 轴,所以 0 在上方
        return [
           2 / width, 0, 0, 0,
           0, -2 / height, 0, 0,
           0, 0, 2 / depth, 0,
          -1, 1, 0, 1,
        ];
      },
    

    就像 X 和 Y 需要从像素空间转换到裁剪空间一样,Z 也需要。在这个例子中我也将 Z 单位化了,我会传递一些和 width 相似的值给 depth ,所以我们的空间将会是 0 到 width 像素宽,0 到 height 像素高, 但是对于depth将会是 -depth / 2 到 +depth / 2 。

    最后需要更新计算矩阵的代码

      // 计算矩阵
      var matrix = m4.projection(gl.canvas.clientWidth, gl.canvas.clientHeight, 400);
      matrix = m4.translate(matrix, translation[0], translation[1], translation[2]);
      matrix = m4.xRotate(matrix, rotation[0]);
      matrix = m4.yRotate(matrix, rotation[1]);
      matrix = m4.zRotate(matrix, rotation[2]);
      matrix = m4.scale(matrix, scale[0], scale[1], scale[2]);
    
      // 设置矩阵
      gl.uniformMatrix4fv(matrixLocation, false, matrix);
    

    这是结果(https://webglfundamentals.org/webgl/webgl-3d-step1.html):

    我们遇到的第一个问题是 F 在三维中过于扁平, 所以很难看出三维效果。解决这个问题的方法是将它拉伸成三维几何体。现在的 F 是由三个矩形组成,每个矩形两个三角形。让它变三维需要 16 个矩形。三个矩形在正面,三个背面,一个左侧,四个右侧,两个上侧,三个底面。

    需要列出的还有很多,16 个矩形每个有两个三角形,每个三角形有 3 个顶点, 所以一共有 96 个顶点。如果你想看这些可以去示例的源码里找。

    我们需要绘制更多顶点所以

        // 绘制几何体
        var primitiveType = gl.TRIANGLES;
        var offset = 0;
        var count = 16 * 6;
        gl.drawArrays(primitiveType, offset, count);
    
    

    这是对应结果(https://webglfundamentals.org/webgl/webgl-3d-step2.html)

    拖动滑块很难看出它是三维的,让我们给矩形上不同的颜色。需要在顶点着色器中添加一个属性和一个可变量, 将颜色值传到片断着色器中。

    这是新的顶点着色器

    <script id="3d-vertex-shader" type="x-shader/x-vertex">
    attribute vec4 a_position;
    attribute vec4 a_color;
    
    uniform mat4 u_matrix;
    
    varying vec4 v_color;
    
    void main() {
      // 将位置和矩阵相乘.
      gl_Position = u_matrix * a_position;
    
      // 将颜色传递给片断着色器
      v_color = a_color;
    }
    </script>
    

    然后在片断着色器中使用颜色

    <script id="3d-vertex-shader" type="x-shader/x-fragment">
    precision mediump float;
    
    // 从顶点着色器中传入
    varying vec4 v_color;
    
    void main() {
       gl_FragColor = v_color;
    }
    </script>
    

    我们需要找到属性的位置,然后在另一个缓冲中存入对应的颜色。

    ...
      var colorLocation = gl.getAttribLocation(program, "a_color");
    
      ...
      // 给颜色创建一个缓冲
      var colorBuffer = gl.createBuffer();
      gl.bindBuffer(gl.ARRAY_BUFFER, colorBuffer);
      // 将颜色值传入缓冲
      setColors(gl);
    
    
      ...
    // 向缓冲传入 'F' 的颜色值
    
    function setColors(gl) {
      gl.bufferData(
          gl.ARRAY_BUFFER,
          new Uint8Array([
            // 正面左竖
            200,  70, 120,
            200,  70, 120,
            200,  70, 120,
            200,  70, 120,
            200,  70, 120,
            200,  70, 120,
    
            // 正面上横
            200,  70, 120,
            200,  70, 120,
            ...
            ...
          gl.STATIC_DRAW);
    }
    

    在渲染时告诉颜色属性如何从缓冲中获取颜色值

    // 启用颜色属性
    gl.enableVertexAttribArray(colorLocation);
    
    // 绑定颜色缓冲
    gl.bindBuffer(gl.ARRAY_BUFFER, colorBuffer);
    
    // 告诉颜色属性怎么从 colorBuffer (ARRAY_BUFFER) 中读取颜色值
    var size = 3;                 // 每次迭代使用3个单位的数据
    var type = gl.UNSIGNED_BYTE;  // 单位数据类型是无符号 8 位整数
    var normalize = true;         // 标准化数据 (从 0-255 转换到 0.0-1.0)
    var stride = 0;               // 0 = 移动距离 * 单位距离长度sizeof(type)  每次迭代跳多少距离到下一个数据
    var offset = 0;               // 从绑定缓冲的起始处开始
    gl.vertexAttribPointer(
        colorLocation, size, type, normalize, stride, offset)
    

    现在我们得到这个(https://webglfundamentals.org/webgl/webgl-3d-step3.html)。

    呃,发生了什么?它好像把 'F' 的所有部分都按照提供的顺序显示出来了, 正面,背面,侧面等等。有时候这并不是想要的结果,在背面的物体反而被绘制出来了。

    红色部分 是 'F' 的正面,但是因为它在数据的前部所以最先被绘制出来,然后它后面的面绘制后挡住了它。例如紫色部分 实际上是 'F' 的背面,由于它在数据中是第二个所以第二个被画出来。

    WebGL中的三角形有正反面的概念,正面三角形的顶点顺序是逆时针方向, 反面三角形是顺时针方向。 

    WebGL可以只绘制正面或反面三角形,可以这样开启:

    gl.enable(gl.CULL_FACE);
    

    将它放在 drawScene 方法里,开启这个特性后WebGL默认“剔除”背面三角形, "剔除"在这里是“不用绘制”的花哨叫法。

    对于WebGL而言,一个三角形是顺时针还是逆时针是根据裁剪空间中的顶点顺序判断的, 换句话说,WebGL是根据你在顶点着色器中运算后提供的结果来判定的, 这就意味着如果你把一个顺时针的三角形沿 X 轴缩放 -1 ,它将会变成逆时针, 或者将顺时针的三角形旋转180度后变成逆时针。由于我们没有开启 CULL_FACE, 所以可以同时看到顺时针(正面)和逆时针(反面)三角形。现在开启了, 任何时候正面三角形无论是缩放还是旋转的原因导致翻转了,WebGL就不会绘制它。这件事很有用,因为通常情况下你只需要看到你正面对的面。

    开启 CULL_FACE 后得到(https://webglfundamentals.org/webgl/webgl-3d-step4.html)

    嗨!三角形都去哪了?结果证明,大多数三角形朝向都是错的, 旋转的时候你会看到背面的三角形,幸好它很容易解决, 我们只需要看看哪些是三角形是反的,然后交换它们的两个顶点。例如一个反的三角形:

       1,   2,   3,
       40,  50,  60,
       700, 800, 900,
    

    只需要交换后两个顶点的位置:

           1,   2,   3,
           700, 800, 900,
           40,  50,  60,
    

    通过修正朝向错误后得到(https://webglfundamentals.org/webgl/webgl-3d-step5.html):

    这很接近实际效果了但是还有一个问题,即使所有三角形的朝向是正确的, 然后背面的被剔除了,有些应该在背面的部分还是出现在了前面。

    接触 DEPTH BUFFER(深度缓冲)。

    深度缓冲有时也叫 Z-Buffer,是一个存储像素深度的矩形, 一个深度像素对应一个着色像素,在绘制图像时组合使用。当WebGL绘制每个着色像素时也会写入深度像素, 它的值基于顶点着色器返回的Z值,就像我们将 X 和 Y 转换到裁剪空间一样, Z 也在裁剪空间或者 (-1 到 +1) 。这个值会被转换到深度空间( 0 到 +1), WebGL绘制一个着色像素之前会检查对应的深度像素, 如果对应的深度像素中的深度值小于当前像素的深度值,WebGL就不会绘制新的颜色。反之它会绘制片断着色器提供的新颜色并更新深度像素中的深度值。这也意味着在其他像素后面的像素不会被绘制。

    我们可以像这样开启这个特性:

      gl.enable(gl.DEPTH_TEST);
    

    在开始绘制前还需要清除深度缓冲为 1.0 。

       // 绘制场景
      function drawScene() {
        ...
    
        // 清空画布和深度缓冲
        gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
    
        ...
    

    现在得到(https://webglfundamentals.org/webgl/webgl-3d-step6.html):

    这才是三维!

    还有一件小事,在大多数三维数学库中没有负责像素空间与裁剪空间转换的 projection 方法。代替的是叫做 ortho 或 orthographic 的方法,它看起来像这样:

    var m4 = {
      orthographic: function(left, right, bottom, top, near, far) {
        return [
          2 / (right - left), 0, 0, 0,
          0, 2 / (top - bottom), 0, 0,
          0, 0, 2 / (near - far), 0,
    
          (left + right) / (left - right),
          (bottom + top) / (bottom - top),
          (near + far) / (near - far),
          1,
        ];
      }
    

    和我们简单的 projection 方法不同的是正射投影有更多的参数可以传递, 左,右,上,下,近和远,给我们更灵活的选择。为了用这个方法实现之前的投影, 需要这样调用:

    var left = 0;
    var right = gl.canvas.clientWidth;
    var bottom = gl.canvas.clientHeight;
    var top = 0;
    var near = 400;
    var far = -400;
    m4.orthographic(left, right, bottom, top, near, far);
    

    下一篇将讲述如何实现透视投影。

    番外:

    为什么属性类型是 vec4 但是 gl.vertexAttribPointer 的大小是 3
    注意细节的你可能发现,我们定义了这样两个属性

    attribute vec4 a_position;
    attribute vec4 a_color;
    

    两个都是 'vec4' 类型,当我们告诉WebGL如何从缓冲中获取数据时使用

    // 告诉属性怎么从 positionBuffer (ARRAY_BUFFER) 中读取位置
    var size = 3;          // 每次迭代使用 3 个单位的数据
    var type = gl.FLOAT;   // 单位数据类型是32位的浮点型
    var normalize = false; // 不需要归一化数据
    var stride = 0;        // 0 = 移动距离 * 单位距离长度sizeof(type)
                           // 每次迭代跳多少距离到下一个数据
    var offset = 0;        // 从绑定缓冲的起始处开始
    gl.vertexAttribPointer(
        positionAttributeLocation, size, type, normalize, stride, offset);
    
    ...
    // 告诉颜色属性怎么从 colorBuffer (ARRAY_BUFFER) 中读取颜色值
    var size = 3;          // 每次迭代使用3个单位的数据
    var type = gl.UNSIGNED_BYTE;   // 单位数据类型是无符号 8 位整数
    var normalize = true;  // 标准化数据 (从 0-255 转换到 0.0-1.0)
    var stride = 0;        // 0 = 移动距离 * 单位距离长度sizeof(type)
                           // 每次迭代跳多少距离到下一个数据
    var offset = 0;        // 从绑定缓冲的起始处开始
    gl.vertexAttribPointer(
        colorAttributeLocation, size, type, normalize, stride, offset);
    

    这里的 '3' 表示的时每次迭代从缓冲中提取三个值给顶点着色器中的属性。能正常运行是因为WebGL会给这些值设定默认值,默认值是0, 0, 0, 1 也就是 x = 0, y = 0, z = 0 和 w = 1 。我们需要传入 x 和 y 并且需要 z 是 1 , 由于 z 的默认值是 0 所以我们需要额外提供 z 值,对于三维,即使我们没有提供 'w', 默认的 1 正是矩阵运算需要的值。

    前端qq群:850038125

    前端微信群:

    展开全文
  • far:远平面距离 * near、far 可以认为是Z轴方向上的近裁剪平面和远裁剪平面 * 正射投影的最大特点:无论物体距离相机有多远,投影后的物体大小尺寸不变 * */ /* * 正射投影之后,三角形就被置于这个矩阵长方体(-2,2...
    namespace sharpGLTest03
    {
            // 主表单类
        public partial class SharpGLForm : Form
        {
            /// <summary>
            /// Initializes a new instance of the <see cref="SharpGLForm"/> class.
            /// </summary>
            public SharpGLForm()
            {
                InitializeComponent();
            }
    
            //  处理OpenGL控件的OpenGLDraw事件
            //  "sender":事件的来源
            //  "e":包含事件数据的实例
            private void openGLControl_OpenGLDraw(object sender, RenderEventArgs e)
            {
                //  获取OpenGL对象
                OpenGL gl = openGLControl.OpenGL;
    
                //  清除颜色和深度缓冲区
                gl.Clear(OpenGL.GL_COLOR_BUFFER_BIT | OpenGL.GL_DEPTH_BUFFER_BIT);
    
                //  加载单位矩阵
                gl.LoadIdentity();
    
                //  围绕Y轴旋转
                //gl.Rotate(rotation, 0.0f, 1.0f, 0.0f);
    
                //  画一个彩色的金字塔
                gl.Begin(OpenGL.GL_TRIANGLES);
    
                {
                    //  画三角形
                    gl.Vertex(0.0f, 0f, 0.0f);
                    gl.Vertex(-1.0f, -1f, 0.0f);
                    gl.Vertex(1.0f, -1f, 0.0f);
                }
    
                //gl.Color(1.0f, 0.0f, 0.0f);
                //gl.Vertex(0.0f, 1.0f, 0.0f);
                //gl.Color(0.0f, 1.0f, 0.0f);
                //gl.Vertex(-1.0f, -1.0f, 1.0f);
                //gl.Color(0.0f, 0.0f, 1.0f);
                //gl.Vertex(1.0f, -1.0f, 1.0f);
                //gl.Color(1.0f, 0.0f, 0.0f);
                //gl.Vertex(0.0f, 1.0f, 0.0f);
                //gl.Color(0.0f, 0.0f, 1.0f);
                //gl.Vertex(1.0f, -1.0f, 1.0f);
                //gl.Color(0.0f, 1.0f, 0.0f);
                //gl.Vertex(1.0f, -1.0f, -1.0f);
                //gl.Color(1.0f, 0.0f, 0.0f);
                //gl.Vertex(0.0f, 1.0f, 0.0f);
                //gl.Color(0.0f, 1.0f, 0.0f);
                //gl.Vertex(1.0f, -1.0f, -1.0f);
                //gl.Color(0.0f, 0.0f, 1.0f);
                //gl.Vertex(-1.0f, -1.0f, -1.0f);
                //gl.Color(1.0f, 0.0f, 0.0f);
                //gl.Vertex(0.0f, 1.0f, 0.0f);
                //gl.Color(0.0f, 0.0f, 1.0f);
                //gl.Vertex(-1.0f, -1.0f, -1.0f);
                //gl.Color(0.0f, 1.0f, 0.0f);
                //gl.Vertex(-1.0f, -1.0f, 1.0f);
                gl.End();
    
                //  轻推旋转
                //rotation += 3.0f;
            }
    
    
    
            //  处理OpenGL控件的OpenGLInitialized事件
            private void openGLControl_OpenGLInitialized(object sender, EventArgs e)
            {
                //  TODO: 在这里初始化OpenGL
    
                //  获取OpenGL对象
                OpenGL gl = openGLControl.OpenGL;
    
                //  设置清晰的颜色
                gl.ClearColor(0, 0, 0, 0);
            }
    
    
            //  处理OpenGL控件的Resized事件
            private void openGLControl_Resized(object sender, EventArgs e)
            {
                // 在此设置投影矩阵
    
                //  获取OpenGL对象
                OpenGL gl = openGLControl.OpenGL;
    
                //  设置投影矩阵;设置当前矩阵模式,对投影矩阵应用随后的矩阵操作
                gl.MatrixMode(OpenGL.GL_PROJECTION);
    
                //  加载身份;重置当前指定的矩阵为单位矩阵,将当前的用户坐标系的原点移到了屏幕中心
                gl.LoadIdentity();
    
                //  创建透视投影变换
                /*
                 * 创建透视效果的函数名和原型
                 * Perspective(double fovy, double aspect, double zNerar, double zFar)
                 * fovy:是控制视野子在XY平面的角度,范围是0——180度。视野度数
                 * aspect:是窗口的纵横比
                 * zNerar,zFar:分别是近处和远处的裁面位置
                 * 
                 * */
                //gl.Perspective(60.0f, (double)Width / (double)Height, 0.01, 100.0);
    
                //创建正射投影变换
                /*
                 * Ortho(double left, double right, double bottom, double top,double near,double far)
                 * near:近平面距离;far:远平面距离
                 * near、far 可以认为是Z轴方向上的近裁剪平面和远裁剪平面
                 * 正射投影的最大特点:无论物体距离相机有多远,投影后的物体大小尺寸不变
                 * */
                /*
                 * 正射投影之后,三角形就被置于这个矩阵长方体(-2,2,-3,3,-2,-5)的视景中了,以后LookAt就是在看这个视影体中的内容,
                 * 如果摄像机的视点设置有超出这个视景体的部分将看不到,相当于被裁剪了
                 * */
                gl.Ortho(-2,2,-3,3,-2,-5);
    
                //  视点变换
                /* 
                 * 视点变换的函数LookAt的原形为:
                 * LookAt(double eyex.double eyey,double eyez,double centerx,double centery,double centerz,double upx,double upy,double upz);
                 * 这个函数是做视点变换用的,你可以认为它是设置摄像机的函数
                 * 在OpenGL中,默认时视点定位于坐标系的原点,初始方向指向Z轴负方向,前面说过,默认的三维模型也是贴着世界坐标系的Z轴0的深度上
                 * 放置的,因此,如果不进行视点变换,则摄像机正好贴着物体,什么也看不见。这就是为什么在上一节的代码里面要有一句代码gl.Transkate()
                 * 用于把物体往Z轴负方向移动一定距离的原因
                 * eyex,eyey, eyez ; 表示摄像机本身位于世界坐标系中的位置
                 * centerx,centery,centerz ;相当于调整了摄像机目标点的位置
                 *  upx,upy,upz ;相当于在旋转3dmax目标摄像机;这个参数的值并不是角度值,而是向量,数值的大小没意义,
                 * 正负值才有意义。upx,upy只能在上下,左右,45度这几个角度中变换,而且upz取值似乎没什么意义 ;
                 * */
                // 透视投影——从后左方看画出的三维三角形
                //gl.LookAt(-5, 5, -5, 0, 0, 0, 0, 1, 0);
    
                // 透视投影——从正前方看画出的三维三角形
                gl.LookAt(0, 0, 1, 0, 0, -10, 0, 1, 0);
    
                // 正射投影——gl.Ortho(-2,2,-3,3,-2,-5);LookAt第三个参数eyez要位于Ortho参数near、far(即-2,-5)之间的原因
                gl.LookAt(0, 0, -3, 0, 0, -10, 0, 1, 0);
    
                //  设置当前矩阵为模型视图矩阵
                gl.MatrixMode(OpenGL.GL_MODELVIEW);
            }
    
            //  当前的轮换
            //private float rotation = 0.0f;
        }
    }

     

    转载于:https://www.cnblogs.com/lotuses/p/11357937.html

    展开全文
  • 经过透视投影 (正射投影也一样)变换, 能够把点 从 观察空间(相机坐标系)转换到 齐次裁剪空间坐标系(又叫规则观察体(Canonical View Volume)中如下图)。这个转化后的空间体 不仅独立于 把三维场景转换为二维...
  • OpenGL投影变换函数的实现

    千次阅读 2015-04-12 17:44:51
    在某些情况下,我们需要自己实现透视投影和正射投影的函数,那么根据前一篇转载的博客,OpenGL投影矩阵的推导,我们很容易写出glFrustum和glOrtho函数的实现。glFrustum的函数实现如下:void MyFrustum (GLdouble ...
  • OpenGL3.3透视投影

    2020-12-07 20:03:13
    正射投影 我们只需要把物体移到坐标系中心 然后再将整个坐标缩放在[-1,1]之间就行了 最终正交矩阵 透视投影 计算机图形网课老师的办法 我们可以把透视投影的计算分两步 1.计算一个可以把透视投影转换成正射投影...
  • 投影变换是一种很关键的图形变换,OpenGL中只提供了两种投影方式,一种是正射投影,另一种是透视投影。不管是调用哪种投影函数,为了避免不必要的变换,其前面必须加上以下两句: glMAtrixMode(GL_PROJECTION); ...
  • OpenGL两种投影方式

    2016-03-20 10:41:48
    投影变换是一种很关键的图形变换,OpenGL中只提供了两种投影方式,一种是正射投影,另一种是透视投影。不管是调用哪种投影函数,为了避免不必要的变换,其前面必须加上以下两句:  glMAtrixMode(GL
  • opengl透射投影出错

    2014-11-13 17:45:52
    在ChangeSize函数中,如果设置成正射投影glOrtho就正常显示图像,如果设置成透射投影gluPerspective就出错,有些没出错,但图像又跟我想的不一样,可能我对透射投影还不是很理解。请懂的人帮忙解答一下,感激!
  • opengl两种投影类型

    2017-06-07 21:45:00
    投影变换是一种很关键的图形变换,OpenGL中只提供了两种投影方式,一种是正射投影,另一种是透视投影。不管是调用哪种投影函数,为了避免不必要的变换,其前面必须加上以下两句: glMAtrixMode(GL_PRO...
  • openGL两种投影方式

    千次阅读 2017-05-17 13:43:32
    投影变换是一种很关键的图形变换,OpenGL中只提供了两种投影方式,一种是正射投影,另一种是透视投影。不管是调用哪种投影函数,为了避免不必要的变换,其前面必须加上以下两句:  glMAtrixMode(GL_PROJECTION); ...
  • OpenGL中,如果想对模型进行操作,就要对这个模型的状态(当前的矩阵)乘上这个操作对应的一个矩阵. 如果乘以变换矩阵(平移, 缩放, 旋转), 那相乘之后, 模型的位置被变换; 如果乘以投影矩阵(将3D物体投影到2D平面), ...
  • OPENGL 投影矩阵原理

    2020-01-09 10:51:12
    OPENGL 投影矩阵原理前言总览透视投影合理的创建标题,有助于目录的生成如何改变文本的样式插入链接与图片如何插入一段漂亮的代码片生成一个适合你的列表创建一个表格设定内容居中、居左、居右SmartyPants创建一个...
  • OpenGL投影矩阵

    千次阅读 2018-11-09 15:41:05
    电脑屏幕是2D表面,必须将OpenGL渲染的3D场景作为2D图像投影到计算机屏幕上,所以就需要用到投影变换MpM_pMp​。首先,MpM_pMp​将所有顶点数据从眼睛坐标转换为裁剪坐标。然后,这些裁剪坐标的各分量(x,y,z)通过...
  • OpenGL投影变换小结

    2013-04-11 15:25:04
    投影变换是一种很关键的图形变换,OpenGL中只提供了两种投影方式,一种是正射投影,另一种是透视投影。不管是调用哪种投影函数,为了避免不必要的变换,其前面必须加上以下两句:  glMAtrixMode(GL_PROJECTION); ...
  • OpenGL投影变换函数gluOrtho2D()和视口变换函数glViewport()    1. void glOrtho(GLdouble left,GLdouble right,GLdouble bottom,GLdouble top, ...正射投影的最大一个特点是无论物体距离相机多远,

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 666
精华内容 266
关键字:

opengl正射投影