(七)Graphics DrawMesh
1.前言
本文承接上一节,主要讲一下如何用graphics绘制一个Mesh以及将绘制结果绘制到一个RenderTexture上。代码在文末。
2.Graphics DrawMesh
代码中所用材质shader为Unlit/Texture。
2.1 ToScreen
以下为绘制到屏幕上的示例代码:
private void DrawToScreen()
{
drawBuffer.Clear();
drawBuffer.ClearRenderTarget(true, true, clearColor);
Graphics.ExecuteCommandBuffer(drawBuffer);
drawBuffer.DrawMesh(Graphics00Mesh.Instance.GetMesh(triCount, radius), Matrix4x4.identity, mat);
Graphics.ExecuteCommandBuffer(drawBuffer);
}
此时方法只能在OnPostRender中调用,所以网格顶点数据即为实际数据。在OnpostRender中调用时,相当于在借助Camera在渲染流程中进行渲染Mesh,所以坐标点就是真是位置。如果看不到效果,可能是因为绘制的Mesh不在Camera的视锥体内,尝试调节mesh的位置,可以找到。此方法与这一篇方法类似。
2.2 ToTarget
此节将Mesh绘制到一个RenderTexture上。示例代码如下:
private void DrawToTarget()
{
GL.PushMatrix();
Graphics.SetRenderTarget(target);
GL.LoadPixelMatrix(0, target.width, 0, target.height);
drawBuffer.Clear();
drawBuffer.ClearRenderTarget(true, true, clearColor);
Graphics.ExecuteCommandBuffer(drawBuffer);
drawBuffer.DrawMesh(Graphics00Mesh.Instance.GetMesh(triCount, radius), Matrix4x4.identity, mat);
Graphics.ExecuteCommandBuffer(drawBuffer);
GL.PopMatrix();
}
此方法可以在update中使用。
2.2.1 注意事项一
由于此方法是直接绘制到二维RenderTexture上,所以要进行坐标变换,且要先设置Target后LoadPixelMatrix。
2.2.2 注意事项二
由于坐标要转换到像素坐标,所以mesh顶点只显示大于0的部分,本例中Mesh的中心是(0,0,0),所以会只显示四分之一,跟这一篇2.3节一样。
而且如果Mesh的顶点数据过小,可能看不到。以本例圆形mesh为例,如果半径为1,那么在屏幕上只有一个像素大小,所以是看不到的,此时可以设置为100或者更大。
3.完整代码
3.1 Mesh代码
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Graphics00Mesh
{
[Range(3, 100)]
public int triCount = 6;
public float radius = 5;
public bool showHalf = false;
private static Graphics00Mesh instance;
public static Graphics00Mesh Instance
{
get
{
if (instance == null)
{
instance = new Graphics00Mesh();
}
return instance;
}
}
public Mesh GetMesh(int triCount,float radius)
{
this.triCount = triCount;
this.radius = radius;
Mesh mesh = new Mesh();
mesh.name = MeshName;
mesh.vertices = Vertices;
mesh.triangles = Triangles;
mesh.uv = Uvs;
return mesh;
}
protected string MeshName
{
get
{
return "Circle Mesh";
}
}
protected Vector3[] Vertices
{
get
{
Vector3[] vertices = new Vector3[triCount + 1];
vertices[0] = Vector3.zero;
float angleDelta = 2 * Mathf.PI / triCount;
for (int i = 0; i < triCount; i++)
{
float angle = angleDelta * i;
float x = radius * Mathf.Cos(angle);
float y = radius * Mathf.Sin(angle);
vertices[i + 1] = new Vector3(x, y, 0);
}
return vertices;
}
}
protected int[] Triangles
{
get
{
int[] triangles = new int[triCount * 3];
for (int i = 0; i < triCount; i++)
{
if (showHalf)
{
if (i % 2 == 0) continue;
}
triangles[i * 3] = 0;
triangles[i * 3 + 2] = i + 1;
if (i + 2 > triCount)
{
triangles[i * 3 + 1] = 1;
}
else
{
triangles[i * 3 + 1] = i + 2;
}
}
return triangles;
}
}
protected Vector2[] Uvs
{
get
{
Vector2[] uvs = new Vector2[triCount + 1];
uvs[0] = new Vector2(0.5f, 0.5f);
float angleDelta = 2 * Mathf.PI / triCount;
for (int i = 0; i < triCount; i++)
{
float angle = angleDelta * i;
float x = Mathf.Cos(angle) * 0.5f + 0.5f;
float y = Mathf.Sin(angle) * 0.5f + 0.5f;
uvs[i + 1] = new Vector2(x, y);
}
return uvs;
}
}
}
3.2 示例代码
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Rendering;
public class Graphics07DrawMeshToTarget : MonoBehaviour
{
public DrawLocation location = DrawLocation.ONGUI;
public bool toTarget = false;
public Color clearColor = Color.blue;
public Material mat;
public RenderTexture target;
public int triCount = 10;
public float radius = 20;
CommandBuffer drawBuffer;
void Draw()
{
if (toTarget)
{
DrawToTarget();
}
else
{
DrawToScreen();
}
}
private void DrawToScreen()
{
drawBuffer.Clear();
drawBuffer.ClearRenderTarget(true, true, clearColor);
Graphics.ExecuteCommandBuffer(drawBuffer);
drawBuffer.DrawMesh(Graphics00Mesh.Instance.GetMesh(triCount, radius), Matrix4x4.identity, mat);
Graphics.ExecuteCommandBuffer(drawBuffer);
}
private void DrawToTarget()
{
GL.PushMatrix();
Graphics.SetRenderTarget(target);
GL.LoadPixelMatrix(0, target.width, 0, target.height);
drawBuffer.Clear();
drawBuffer.ClearRenderTarget(true, true, clearColor);
Graphics.ExecuteCommandBuffer(drawBuffer);
drawBuffer.DrawMesh(Graphics00Mesh.Instance.GetMesh(triCount, radius), Matrix4x4.identity, mat);
Graphics.ExecuteCommandBuffer(drawBuffer);
GL.PopMatrix();
}
private void Start()
{
drawBuffer = new CommandBuffer() { name = "DrawMesh buffer" };
}
private void OnGUI()
{
if (location != DrawLocation.ONGUI) return;
if (Event.current.type.Equals(EventType.Repaint))
{
Draw();
}
}
private void Update()
{
if (location != DrawLocation.UPDATE) return;
Draw();
}
private void OnPostRender()
{
if (location != DrawLocation.POSTRENDER) return;
Draw();
}
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· Docker 太简单,K8s 太复杂?w7panel 让容器管理更轻松!