精华内容
下载资源
问答
  • OpenGL正交投影

    2012-04-07 10:42:00
    OpenGL正交投影 " ); 19 20 glutReshapeFunc(OnReShape); 21 glutDisplayFunc(OnDisplay); 22 glutMouseFunc(OnMouse); 23 24 25 SetupLights(); 26 27 glutMainLoop(); 28 } 29 30 /...

    代码:

      1 #define GLUT_DISABLE_ATEXIT_HACK
    2 #include "gl/glut.h"
    3
    4 GLboolean Large=GL_FALSE; //坐标单位变大或变小
    5 GLint Width; //视区宽度
    6 GLint Height; //视区高度
    7
    8 void OnDisplay(void);
    9 void OnReShape(int,int);
    10 void OnMouse(GLint,GLint,GLint,GLint);
    11 void SetupLights();
    12
    13 void main(int argc,char* argv[])
    14 {
    15 glutInit(&argc,argv);
    16 glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH);
    17 glutInitWindowSize(600,480);
    18 glutCreateWindow("OpenGL正交投影");
    19
    20 glutReshapeFunc(OnReShape);
    21 glutDisplayFunc(OnDisplay);
    22 glutMouseFunc(OnMouse);
    23
    24
    25 SetupLights();
    26
    27 glutMainLoop();
    28 }
    29
    30 //显示 回调函数
    31 void OnDisplay(void)
    32 {
    33 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    34
    35 glEnable(GL_DEPTH_TEST); //启用深度检测
    36
    37 glMatrixMode(GL_MODELVIEW);
    38 glLoadIdentity();
    39
    40 glRotatef(30.0f,1.0f,0.0f,0.0f);
    41 glRotatef(15.0f,0.0f,1.0f,0.0f);
    42
    43 glColor3f(0.7f,0.5f,0.3f);
    44 glutSolidTeapot(50.0f);
    45
    46 glutSwapBuffers();
    47
    48 }
    49 //窗口尺寸变化后的回调函数
    50 void OnReShape(int w,int h)
    51 {
    52 glViewport(0,0,w,h);
    53 Width=w;
    54 Height=h;
    55 glMatrixMode(GL_PROJECTION); //将当前矩阵指定为投影模式
    56 glLoadIdentity();
    57
    58 GLfloat aspect =(float)w/(float)h;
    59
    60 //设置三维投影区
    61 if(!Large)
    62 if (w<=h) //较小的坐标单位
    63 {
    64 glOrtho(-100.0f,100.0f,-100.0f/aspect,100.0f/aspect,-100.0f,100.0f);
    65 }
    66 else
    67 {
    68 glOrtho(-100.0f*aspect,100.0f*aspect,-100.0f,100.0f,-100.0f,100.0f);
    69 }
    70 else
    71 if (w<=h) //较大的坐标单位
    72 {
    73 glOrtho(-60.0f,60.0f,-60.0f/aspect,60.0f/aspect,-60.0f,60.0f);
    74 }
    75 else
    76 {
    77 glOrtho(-60.0f*aspect,60.0f*aspect,-60.0f,60.0f,-60.0f,60.0f);
    78 }
    79
    80
    81
    82 }
    83
    84 void OnMouse(GLint button,GLint state,GLint x, GLint y)
    85 {
    86 if(button==GLUT_LEFT_BUTTON && state==GLUT_UP) //鼠标左键释放
    87 Large= !Large; //逻辑变量取反
    88
    89 OnReShape(Width,Height);
    90 glutPostRedisplay();
    91 }
    92
    93 void SetupLights()
    94 {
    95 GLfloat ambientLight[]={0.2f,0.2f,0.2f,1.0f};//环境光
    96 GLfloat diffuseLight[]={0.9f,0.9f,0.9f,1.0f};//漫反射
    97 GLfloat specularLight[]={1.0f,1.0f,1.0f,1.0f};//镜面光
    98 GLfloat lightPos[]={50.0f,80.0f,60.0f,1.0f};//光源位置
    99
    100 glEnable(GL_LIGHTING); //启用光照
    101 glLightfv(GL_LIGHT0,GL_AMBIENT,ambientLight);//设置环境光源
    102 glLightfv(GL_LIGHT0,GL_DIFFUSE,diffuseLight);//设置漫反射光源
    103 glLightfv(GL_LIGHT0,GL_SPECULAR,specularLight);//设置镜面光源
    104 glLightfv(GL_LIGHT0,GL_POSITION,lightPos);//设置灯光位置
    105 glEnable(GL_LIGHT0); //打开第一个灯光
    106
    107 glEnable(GL_COLOR_MATERIAL); //启用材质的颜色跟踪
    108 glColorMaterial(GL_FRONT,GL_AMBIENT_AND_DIFFUSE); //指定材料着色的面
    109 glMaterialfv(GL_FRONT,GL_SPECULAR,specularLight); //指定材料对镜面光的反应
    110 glMateriali(GL_FRONT,GL_SHININESS,100); //指定反射系数
    111
    112
    113 }



    转载于:https://www.cnblogs.com/xiacl/archive/2012/04/07/2435739.html

    展开全文
  • Android OpenGL正交投影

    2017-08-02 16:34:26
    Android OpenGL正交投影 1、正交投影 在OpenGL里,渲染的一切物体都要映射到x轴和y轴上[-1, 1]的范围内,这个范围的坐标被称为归一化设备坐标,其独立于屏幕实际的尺寸或形状。 但在横屏模式下,东西会被压扁。 ...

    Android OpenGL正交投影

    首先申明下,本文为笔者学习《OpenGL ES应用开发实践指南》的笔记,并加入笔者自己的理解和归纳总结。

    1、正交投影

    在OpenGL里,渲染的一切物体都要映射到x轴和y轴上[-1, 1]的范围内,这个范围的坐标被称为归一化设备坐标,其独立于屏幕实际的尺寸或形状。
    但在横屏模式下,东西会被压扁。


    我们一般会先在虚拟坐标空间里工作,通过正交投影把虚拟空间坐标转换回归一化设备坐标

    2、矩阵

    矩阵是一个有多个元素的二维数组。在OpenGL里,使用矩阵作向量投影,如正交和透视投影,也用它们使物体旋转、平移和缩放。
    (1) 单位矩阵
    单位矩阵如下图所示


    单位矩阵乘以任何向量总是得到与原来相同的向量。

    (2) 平移矩阵
    平移矩阵可以把一个物体沿着指定距离移动。


    一个位置为(2, 2)的向量,沿x轴平移3,沿y轴平移3。把x赋值为3,把y也赋值为3。

    3、定义正交投影

    Matrix的orthoM方法可以生成一个正交投影
    orthoM(float[] m, int mOffset, float left, float right, float bottom, float top,
                    float near, float far)
    • float[] m:目标数组,存储正交投影矩阵
    • int mOffset:结果矩阵起始的偏移量
    • float left:x轴的最小范围
    • float right:x轴的最大范围
    • float bottom:y轴的最小范围
    • float top:y轴的最大范围
    • float near:z轴的最小范围
    • float far:z轴的最大范围
    当我们调用这个方法的时候,应该会产生下面的正交投影矩阵。

    4、着色器文件

    (1) 顶点着色器,ortho_vertex_shader.glsl文件
    添加u_Matrix变量,意思是这个uniform代表4x4的矩阵。

    uniform mat4 u_Matrix;
    
    attribute vec4 a_Position;
    attribute vec4 a_Color;
    
    varying vec4 v_Color;
    
    void main()
    {
        v_Color = a_Color;
    
        gl_Position = u_Matrix * a_Position;
        gl_PointSize = 10.0;
    }
    (2) 片段着色器,ortho_fragment_shader.glsl文件
    precision mediump float;
    
    varying vec4 v_Color;
    
    void main()
    {                    	
        gl_FragColor = v_Color;
    }

    5、绘制着色器

    (1) 传递矩阵给着色器
    GLES20.glUniformMatrix4fv(uMatrixLocation, 1, false, projectionMatrix, 0);
    (2) OpenGLOrthoShaderRender类
    private class OpenGLOrthoShaderRender implements GLSurfaceView.Renderer {
    	private final static String A_POSITION = "a_Position";
    	private final static String A_COLOR = "a_Color";
    	private final static String U_MATRIX = "u_Matrix";
    
    	private static final int POSITION_COMPONENT_COUNT = 2;
    	private static final int COLOR_COMPONENT_COUNT = 3;
    	private static final int BYTES_PER_FLOAT = 4;
    	private static final int STRIDE = (POSITION_COMPONENT_COUNT + COLOR_COMPONENT_COUNT)
    			* BYTES_PER_FLOAT;
    
    	private float[] projectionMatrix = new float[16];
    	private FloatBuffer vertexData;
    	private int mProgramId;
    	private int aPositionLocation, aColorLocation, uMatrixLocation;
    
    	OpenGLOrthoShaderRender() {
    		float[] tableVerticesWithTriangles = {
    				// 中心点
    				0f, 0f, 1f, 1f, 1f,
    
    				// 四个角
    				-0.5f, -0.8f, 0.7f, 0.7f, 0.7f,
    				 0.5f, -0.8f, 0.7f, 0.7f, 0.7f,
    				 0.5f,  0.8f, 0.7f, 0.7f, 0.7f,
    				-0.5f,  0.8f, 0.7f, 0.7f, 0.7f,
    				-0.5f, -0.8f, 0.7f, 0.7f, 0.7f,
    
    				// 直线
    				-0.5f, 0f, 1f, 0f, 0f,
    				0.5f, 0f, 1f, 0f, 0f,
    
    				// 点
    				0f, -0.25f, 0, 0, 1,
    				0f,  0.25f, 1, 0, 0
    		};
    
    		vertexData = ByteBuffer
    				.allocateDirect(tableVerticesWithTriangles.length * BYTES_PER_FLOAT)
    				.order(ByteOrder.nativeOrder())
    				.asFloatBuffer();
    		vertexData.put(tableVerticesWithTriangles);
    	}
    
    	@Override
    	public void onSurfaceCreated(GL10 gl, EGLConfig config) {
    		GLES20.glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
    
    		mProgramId = useProgram(R.raw.ortho_vertex_shader, R.raw.ortho_fragment_shader);
    
    		// 获取Attribute位置
    		aPositionLocation = GLES20.glGetAttribLocation(mProgramId, A_POSITION);
    		aColorLocation = GLES20.glGetAttribLocation(mProgramId, A_COLOR);
    		// 获取u_Matrix位置
    		uMatrixLocation = GLES20.glGetUniformLocation(mProgramId, U_MATRIX);
    
    		vertexData.position(0);
    		GLES20.glVertexAttribPointer(aPositionLocation, POSITION_COMPONENT_COUNT,
    				GLES20.GL_FLOAT, false, STRIDE, vertexData);
    		GLES20.glEnableVertexAttribArray(aPositionLocation);
    
    		vertexData.position(POSITION_COMPONENT_COUNT);
    		GLES20.glVertexAttribPointer(aColorLocation, COLOR_COMPONENT_COUNT,
    				GLES20.GL_FLOAT, false, STRIDE, vertexData);
    		GLES20.glEnableVertexAttribArray(aColorLocation);
    	}
    
    	@Override
    	public void onSurfaceChanged(GL10 gl, int width, int height) {
    		GLES20.glViewport(0, 0, width, height);
    
    		final float aspectRatio = width > height ?
    				(float)width / (float)height : (float)height / (float)width;
    		if (width > height) {
    			Matrix.orthoM(projectionMatrix, 0, -aspectRatio, aspectRatio, -1f, 1f, -1f, 1f);
    		} else {
    			Matrix.orthoM(projectionMatrix, 0, -1f, 1f, -aspectRatio, aspectRatio, -1f, 1f);
    		}
    	}
    
    	@Override
    	public void onDrawFrame(GL10 gl) {
    		GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT);
    
    		// 给着色器传递正交投影矩阵
    		GLES20.glUniformMatrix4fv(uMatrixLocation, 1, false, projectionMatrix, 0);
    
    		// 绘制三角形
    		GLES20.glDrawArrays(GLES20.GL_TRIANGLE_FAN, 0, 6);
    
    		// 绘制直线
    		GLES20.glDrawArrays(GLES20.GL_LINES, 6, 2);
    
    		// 绘制点
    		GLES20.glDrawArrays(GLES20.GL_POINTS, 8, 1);
    
    		// 绘制点
    		GLES20.glDrawArrays(GLES20.GL_POINTS, 9, 1);
    	}
    
    }
    显示如下



    展开全文
  • 正交投影(Orthographic projection)、透视除法(perspective division)、透视投影(Perspective Projection) 在3D世界中正交投影矩阵 被 透视投影矩阵所代替。 归一化设备坐标 OpenGL的坐标空间是...
    正交投影(Orthographic projection)、透视除法(perspective division)、 透视投影(Perspective Projection)

    在3D世界中正交投影矩阵 被 透视投影矩阵所代替。

    归一化设备坐标
    OpenGL的坐标空间是[-1, 1],x,y轴超过该区域的都将被切掉 看不见。
    手机像素是 1280 X 720,归一化后 坐标空间从[1280X720],映射到[-1,1]

    问题:导致物体变形,因为 x,y轴坐标长度都是1 - (-1)= 2,但x,y轴像素数量不同。y轴像素多,单位坐标就会变长。
    办法:是短的轴映射为1,长的轴根据与短轴的比例 映射。[0, 1280] ,[0, 720]----》[-1280/720 , 1280/720],[-1, 1]。这个空间被称作 虚拟坐标空间
    在虚拟坐标空间上操作顶点,为了OpenGL最终正确渲染,渲染前还需 将虚拟坐标 映射为 归一设备坐标。
    而这个映射叫做 正交投影(orthographic projection)

    二维世界
    正交投影(归 一化设备坐标,不变形)



    该方法位于Matrix中


    @Override
    public void onSurfaceChanged(GL10 gl, int width, int height) {
    gl.glViewport(0, 0, width, height);
    final float aspectRatio = width > height ?
    (float) width / (float) height :
    (float) height / (float) width;
    if (width > height) {
    Matrix.orthoM(projectionMatrix, 0, -aspectRatio, aspectRatio, -1f, 1f, -1f, 1f);
    } else {
    Matrix.orthoM(projectionMatrix, 0, -1f, 1f, -aspectRatio, aspectRatio, -1f, 1f);
    }
    }
    投影后的特点是 物体的远近,不影响投影的大小。


    三维世界
    透视除法
    归一化设备之前,OpenGL执行的额外操作 透视除法

    w分量除以x,y,z分量(w默认值是1),产生三维幻想 透视效应

    上图点坐标都是(-1, -1, 0),但是设置w后,(x,y,z,w)实际是(x/w, y/w, z/w),w越大越趋向于 归一化设备坐标的中心(0, 0, 0)。
    其中z的数都为0,单凭w值就营造出三维效果。


    透视投影矩阵(Perspective Projection)
    不应指定投影除法中点的w值,而要通过矩阵生成。

    视椎体(Frustum)
    由透视投影矩阵和投影除法创造(如下图)
    远端(far side):
    近端(near side):
    Focal Point:following the lines that extend from the large end to the small end of the frustum and then following them past the small end util they meet together.
    Focal Length: represent by the value of z, The distance between the focal point and the small end of the frustum.
    通用投影矩阵:调整视野,屏幕宽高比
    以下公式 通过物体与焦点的距离(z)来映射w,z越大,w越大,物体越小


    透视投影Android Matrix有两个方法,
    frustumM()
    有缺陷,影响某些类型的投影
    perspectiveM(),
    从Android的ICS(Ice Cream Sandwich)引入

    所以最好自己写perspectiveM: r1
    public static void perspectiveM (float[] m, float yFovInDegrees, float aspect,
    float n, float f) {
    final float angleInRadians = (float) (yFovInDegrees * Math.PI / 180.0);

    final float a = (float) (1.0 / Math.tan(angleInRadians / 2.0));

    m[0] = a / aspect;
    m[1] = 0f;
    m[2] = 0f;
    m[3] = 0f;

    m[4] = 0f;
    m[5] = a;
    m[6] = 0f;
    m[7] = 0f;

    m[8] = 0f;
    m[9] = 0f;
    m[10] = -((f+n) / (f-n));
    m[11] = -1f;

    m[12] = 0f;
    m[13] = 0f;
    m[14] = -((2f * f * n) / (f - n));
    m[15] = 0f;
    }
    较宽的视野会引起形变





    正交投影与透视投影区别
    正交投影中平行的光 照射到与其平行的物体就变成点或者线了,看不到平行物体的侧面(就是图中的小旗子)
    透视投影中平行的光实际上发散出去的(就像人眼看平行的铁轨,明明是平行的,但是透视效果确实两个平行铁轨越远越相较于某一点),实际的光是不平行的 当然就可以看到物体的侧面。




    模型矩阵
    用于移动物体,将模型矩阵合并到投影矩阵中
    private final float[] modelMatrix = new float[16];

    onSurfaceChanged() {
    setIdentityM(modelMatrix, 0);
    translateM(modelMatrix, 0, 0f, 0f, -2f);
    }


    旋转矩阵



    tow transformation steps and three different coordinate spaces;


    Clip Space
    4component of coordinates x,y,z,w
    Any coordinate show rang in [-w, w], or it wil be cliped and can't be visible.
    And is Clip space

    Projection matrix

    W越大离屏幕越远

    Depth buffer:
    the component Z as Depth buffer





    展开全文
  • OpenGL ES 正交投影

    千次阅读 2016-10-23 15:59:14
    OpenGL ES 正交投影OpenGL ES 正交投影 绘制正方形 引入投影 正交投影背后的数学 摄像机设置 视口绘制正方形在最开始绘制的六边形里面好像看起来挺容易的,也没有出现什么问题,接下来不妨忘记前面绘制六边形的代码...

    OpenGL ES 正交投影

    绘制正方形

    在最开始绘制的六边形里面好像看起来挺容易的,也没有出现什么问题,接下来不妨忘记前面绘制六边形的代码,让我们按照自己的理解来绘制一个简单的正方形。

    按照我的理解,要想在屏幕中间显示一个正方形,效果如下图所示

    手机屏幕上应该显示的正方形

    应该创建的数据如下图所示

    数据

    即传给渲染管线的顶点数据如下图:

    float[] vertexArray = new float[] {
                (float) -0.5, (float) -0.5, 0,
                (float) 0.5, (float) -0.5, 0,
                (float) -0.5, (float) 0.5, 0,
                (float) 0.5, (float) 0.5, 0
            };

    于是代码大概是这样子的,这里省略掉与主题无关的代码,颜色用纯色填充,因此在片元着色器中指定颜色,也省略掉一系列矩阵变换。顶点着色器中直接将顶点传给渲染管线,片元着色器中给片元设置固定颜色红色。

    Rectangle.java

    public class Rectangle {
        private FloatBuffer mVertexBuffer;
        private int mProgram;
        private int mPositionHandle;
    
        public Rectangle(float r) {
            initVetexData(r);
        }
    
        public void initVetexData(float r) {
            // 初始化顶点坐标
            float[] vertexArray = new float[] {
                (float) -0.5, (float) -0.5, 0,
                (float) 0.5, (float) -0.5, 0,
                (float) -0.5, (float) 0.5, 0,
                (float) 0.5, (float) 0.5, 0
            };
    
            ByteBuffer buffer = ByteBuffer.allocateDirect(vertexArray.length * 4);
            buffer.order(ByteOrder.nativeOrder());
            mVertexBuffer = buffer.asFloatBuffer();
            mVertexBuffer.put(vertexArray);
            mVertexBuffer.position(0);
    
            int vertexShader = loaderShader(GLES20.GL_VERTEX_SHADER, vertexShaderCode);
            int fragmentShader = loaderShader(GLES20.GL_FRAGMENT_SHADER, fragmentShaderCode);
    
            mProgram = GLES20.glCreateProgram();
            GLES20.glAttachShader(mProgram, vertexShader);
            GLES20.glAttachShader(mProgram, fragmentShader);
            GLES20.glLinkProgram(mProgram);
    
            mPositionHandle = GLES20.glGetAttribLocation(mProgram, "aPosition");
        }
    
        public void draw() {
            GLES20.glUseProgram(mProgram);
            // 将顶点数据传递到管线,顶点着色器
            GLES20.glVertexAttribPointer(mPositionHandle, 3, GLES20.GL_FLOAT, false, 0, mVertexBuffer);
            GLES20.glEnableVertexAttribArray(mPositionHandle);
            // 绘制图元
            GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, 4);
        }
    
        private int loaderShader(int type, String shaderCode) {
            int shader = GLES20.glCreateShader(type);
            GLES20.glShaderSource(shader, shaderCode);
            GLES20.glCompileShader(shader);
            return shader;
        }
    
        private String vertexShaderCode = "attribute vec3 aPosition;"
                + "void main(){"
                + "gl_Position = vec4(aPosition,1);"
                + "}";
    
        private String fragmentShaderCode = "precision mediump float;"
                + "void main(){"
                + "gl_FragColor = vec4(1,0,0,0);"
                + "}";
    
    }

    RectangleView.java

    public class RectangleView extends GLSurfaceView{
    
        public RectangleView(Context context) {
            super(context);
            setEGLContextClientVersion(2);
            setRenderer(new MyRender());
        }
    
        class MyRender implements GLSurfaceView.Renderer {
            private Rectangle rectangle;
    
            @Override
            public void onSurfaceCreated(GL10 gl, EGLConfig config) {
                GLES20.glClearColor(0.5f, 0.5f, 0.5f, 1);
                rectangle = new Rectangle(0.5f);
                GLES20.glEnable(GLES20.GL_DEPTH_TEST);
            }
    
            @Override
            public void onSurfaceChanged(GL10 gl, int width, int height) {
                GLES20.glViewport(0, 0, width, height);
            }
    
            @Override
            public void onDrawFrame(GL10 gl) {
                GLES20.glClear( GLES20.GL_DEPTH_BUFFER_BIT | GLES20.GL_COLOR_BUFFER_BIT);
                rectangle.draw();
            }
        }
    
    }

    然后出来的效果是这样子的,实际上屏幕上的坐标并不是这样子的,后面可以知道上面画的这个样子其实只是一个归一化的设备坐标。归一化设备坐标可以通过公式映射到实际的手机屏幕,后面会学到。

    实际效果_竖屏

    咦,实际效果好像和想象中的不太一样呀。我的本意是显示一个正方形,但实际上现实的却是一个矩形了,y轴上被拉伸了,并且横屏状态下也是类似的情况。但比较巧的是,如果以屏幕中心做一个坐标轴,就会发现,这个矩形的四个顶点在这个坐标轴x、y范围为[-1,1]的中间。

    实际上,要显示的所有物体映射到手机屏幕上,都是要映射到x、y、z轴上的[-1,1]范围内,这个范围内的坐标称为归一化设备坐标,独立于屏幕的实际尺寸和形状。

    因此按照这样的规定,我们要创建一个正方形就非常困难了,因为要创建正方形就必须考虑手机的宽高比,传入数据的时候就比较复杂了:不能仅仅站在要绘制物体的自身角度来看了。也就是说,上面的例子中要绘制一个正方形,传入的顶点数据的y坐标要按照比例进行一点转换,比如对16:9的屏幕,将上面传入的顶点数据的y坐标都乘以9/16即可。但同时会发现当处于横屏时,又要处理传入的x坐标的值,显然这不是一个好的方案。

    引入投影

    实际上,对于一个物体来说它有它自身的坐标,这个空间称为物体空间,也就是设计物体的时候采用的一个坐标空间,物体的几何中心在坐标原点上,归一化后坐标范围在[-1,1]之间,x和y轴分度是一致的。

    将在这个空间的物体直接往手机屏幕的归一化坐标绘制时,由于屏幕的宽高比的问题,就会出现和预料结果不一样。所以只需要对物体空间的坐标做一个映射即可。

    正交投影就是为了解决这个问题的,

    public static void orthoM(float[] m, int mOffset,
            float left, float right, float bottom, float top,
            float near, float far)

    正交投影背后的数学

    orthoM函数产生的矩阵会把所有的左右之间、上下之间,远近之间的点映射到归一化设备坐标中。

    各参数的含义如图所示

    正交投影示意图

    正交投影是一种平行投影,投影线是平行的,其视景体是一个长方体,坐标位于视景体中的物体才有效,视景体里面的物体投影到近平面上的部分最终会显示到屏幕的视口中,关于视口后面会降到。

    会产生下面的矩阵,z轴的负值会反转z坐标,这是因为归一化设备坐标是左手系统,而OpenGL ES中的坐标系统都是右手系统,这里还涉及到顶点坐标的w分量,目前暂时用不到。

    2rightleft00002topbottom00002farnear0right+leftrightlefttop+bottomtopbottomfar+nearfarnear1

    利用矩阵的就可以将物体空间[-1,1]之间的坐标映射到屏幕归一化设备坐标的[-1,1]之间。归一化屏幕坐标是右手坐标系统,原点在屏幕正中心,向右为x轴正方向,向上为y轴正方向,z轴垂直屏幕向外。以竖屏为例,比如设置left=-1,right=1,bottom=-hight/width,top=hight/width,比如我的手机分辨率为1920*1080 =1.8 对上面的正方形点(0.5,0.5)坐标而言经过变化就成了(0.5,0.3)

    100000.6000000010.50.500=0.50.300

    在屏幕的归一化设备坐标中来看就是一个正方形了,因为y轴范围显然比x轴大,0.3对应的实际长度和x轴的0.5长度是一样的。

    上面的代码需要做如下修改,在onSurfaceChanged里面增加如下代码

    @Override
            public void onSurfaceChanged(GL10 gl, int width, int height) {
                GLES20.glViewport(0, 0, width, height);
                // 根据屏幕方向设置投影矩阵
                float ratio= width > height ? (float)width / height : (float)height / width;
                if (width > height) {
                    // 横屏 
                    Matrix.orthoM(mProjectionMatrix, 0, -ratio, ratio, -1, 1, 0, 5);
                } else {
                    Matrix.orthoM(mProjectionMatrix, 0, -1, 1, -ratio, ratio, 0, 5);
                }
            }

    接着在顶点着色器中对顶点乘以投影矩阵

    private String vertexShaderCode = "uniform mat4 uProjectionMatrix;" // 增加这一行
                + "attribute vec3 aPosition;"
                + "void main(){"
                + "gl_Position = uProjectionMatrix * vec4(aPosition,1);" // 不是直接赋值而是乘以投影矩阵
                + "}";

    最后增加获取着色器中uProjectionMatrix以及传入值的代码部分即可。最终的效果不论横屏还是竖屏,显示的都是我们期望的正方形。

    摄像机设置

    需要补充的是,上面的参数near、far的含义指的是和视点的距离,视点貌似到目前还未接触到,它指的是摄像机的位置,和实际生活中用相机看物体一样,从不同的角度和位置拍摄同一个物体获得的照片肯定是不一样的,摄像机位置用setLookAtM函数指定。

     public static void setLookAtM(float[] rm,  // 生成的摄像机矩阵
                                   int rmOffset,
                float eyeX, float eyeY, float eyeZ,  // 摄像机的位置
                float centerX, float centerY, float centerZ,  // 观察目标点的位置
                                                              // 摄像机位置和观察目标点的位置确定了观察方向
                float upX, float upY,float upZ  // up向量在x、y、z轴上的分量,我觉得一般应该是和观察方向垂直的
                                  )

    前面提到的确定的视景体就和上面函数指定的摄像机位置和观察方向有关。摄像机默认位置在(0,0,0)处,在上面的设置下,如果将改正方形沿z轴正方向平移1个单位,屏幕上就显示不了,因为已经跑到了设置的视景体外面了。

    关于摄像机的参数和投影near和far参数的设置需要注意,肯定不是胡乱设置的!摄像机的位置、方向和投影矩阵定义的视景体最终确定了视景体的位置,如果设置不当就会导致物体没有显示在屏幕上,因为物体的坐标可能位于视景体外面。

    视口

    前面说过在视景体中的物体最终会投影到近平面上,最终显示到视口上,正如前面在onSurfaceChanged设置的那样。

    public static native void glViewport(
            int x,
            int y,
            int width,
            int height
        );

    视口中各参数的含义

    视口示意图

    视口用的屏幕坐标系原点并不在屏幕左上角而是在左下角,x轴向右,y轴向上。其实还不是很准确,准确的说,视口的坐标原点位于该View的左下角,因为GLSurfaceView并不总是占据整个屏幕的。

    代码

    展开全文
  • 正交投影与透视投影的源码; 该源码是 OpenGL 示例源码集合. OpenGL 需要依赖 v7 包
  • 主要为大家详细介绍了OpenGL ES正交投影的实现方法,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
  • OpenGL正交投影和透视投影矩阵(二) —— 结合OpenGL代码验证
  • 我的正交投影参数为 ``` glOrtho(87200, 88000, 12250.0, 13050.0, -50, 50); ``` 这样可以完整的看到图形。 但是换到透视投影 ``` glFrustum(87200, 88000, 12250.0, 13050.0, 1, 60); ``` 就没法显示出图形了...
  • 正交投影void glOrtho(GLdouble left, GLdouble right, GLdouble bottom, GLdouble top, GLdouble zNear, GLdouble zFar);void gluOrtho2D(GLdouble left, GLdouble right, GLdouble bottom, GLdouble top);透视投影...
  • 搭建一个场景,模拟房间摄像头的运动方式,设置两个摄像机,一个是正交投影,一个是透视投影,附带readme以及原理说明
  • OpenGL 正交、透视投影

    千次阅读 2016-03-29 10:24:09
    OpenGL中,如果想对模型进行操作,就要对这个模型的状态(当前的矩阵)乘上这个操作对应的一个矩阵. 如果乘以变换矩阵(平移, 缩放, 旋转), 那相乘之后, 模型的位置被变换; 如果乘以投影矩阵(将3D物体投影到2D平面)...
  • OpenGL 使用透视投影、正交投影

    千次阅读 2019-11-06 16:47:51
    正交投影 1. 透视投影 display函数 void display() { //清空屏幕,使用了深度缓存`GL_DEPTH_BUFFER_BIT`必须加 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glLoadIdentity(); //设...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 2,941
精华内容 1,176
关键字:

opengl正交投影