Unity3D学习笔记1——绘制一个三角形
1. 绪论
最近想学习一下Unity3d,无奈发现现在大部分教程不仅是视频形式的,面对的也是美术、设计之类的非程序员,更多的时候都是把Unity3d当作PS一样的工具来用,真正面对程序开发的教程反而非常少,更不用说希望能研究到一些底层图形技术的技术工作者了。
说一下我看的两本Unity3d书籍吧。第一本是《Unity 3D游戏开发(第2版)》(宣雨松 著)。这本书算是大部分教程书籍中评价比较好的了,很多人推荐。不过个人感觉作者对Unity3D的知识有了太多的积累,已经忘记了初学者初学Unity3D的心态,知识也显得比较零散。不过这也是国内大多数书籍的通病了,更像是作者对知识的总结而不是成体系的向读者介绍知识。建议初学者看这本书一定要实操,喜欢头脑风暴的同学不适合这本书。
看的第二本书是《Unity Shader入门精要》(冯乐乐 著)。令人佩服的是这本书是位程序媛写的,可能正是因为如此,这本书写的确实非常细致到位。尤其是前面几章对渲染管线的描述,从Unity3D图形技出发,已然上升到计算机图形学的高度上,对学习其他的图形技术也有非常大的帮助(毕竟很多图形技术都是通用的)。当时看了觉得确实很不错,因此还送了同事一本。
最后就是自己也想总结一下Unity3D的相关知识吧,本身是个程序猿,当然更多的会偏向游戏开发的程序员角度,或者图形技术的程序员的角度一点。
2. 概述
图形渲染技术的第一个HelloWorld当然应该就是绘制一个三角形了。在绝大多数情况下,三角面是渲染物体的基础图元。作为高级的渲染引擎,像三角面这样的几何体甚至不需要我们去通过代码来绘制,但是却是我们学习的基础,立足于这个基础,我们以后能够渲染更加复杂的图形。
3. 详论
3.1. 准备
通过Unity Hub创建一个3D工程:

进入Unity3D环境,通过右键菜单,在"Hierarchy"视图中添加一个名为"Root"空的GameObject:

GameObject对象是Unity3D中得一个基础类,Unity3D中得绝大部分对象都是基于它实现的,比如相机、灯光、或者模型等。所以我们这里把创建的名为Root的GameObject对象作为场景的根节点。
在Root对象的Inspector面板中,可以看到一个"Add Component"按钮:

也就是说,通过"Add Component"按钮,我们可以挂接一些组件,这样,空的GameObject对象就成为了其他类型的对象。例如,我这里挂接一个C#脚本,通过C#脚本来绘制物体,那么这个GameObject,表示的就是一个渲染的物体。
在"Project"视图中,通过右键菜单创建一个C#脚本:

通过Root对象的Inspector面板中的"Add Component"按钮,将这个脚本,挂接到Root对象下:

3.2. 实现
通过"Project"视图的右键菜单中打开这个C#工程,可以看到我们添加的脚本"Main.CS":
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Main : MonoBehaviour
{
// Start is called before the first frame update
void Start()
{
}
// Update is called once per frame
void Update()
{
}
}
这个脚本提供了两个方法:
- Start()表示初始化(第一帧)的时候需要更新的内容,通常用于初始化之后不再更新的内容。比如我们会在这里绘制一个物体。
- Update()表示每一帧都需要实时更新的内容,比如相机与鼠标键盘事件的交互。
那么就在Start()中进行绘制一个三角形的操作:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Main : MonoBehaviour
{
// Start is called before the first frame update
void Start()
{
GameObject main = GameObject.Find("/Root");
if (main == null)
{
return;
}
GameObject triangleGameObject = GreateTriangle();
triangleGameObject.transform.parent = main.transform;
}
GameObject GreateTriangle()
{
string name = "triangle";
Mesh mesh = new Mesh();
mesh.name = name;
Vector3[] vertices = new Vector3[3]
{
new Vector3(0, 0, 0),
new Vector3(0, 10, 0),
new Vector3(10, 0, 0)
};
mesh.vertices = vertices;
int[] triangles = new int[3] { 0, 1, 2 };
mesh.triangles = triangles;
GameObject triangleGameObject = new GameObject(name);
MeshFilter mf = triangleGameObject.AddComponent<MeshFilter>();
mf.sharedMesh = mesh;
MeshRenderer meshRenderer = triangleGameObject.AddComponent<MeshRenderer>();
return triangleGameObject;
}
// Update is called once per frame
void Update()
{
}
}
3.3. 解析
3.3.1. 场景树对象
在Start()函数中,首先我们找到了场景根节点Root,然后又通过调用GreateTriangle()函数,创建了一个三角形的GameObject对象,最后把这个三角形对象挂接到Root对象下:
void Start()
{
GameObject main = GameObject.Find("/Root");
if (main == null)
{
return;
}
GameObject triangleGameObject = GreateTriangle();
triangleGameObject.transform.parent = main.transform;
}
可以看到子对象挂接到父对象是通过GameObject对象中Transform对象来挂接的,这其实体现了一种思维的体现:Transform其实是表达GameObject对象空间位置的的4X4矩阵,父节点设置Transform会影响到子节点的位置,子节点的初始位置都是基于父节点的Transform开始计算的。通过这种方式,再复杂的场景也可以组织成一个场景树节点:

3.3.2. 绘制方法
经过图形技术的多年发展,现在大部分图像渲染引擎都会把渲染的物体封装成两种对象:渲染物体的骨架封装成Mesh(网格),因为绝大多数物体都是通过一个个三角面片渲染出来的;渲染物体的血肉封装成Material(材质),影响最终渲染的效果,如物体的光感、质地。
所以,为了绘制一个三角形,当然应该先绘制一个Mesh:
GameObject GreateTriangle()
{
string name = "triangle";
Mesh mesh = new Mesh();
mesh.name = name;
Vector3[] vertices = new Vector3[3]
{
new Vector3(0, 0, 0),
new Vector3(0, 10, 0),
new Vector3(10, 0, 0)
};
mesh.vertices = vertices;
int[] triangles = new int[3] { 0, 1, 2 };
mesh.triangles = triangles;
//...
}
这里,我们给Mesh传入了三个顶点,以及顶点的三角面索引。三角面索引表示的是按照索引的顺序,通过顶点进行绘制,这样就可以使用较少的顶点进行绘制,节约空间,毕竟Mesh中很多三角面片是共顶点的。
接下来,给GameObject增加一个MeshFilter组件,通过这个组件挂接刚创建的Mesh;给GameObject增加一个MeshRenderer组件,这个组件是用来挂接Material的,不过暂时没有用上Material(但是必须增加MeshRenderer组件,否则不会显示物体)。
GameObject GreateTriangle()
{
//...
GameObject triangleGameObject = new GameObject(name);
MeshFilter mf = triangleGameObject.AddComponent<MeshFilter>();
mf.sharedMesh = mesh;
MeshRenderer meshRenderer = triangleGameObject.AddComponent<MeshRenderer>();
return triangleGameObject;
}
4. 结果
点击"Play",运行结果如下:


Unity3D学习笔记1——绘制一个三角形的更多相关文章
- Unity3D学习笔记2——绘制一个带纹理的面
目录 1. 概述 2. 详论 2.1. 网格(Mesh) 2.1.1. 顶点 2.1.2. 顶点索引 2.2. 材质(Material) 2.2.1. 创建材质 2.2.2. 使用材质 2.3. 光照 ...
- OpenGL学习笔记(1) 画一个三角形
最近找实习有一丢丢蛋疼,沉迷鬼泣5,四周目通关,又不想写代码,写篇笔记复习一下,要好好学图形学啊 用OpenGL画一个三角形 项目的简介 记录一下跟着learnOpenGL学习的过程 笔记里的代码放在 ...
- Unity3D学习笔记3——Unity Shader的初步使用
目录 1. 概述 2. 详论 2.1. 创建材质 2.2. 着色器 2.2.1. 名称 2.2.2. 属性 2.2.3. SubShader 2.2.3.1. 标签(Tags) 2.2.3.2. 渲染 ...
- Unity3D学习笔记4——创建Mesh高级接口
目录 1. 概述 2. 详论 3. 其他 4. 参考 1. 概述 在文章Unity3D学习笔记2--绘制一个带纹理的面中使用代码的方式创建了一个Mesh,不过这套接口在Unity中被称为简单接口.与其 ...
- Unity3D学习笔记6——GPU实例化(1)
目录 1. 概述 2. 详论 3. 参考 1. 概述 在之前的文章中说到,一种材质对应一次绘制调用的指令.即使是这种情况,两个三维物体使用同一种材质,但它们使用的材质参数不一样,那么最终仍然会造成两次 ...
- Unity3D学习笔记8——GPU实例化(3)
目录 1. 概述 2. 详论 2.1. 自动实例化 2.2. MaterialPropertyBlock 3. 参考 1. 概述 在前两篇文章<Unity3D学习笔记6--GPU实例化(1)&g ...
- Unity3D学习笔记12——渲染纹理
目录 1. 概述 2. 详论 3. 问题 1. 概述 在文章<Unity3D学习笔记11--后处理>中论述了后处理是帧缓存(Framebuffer)技术实现之一:而另外一个帧缓存技术实现就 ...
- [Modern OpenGL系列(三)]用OpenGL绘制一个三角形
本文已同步发表在CSDN:http://blog.csdn.net/wenxin2011/article/details/51347008 在上一篇文章中已经介绍了OpenGL窗口的创建.本文接着说如 ...
- unity3d学习笔记(一) 第一人称视角实现和倒计时实现
unity3d学习笔记(一) 第一人称视角实现和倒计时实现 1. 第一人称视角 (1)让mainCamera和player(视角对象)同步在一起 因为我们的player是生成的,所以不能把mainCa ...
随机推荐
- Window内核学习之保护模式基础
段寄存器 段寄存器有6个分别是 cs,ss,ds,es,fs,gs.这些段寄存器包含16位的可见部分和80位的隐藏部分,共90位. 16位的可见部分就是我们知道的cs等段寄存器的值,我们可以在od中查 ...
- Matlab将数据存为文本文件
dlmwrite :将一个矩阵写到由分隔符分割的文件中. 在保存整数到文件时使用save存为ascii文件时,常常是文件里都是实型格式的数据(有小数点,和后面很多的0,看着很不方便).于是要保存此类数 ...
- COS 数据湖最佳实践:基于 Serverless 架构的入湖方案
01 前言 数据湖(Data Lake)概念自2011年被推出后,其概念定位.架构设计和相关技术都得到了飞速发展和众多实践,数据湖也从单一数据存储池概念演进为包括 ETL 分析.数据转换及数据处理的下 ...
- ocalhost kernel: [244840.301449] nf_conntrack: nf_conntrack: table full, dropping packet
nf_conntrack: table full, dropping packet. 终结篇 "连接跟踪表已满,开始丢包"!相信不少用iptables的同学都会见过这个错误信息 ...
- Docker创建镜像以及私有仓库
Docker的安装及镜像.容器的基本操作详见博客https://blog.51cto.com/11134648/2160257下面介绍Docker创建镜像和创建私有仓库的方法,详细如下: 创建镜像 创 ...
- Linux 操作系统(三) 添加用户、切换用户、删除用户
以下命令均已在 Kali Linux 验证. 1.添加用户 --1-- useradd -m username //username 代表你所添加的用户名 --2-- passw ...
- 015.Python函数名的使用以及函数变量的操作
一 函数名的使用 python中的函数可以像变量一样,动态创建,销毁,当参数传递,作为值返回,叫第一类对象.其他语言功能有限 1.1 函数名是个特殊的变量,可以当做变量赋值 def func(): p ...
- 使用nuget包下载Entity Framework6.0无法使用模型类与数据库上下文自动生成controller与view
解决方法:卸载掉原有的6.0版本EF,从控制台安装5.0版本的. >工具>库程序包管理器>程序包管理器控制台.在PM>后面输入安装命令. 命令如下 Install-Packag ...
- 【分布式】-- 基于Nacos、OpenFeign搭建的微服务抽奖系统后台小案例
1.项目介绍 最近入项目之前要求熟悉一下SpringCloud Nacos微服务基于Feign接口调用并整合Swagger2进行接口文档展示给前端,所以自己按照要求来编写并整合了一套基于SpringC ...
- 多平台Gstreamer Multiplatform
多平台Gstreamer Multiplatform GStreamer可在所有主要操作系统上运行,例如Linux,Android,Windows,Max OS X,iOS,以及大多数BSD,商业Un ...