1.前言
Unity GL类是Low-Level图像类,提供了最基本的图形画法,其与OpenGL的直接画法类似。但是与Graphics类相比,Graphics类更高效。
GL类一般不能再update以及start等脚本方法中调用(可以调用,但是不会显示)。因为在Unity脚本的生命周期中,当开始渲染时camera会clear图像,如果在生命周期的渲染方法调用前调用GL类进行绘制,那么此时绘制的图像很大可能会被Clear掉,所以不会显示。
2.简单示例
本文以官方文档中的一个示例进行分析,并作了简单的修改。
2.1 基本方法
GL类提供了五种最基本的图像绘制种类,即线、三角形和四边形,绘制时以GL.Begin开始,以GL.End结束,中间通过GL.Color来更改颜色,通过GL.Vertex或者GL.Vertex3来添加顶点,如下所示。如果需要进行矩阵变换,则在GL.Begin之前进行矩阵变换,后续会对矩阵问题进行详细分析。
private void DrawLines()
{
GL.Begin(GL.LINES);
float angleDelta = 2 * Mathf.PI / lineCount;
for (int i = 0; i < lineCount; i++)
{
float angle = angleDelta * i;
GL.Color(new Color((float)i / lineCount, 1 - (float)i / lineCount, 1, 1));
GL.Vertex3(0, 0, 0);
GL.Vertex3(Mathf.Cos(angle) * radius, Mathf.Sin(angle) * radius, 0);
}
GL.End();
}
2.2 调用位置
GL类的方法一般要在跟渲染有关的周期函数中调用,因为涉及的后期效果等问题,一般推荐在OnRenderObject方法中调用。所以使用GL的脚本要挂载在含有Camera的游戏物体上。
2.3 设置材质
调用位置和调用方法都已经明确,此时还需要设置渲染状态,即以什么样式或者效果进行渲染。所以此时要设置材质,示例采用内置的shader,并激活渲染的通道,即shader的Pass,如下所示:
private void SetMaterialPass()
{
if (glMat == null)
{
glMat = new Material(Shader.Find("Hidden/Internal-Colored"));
/*glMat.hideFlags = HideFlags.HideAndDontSave;
glMat.SetInt("_SrcBlend", (int)UnityEngine.Rendering.BlendMode.SrcAlpha);
glMat.SetInt("_DstBlend", (int)UnityEngine.Rendering.BlendMode.OneMinusSrcAlpha);
glMat.SetInt("_Cull", (int)UnityEngine.Rendering.CullMode.Off);
glMat.SetInt("_ZWrite", 0);*/
}
glMat.SetPass(0);
}
原文中代码未注释。也有采用如下shader进行示例演示的,如下所示,但是此shader未进行颜色的传递,所以GL.Color无效。
Shader "Custom/Colored_Blended"
{
SubShader
{
Pass
{
BindChannels { Bind "Color", color }
Blend SrcAlpha OneMinusSrcAlpha
ZWrite Off Cull Off Fog { Mode Off }
}
}
}
2.4 完整代码
可通过更改radius或者lineCount来产生变化,如果在保证脚本正确的情况下,图像未出现,检查脚本所在游戏物体是不是含有camera,以及绘制图像是否在camera的事业范围内。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Graphics01GLExample : MonoBehaviour
{
public int lineCount = 10;
public float radius = 3;
private Material glMat;
private void OnRenderObject()
{
SetMaterialPass();
DrawLines();
}
private void SetMaterialPass()
{
if (glMat == null)
{
glMat = new Material(Shader.Find("Hidden/Internal-Colored"));
/*glMat.hideFlags = HideFlags.HideAndDontSave;
glMat.SetInt("_SrcBlend", (int)UnityEngine.Rendering.BlendMode.SrcAlpha);
glMat.SetInt("_DstBlend", (int)UnityEngine.Rendering.BlendMode.OneMinusSrcAlpha);
glMat.SetInt("_Cull", (int)UnityEngine.Rendering.CullMode.Off);
glMat.SetInt("_ZWrite", 0);*/
}
glMat.SetPass(0);
}
private void DrawLines()
{
GL.Begin(GL.LINES);
float angleDelta = 2 * Mathf.PI / lineCount;
for (int i = 0; i < lineCount; i++)
{
float angle = angleDelta * i;
GL.Color(new Color((float)i / lineCount, 1 - (float)i / lineCount, 1, 1));
GL.Vertex3(0, 0, 0);
GL.Vertex3(Mathf.Cos(angle) * radius, Mathf.Sin(angle) * radius, 0);
}
GL.End();
}
}