zoukankan      html  css  js  c++  java
  • (三)GL 空间变换

    1.前言

    采用GL类以及Graphics类进行绘制图形时,都需要用到坐标变换。这跟采用图形学接口进行绘制时相同。以一个球为例,如果在坐标原点处绘制,球心坐标为0。如果在其他位置绘制,球心坐标不为0,此时球面顶点坐标需要重新计算。如果采用矩阵变换(坐标变换),将坐标原点移动到球心所在的位置,则球心仍在原点位置,球面坐标保持不变。所以我们在绘制一个图形时,先进行坐标变换,然后再绘制,绘制结束后再恢复到原来坐标系(即世界坐标系),然后再坐标变换绘制其他图形,然后再恢复到世界坐标系。

    2.GL类坐标变换

    此节主要针对GL类几个加载坐标系的方法来进行说明,如LoadPixelMatrix、MultMatrix等。

    2.1 世界坐标系

    默认为世界坐标系,如下代码为在世界坐标系下绘制正多边形。此时移动camera,图像会移动。因为图像的坐标与camera坐标无关系。

        public int circleRadius = 3;
        public int circleCount = 6;
        public int zValue = 0;
            
        private void DrawCircleSurface()
        {
            float angleDelta = 2 * Mathf.PI / circleCount;
    
            GL.Begin(GL.TRIANGLES);
            GL.Color(Color.yellow);
    
            for (int i = 0; i < circleCount; i++)
            {
                float angle = angleDelta * i;
                float angleNext = angle + angleDelta;
    
                GL.Vertex3(0, 0, zValue);
                GL.Vertex3(Mathf.Cos(angle) * circleRadius, Mathf.Sin(angle) * circleRadius, zValue);
                GL.Vertex3(Mathf.Cos(angleNext) * circleRadius, Mathf.Sin(angleNext) * circleRadius, zValue);
            }
    
            GL.End();
        }`在这里插入代码片`
    

    2.2 局部坐标系

    如果我们让图像变成某一个游戏物体的子物体(如camera),可以采用GL.MultMatrix方法。首先通过transform.localToWorldMatrix获取局部坐标到世界坐标的变换矩阵,然后通过GL.MultMatrix加载进来就可以。此时我们进行绘制时,计算的坐标都为局部坐标,最终数据会通过坐标转换为世界坐标系下结果,代码如下。如果此时再移动camera,图像则跟随camera移动。

       private void DrawCircleSurfaceLocal()
        {
            GL.PushMatrix();
            GL.MultMatrix(transform.localToWorldMatrix);
            DrawCircleSurface();
            GL.PopMatrix();
        }
    

    2.3 屏幕坐标系

    可以通过GL.LoadPixelMatrix将图像直接绘制到屏幕上,此方法有两个重载,对应绘制到当前屏幕上和绘制到指定大小像素上。如果指定大小像素与屏幕相同,则即为绘制到当前屏幕大小。但是此时图像坐标是以像素为大小的,且z值坐标为0.。而且屏幕坐标没有负值,所以以本例正多边形为例,由于原点在0位置,所以屏幕只能显示四分之一图像。

        private void DrawCircleSurfaceScreen()
        {
            //circleRadius = 1000; 以像素为单位
            GL.PushMatrix();
            //GL.LoadPixelMatrix();
            GL.LoadPixelMatrix(0,screenSize.x,0,screenSize.y);
            DrawCircleSurface();
            GL.PopMatrix();
        }
    

    当screenSize的x与y值和屏幕分辨率相同时,与GL.LoadPixelMatrix()的效果一致。

    2.4 正交坐标系

    采用GL.LoadOrtho()方法可以将图像直接绘制到屏幕上,此时是正交视图,大小为1,所以坐标系数值均要小于等于1.。同样坐标值没有负值。

        private void DrawCircleSurfaceOrtho()
        {
            //circleRadius = 1; 最大值为1
            GL.PushMatrix();
            GL.LoadOrtho();
            DrawCircleSurface();
            GL.PopMatrix();
        }
    

    2.5 视口分离

    通过GL.Viewport方法可以实现绘制在局部视口内,如下所示:

        private void DrawCircleSurfaceViewport()
        {
            GL.PushMatrix();
            GL.LoadPixelMatrix();
            GL.Viewport(new Rect(0, 0, Screen.width / 2, Screen.height / 2));
            DrawCircleSurface();
            GL.PopMatrix();
        }
    

    注意:如果坐标系采用的正交坐标系,即采用GL.LoadOrtho()方法,则视口的最大值为1,此时 GL.Viewport(new Rect(0, 0, 1.0f / 2, 1.0f / 2));

    3.完整代码

    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    
    public class Graphics03GLMatrix : MonoBehaviour
    {
        public enum SpaceType
        {
            WORLD,
            LOCAL,
            SCREEN_NORMAL,
            SCREEN,
            VIEWPORT
        }
    
        public SpaceType type = SpaceType.WORLD;
    
        public int circleRadius = 3;
        public int circleCount = 6;
        public int zValue = 0;
        public Vector2 screenSize = Vector2.zero;
    
        private void OnRenderObject()
        {
            SetMaterialPass();
    
            switch (type)
            {
                case SpaceType.WORLD:
                    DrawCircleSurface();
                    break;
                case SpaceType.LOCAL:
                    DrawCircleSurfaceLocal();
                    break;
                case SpaceType.SCREEN_NORMAL:
                    DrawCircleSurfaceOrtho();
                    break;
                case SpaceType.SCREEN:
                    DrawCircleSurfaceScreen();
                    break;
                case SpaceType.VIEWPORT:
                    DrawCircleSurfaceViewport();
                    break;
            }
        }
    
        private Material glMat;
    
        private void SetMaterialPass()
        {
            if (glMat == null)
            {
                glMat = new Material(Shader.Find("Hidden/Internal-Colored"));
            }
    
            glMat.SetPass(0);
        }
    
        private void DrawCircleSurface()
        {
            float angleDelta = 2 * Mathf.PI / circleCount;
    
            GL.Begin(GL.TRIANGLES);
            GL.Color(Color.yellow);
    
            for (int i = 0; i < circleCount; i++)
            {
                float angle = angleDelta * i;
                float angleNext = angle + angleDelta;
    
                GL.Vertex3(0, 0, zValue);
                GL.Vertex3(Mathf.Cos(angle) * circleRadius, Mathf.Sin(angle) * circleRadius, zValue);
                GL.Vertex3(Mathf.Cos(angleNext) * circleRadius, Mathf.Sin(angleNext) * circleRadius, zValue);
            }
    
            GL.End();
        }
    
        private void DrawCircleSurfaceLocal()
        {
            GL.PushMatrix();
            GL.MultMatrix(transform.localToWorldMatrix);
            DrawCircleSurface();
            GL.PopMatrix();
        }
    
        private void DrawCircleSurfaceOrtho()
        {
            //circleRadius = 1; 最大值为1
            GL.PushMatrix();
            GL.LoadOrtho();
            DrawCircleSurface();
            GL.PopMatrix();
        }
    
        private void DrawCircleSurfaceScreen()
        {
            //circleRadius = 1000; 以像素为单位
            GL.PushMatrix();
            //GL.LoadPixelMatrix();
            GL.LoadPixelMatrix(0,screenSize.x,0,screenSize.y);
            DrawCircleSurface();
            GL.PopMatrix();
        }
    
        private void DrawCircleSurfaceViewport()
        {
            GL.PushMatrix();
            GL.LoadPixelMatrix();
            GL.Viewport(new Rect(0, 0, Screen.width / 2, Screen.height / 2));
            DrawCircleSurface();
            GL.PopMatrix();
        }
    }
    
    
  • 相关阅读:
    目录创建用什么命令?创建文件用什么命令?复制文件用什 么命令?
    哪些浏览器支持HTML 5?
    终端是哪个文件夹下的哪个文件?黑洞文件是哪个文件夹下 的哪个命令?
    什么是端到端微服务测试?
    HTML 5中的本地存储概念?
    HTML 5的页面结构和HTML 4或早先的HTML有什么不同?
    Spring 切面可以应用五种类型的通知?
    Math.round(11.5) 等于多少?Math.round(-11.5)等于多少?
    微服务架构如何运作?
    双因素身份验证的凭据类型有哪些?
  • 原文地址:https://www.cnblogs.com/llstart-new0201/p/12315711.html
Copyright © 2011-2022 走看看