【Unity3D】使用GL绘制线段
1 前言
线段渲染器LineRenderer、拖尾TrailRenderer、绘制物体表面三角形网格从不同角度介绍了绘制线段的方法,本文再介绍一种新的绘制线段的方法:使用 GL 绘制线段。
Graphics Library(简称 GL),包含一系列类似 OpenGL 的 Immediate 模式的渲染指令,比 Graphic.DrawMesh() 更高效。GL 是立即执行的,如果在Update() 方法里调用,它们将在相机渲染前执行,相机渲染前会清空屏幕,GL 渲染效果将无法看到。通常 GL 用法是:在相机上挂脚本,并在 OnPostRender() 方法里执行(MonoBehaviour的生命周期)。GL 渲染的图像不需要 GameObject 承载,在 Hierarchy 窗口不会生成 GameObject 对象。
2 代码实现
LinePainter.cs
using UnityEngine;
[RequireComponent(typeof(Camera))]
public class LinePainter : MonoBehaviour {
private Material lineMaterial; // 线段材质
private Vector3[][] circleVertices; // 3个圆环的顶点坐标
private Color[] colors; // 3 个圆环的颜色
private void Start() {
lineMaterial = new Material(Shader.Find("Hidden/Internal-Colored"));
colors = new Color[] {Color.red, Color.green, Color.blue};
circleVertices = new Vector3[3][];
for (int i = 0; i < 3; i++) {
circleVertices[i] = GetCircleLines(Vector3.up, Vector3.one, i, 20);
}
}
private void OnPostRender() { // GL处理不能放在Update里
for (int i = 0; i < 3; i++) {
DrawLines(circleVertices[i], colors[i], Color.yellow, 0.01f);
}
}
private Vector3[] GetCircleLines(Vector3 center, Vector3 radius, int axis, int num) { // 获取圆环顶点数据
Vector3[] vertices = new Vector3[num + 1];
float ds = Mathf.PI * 2.0f / num;
float theta = 0;
if (axis == 0)
{
for (int i = 0; i <= num; i++) {
theta += ds;
Vector3 vec = new Vector3(0, Mathf.Cos(theta), Mathf.Sin(theta));
vertices[i] = new Vector3(vec.x * radius.x, vec.y * radius.y, vec.z * radius.z) + center;
}
} else if (axis == 1) {
for (int i = 0; i <= num; i++) {
theta += ds;
Vector3 vec = new Vector3(Mathf.Cos(theta), 0, Mathf.Sin(theta));
vertices[i] = new Vector3(vec.x * radius.x, vec.y * radius.y, vec.z * radius.z) + center;
}
} else {
for (int i = 0; i <= num; i++) {
theta += ds;
Vector3 vec = new Vector3(Mathf.Cos(theta), Mathf.Sin(theta), 0);
vertices[i] = new Vector3(vec.x * radius.x, vec.y * radius.y, vec.z * radius.z) + center;
}
}
return vertices;
}
private void DrawLines(Vector3[] points, Color lineColor, Color pointColor, float pointSize) { // 绘制线段
GL.PushMatrix();
GL.LoadIdentity();
GL.MultMatrix(GetComponent<Camera>().worldToCameraMatrix);
GL.LoadProjectionMatrix(GetComponent<Camera>().projectionMatrix);
lineMaterial.SetPass(0);
AddLines(points, lineColor);
if (pointColor != null && pointSize > 0) {
AddPoints(points, pointColor, pointSize);
}
GL.PopMatrix();
}
private void AddLines(Vector3[] points, Color color) { // 添加线段端点
GL.Begin(GL.LINE_STRIP);
GL.Color(color);
foreach (Vector3 point in points)
{
GL.Vertex3(point.x, point.y, point.z);
}
GL.End();
}
private void AddPoints(Vector3[] points, Color color, float size) { // 添加绘制点(通过绘制小立方模拟顶点)
GL.Begin(GL.QUADS);
GL.Color(color);
foreach (Vector3 point in points) {
// 前面
GL.Vertex3(point.x + size, point.y + size, point.z - size);
GL.Vertex3(point.x + size, point.y - size, point.z - size);
GL.Vertex3(point.x - size, point.y - size, point.z - size);
GL.Vertex3(point.x - size, point.y + size, point.z - size);
// 后面
GL.Vertex3(point.x + size, point.y + size, point.z + size);
GL.Vertex3(point.x + size, point.y - size, point.z + size);
GL.Vertex3(point.x - size, point.y - size, point.z + size);
GL.Vertex3(point.x - size, point.y + size, point.z + size);
// 上面
GL.Vertex3(point.x + size, point.y + size, point.z + size);
GL.Vertex3(point.x + size, point.y + size, point.z - size);
GL.Vertex3(point.x - size, point.y + size, point.z - size);
GL.Vertex3(point.x - size, point.y + size, point.z + size);
// 下面
GL.Vertex3(point.x + size, point.y - size, point.z + size);
GL.Vertex3(point.x + size, point.y - size, point.z - size);
GL.Vertex3(point.x - size, point.y - size, point.z - size);
GL.Vertex3(point.x - size, point.y - size, point.z + size);
// 左面
GL.Vertex3(point.x - size, point.y + size, point.z + size);
GL.Vertex3(point.x - size, point.y + size, point.z - size);
GL.Vertex3(point.x - size, point.y - size, point.z - size);
GL.Vertex3(point.x - size, point.y - size, point.z + size);
// 右面
GL.Vertex3(point.x + size, point.y + size, point.z + size);
GL.Vertex3(point.x + size, point.y + size, point.z - size);
GL.Vertex3(point.x + size, point.y - size, point.z - size);
GL.Vertex3(point.x + size, point.y - size, point.z + size);
}
GL.End();
}
}
说明: LinePainter 脚本组件需要挂在相机下。
SceneController.cs
using UnityEngine;
public class SceneController : MonoBehaviour {
private Transform cam; // 相机
private float nearPlan; // 近平面
private Vector3 preMousePos; // 上一帧的鼠标坐标
private int keyStatus = 0; // 鼠标样式状态
private bool isDraging = false; // 是否在拖拽中
void Start() {
cam = Camera.main.transform;
nearPlan = Camera.main.nearClipPlane;
}
void Update() {
keyStatus = GetKeyStatus();
UpdateScene(); // 更新场景(Ctrl+Scroll: 缩放场景, Ctrl+Drag: 平移场景, Alt+Drag: 旋转场景)
}
private int GetKeyStatus() { // 获取按键状态(0: 默认, 1: 缩放或平移, 2: 旋转)
if (isDraging) {
return keyStatus;
}
if (Input.GetKey(KeyCode.LeftControl) || Input.GetKey(KeyCode.LeftControl)) {
return 1;
}
if (Input.GetKey(KeyCode.LeftAlt) || Input.GetKey(KeyCode.LeftAlt)) {
return 2;
}
return 0;
}
private void UpdateScene() { // 更新场景(Ctrl+Scroll: 缩放场景, Ctrl+Drag: 平移场景, Alt+Drag: 旋转场景)
float scroll = Input.GetAxis("Mouse ScrollWheel");
if (!isDraging && keyStatus == 1 && Mathf.Abs(scroll) > 0) { // 缩放场景
ScaleScene(scroll);
} else if (Input.GetMouseButtonDown(0)) {
preMousePos = Input.mousePosition;
isDraging = true;
} else if (Input.GetMouseButtonUp(0)) {
isDraging = false;
} else if (Input.GetMouseButton(0)) {
Vector3 offset = Input.mousePosition - preMousePos;
if (keyStatus == 1) { // 移动场景
MoveScene(offset);
} else if (keyStatus == 2) { // 旋转场景
RotateScene(offset);
}
preMousePos = Input.mousePosition;
}
}
private void ScaleScene(float scroll) { // 缩放场景
cam.position += cam.forward * scroll;
}
private void MoveScene(Vector3 offset) { // 平移场景
cam.position -= (cam.right * offset.x / 100 + cam.up * offset.y / 100);
}
private void RotateScene(Vector3 offset) { // 旋转场景
Vector3 rotateCenter = GetRotateCenter(0);
cam.RotateAround(rotateCenter, Vector3.up, offset.x / 3); // 水平拖拽分量
cam.LookAt(rotateCenter);
cam.RotateAround(rotateCenter, -cam.right, offset.y / 5); // 竖直拖拽分量
}
private Vector3 GetRotateCenter(float planeY) { // 获取旋转中心
if (Mathf.Abs(cam.forward.y) < Vector3.kEpsilon || Mathf.Abs(cam.position.y) < Vector3.kEpsilon)
{
return cam.position + cam.forward * (nearPlan + 1 / nearPlan);
}
float t = (planeY - cam.position.y) / cam.forward.y;
float x = cam.position.x + t * cam.forward.x;
float z = cam.position.z + t * cam.forward.z;
return new Vector3(x, planeY, z);
}
}
说明: SceneController 脚本组件用于控制相机位置和姿态,便于从不同角度查看绘制的线段,其原理介绍见→缩放、平移、旋转场景。
3 运行效果

声明:本文转自【Unity3D】使用GL绘制线段
【Unity3D】使用GL绘制线段的更多相关文章
- Unity编辑器 - 使用GL绘制控件
Unity编辑器 - 使用GL绘制控件 控件较为复杂时,可能造成界面卡顿,在EditorGUI中也可以灵活使用GL绘制来提升性能. 以绘制线段为例: using UnityEngine; using ...
- 关于unity3D的GL图像库的使用
GL图象库 GL图象库是底层的图象库,主要功能是使用程序来绘制常见的2D与3D几何图形.这些图形具有一定的特殊性,他们不属于3D网格图形,只会以面的形式渲染.使用GL图象库,可在屏幕中绘制2D几何图形 ...
- Quartz2D复习(一)--- 基础知识 / 绘制线段圆弧 / 图片水印 / 截图
1.Quartz 2D是一个二维绘图引擎,同时支持ios和Mac系统: Quart2D的API是纯C语言的,API来自于Core Graphics框架: 2.Quartz 2D可以绘制图形(线段/三 ...
- C#GDI+ 绘制线段(实线或虚线)、矩形、字符串、圆、椭圆
C#GDI+ 绘制线段(实线或虚线).矩形.字符串.圆.椭圆 绘制基本线条和图形 比较简单,直接看代码. Graphics graphics = e.Graphics; //绘制实线 )) { pen ...
- 初级入门 --- web GL绘制点
" 万丈高楼平地起." 01基础知识 一.相关术语 图元 :WebGL 能够绘制的基本图形元素,包含三种:点.线段.三角形. 片元:可以理解为像素,像素着色阶段是在片元着色器中. ...
- Unity3D中灵活绘制进度条
有时我们需要在Unity3D中绘制进度条,如: 或 如果使用4.6版本以下的unity绘制环形的进度条可能需要费点劲.我搜到的大多数方法都是用NGUI插件,但有时只是 ...
- Android OpenGL ES(九)绘制线段Line Segment .
创建一个DrawLine Activity,定义四个顶点: float vertexArray[] = { -0.8f, -0.4f * 1.732f, 0.0f, -0.4f, 0.4f * 1.7 ...
- gl 绘制多边形的函数解析 分类: OpenGL(转)
http://blog.csdn.net/zhongjling/article/details/7528091 1,所谓正反面 glFrontFace(GL_CCW); // 设置CCW方向为“正面 ...
- unity3d 使用GL 方式画线
这个是画线部分 private Vector3[] linePoints; public int m_LineCount; public int m_PointUsed; public void Re ...
- Unity使用OpenGL绘制线段
using System.Collections; using System.Collections.Generic; using UnityEngine; public class ShowGrid ...
随机推荐
- 12-Verilog-同步FIFO设计
同步FIFO和异步FIFO FIFO分为一个同步FIFO,一个异步FIFO,FIFO有读口和写口 读写时钟是一个,就是同步FIFO;读写时钟不是一个,异步FIFO IP核设计中,一般使用同步FIFO设 ...
- [转帖]How to Resolve ORA-3136 Inbound Connection Timed Out
https://logic.edchen.org/how-to-resolve-ora-3136-inbound-connection-timed-out/#:~:text=ORA-03136%3A% ...
- [转帖]061、监控指标之TiKV
资源相关 Grafana监控 TiKV-Details -> Cluster - Store Size / Available Size Grafana监控 TiKV-Details -> ...
- [转帖]CentOS-7-x86_64-DVD-2009 rpm包列表(centos7.9)
https://www.cnblogs.com/hiyang/p/14803391.html 文件数 4071 个,共3.8G 复制389-ds-base-1.3.10.2-6.el7.x86_64. ...
- 一个简单的科普-延迟与RT时间
一个简单的科普-延迟与RT时间 背景 发现稍微一复杂就没人看. 这次像是写一个简单的科普文章. 主要说一下网络延迟还有网络的响应时间. 这里想通过一个题目进行引申. 如果Skylink全球商用: 中国 ...
- [转帖]一口气看完45个寄存器,CPU核心技术大揭秘
https://www.cnblogs.com/xuanyuan/p/13850548.html 序言 前段时间,我连续写了十来篇CPU底层系列技术故事文章,有不少读者私信我让我写一下CPU的寄存器. ...
- ARM 平台Docker运行RabbitMQ 以及迁移的简单办法
公司网络很垃圾. 可以使用vps 进行下载和打包 放到 公司的机器上面进行使用. 1. 搜索有没有可用的镜像. [root@JNXLH ~]# docker search rabbitmq |gre ...
- Redis labs 的安装
Install and setup This guide shows how to install Redis Enterprise Software, which includes several ...
- Redux和@reduxjs/toolkit的使用
1. 简介: Redux 是一种用于管理应用程序状态的 JavaScript 库.它是一个可预测的状态容器,可以用于编写 可维护和可扩展的应用程序. @reduxjs/toolkit 是一个官方提供的 ...
- 语义检索系统:基于Milvus 搭建召回系统抽取向量进行检索,加速索引
语义检索系统:基于Milvus 搭建召回系统抽取向量进行检索,加速索引 目标:使用 Milvus 搭建召回系统,然后使用训练好的语义索引模型,抽取向量,插入到 Milvus 中,然后进行检索. 语义搜 ...