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()
{
}
}

这个脚本提供了两个方法:

  1. Start()表示初始化(第一帧)的时候需要更新的内容,通常用于初始化之后不再更新的内容。比如我们会在这里绘制一个物体。
  2. 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——绘制一个三角形的更多相关文章

  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. 光照 ...

  2. OpenGL学习笔记(1) 画一个三角形

    最近找实习有一丢丢蛋疼,沉迷鬼泣5,四周目通关,又不想写代码,写篇笔记复习一下,要好好学图形学啊 用OpenGL画一个三角形 项目的简介 记录一下跟着learnOpenGL学习的过程 笔记里的代码放在 ...

  3. 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. 渲染 ...

  4. Unity3D学习笔记4——创建Mesh高级接口

    目录 1. 概述 2. 详论 3. 其他 4. 参考 1. 概述 在文章Unity3D学习笔记2--绘制一个带纹理的面中使用代码的方式创建了一个Mesh,不过这套接口在Unity中被称为简单接口.与其 ...

  5. Unity3D学习笔记6——GPU实例化(1)

    目录 1. 概述 2. 详论 3. 参考 1. 概述 在之前的文章中说到,一种材质对应一次绘制调用的指令.即使是这种情况,两个三维物体使用同一种材质,但它们使用的材质参数不一样,那么最终仍然会造成两次 ...

  6. Unity3D学习笔记8——GPU实例化(3)

    目录 1. 概述 2. 详论 2.1. 自动实例化 2.2. MaterialPropertyBlock 3. 参考 1. 概述 在前两篇文章<Unity3D学习笔记6--GPU实例化(1)&g ...

  7. Unity3D学习笔记12——渲染纹理

    目录 1. 概述 2. 详论 3. 问题 1. 概述 在文章<Unity3D学习笔记11--后处理>中论述了后处理是帧缓存(Framebuffer)技术实现之一:而另外一个帧缓存技术实现就 ...

  8. [Modern OpenGL系列(三)]用OpenGL绘制一个三角形

    本文已同步发表在CSDN:http://blog.csdn.net/wenxin2011/article/details/51347008 在上一篇文章中已经介绍了OpenGL窗口的创建.本文接着说如 ...

  9. unity3d学习笔记(一) 第一人称视角实现和倒计时实现

    unity3d学习笔记(一) 第一人称视角实现和倒计时实现 1. 第一人称视角 (1)让mainCamera和player(视角对象)同步在一起 因为我们的player是生成的,所以不能把mainCa ...

随机推荐

  1. Mybatis学习之自定义持久层框架(五) 自定义持久层框架:封装CRUD操作

    前言 上一篇文章我们完成了生产sqlSession的工作,与数据库的连接和创建会话的工作都已完成,今天我们可以来决定会话的内容了. 封装CRUD操作 首先我们需要创建一个SqlSession接口类,在 ...

  2. apache common pool2原理与实战

    完整源码,请帮我点个star哦! 原文地址为https://www.cnblogs.com/haixiang/p/14783955.html,转载请注明出处! 简介 对象池顾名思义就是存放对象的池,与 ...

  3. pytorch实现LeNet5分类CIFAR10

    关于LeNet-5 LeNet5的Pytorch实现在网络上已经有很多了,这里记录一下自己的实现方法. LeNet-5出自于Gradient-Based Learning Applied to Doc ...

  4. ES6中函数参数默认值问题

    参数默认值 // 以前的参数默认值写法 let fn = (a, b) => { a = typeof a === "undefined" ? 10 : a b = type ...

  5. 把一个整体目标设置成多个分阶段目标,完成了一个目标后,就相当于一件事OVER

    如果事情有变坏的可能,不管这种可能性有多小,它总会发生 . 一.任何事都没有表面看起来那么简单:二.所有的事都会比你预计的时间长:三.会出错的事总会出错:四.如果你担心某种情况发生,那么它就一定会发生 ...

  6. CentOS Linux搭建独立SVN Server全套流程(修改svn仓库地址、服务启动等)

    CentOS Linux搭建独立SVN Server全套流程(修改svn仓库地址.服务启动等) 原 一事能狂便少年 发布于 2016/12/27 11:16 字数 1113 阅读 1.3K  收藏 0 ...

  7. elasticksearch分词,导致kibana的url出现问题

    在Kibana的展示页面中,我们点击Table的左侧栏,发现Elasticsearch中的数据在展示中是正确的数据,比如:agent中www.baidu.com/test,该界面中会正确的显示为www ...

  8. 拉勾、Boss直聘、内推、100offer

    BOSS直聘 拉勾.Boss直聘.内推.100offer  

  9. bond0 配置ip不生效排查方法

         今天巡检的时候,发现无法连接到服务器上面了,于是到机房连接到显示器查看: 1.先检查网卡,协议有没有问题. 2.远程链接的网卡名称是bond0,用ifconfig看看网卡配置,然后发现配置的 ...

  10. HTTP、TCP、UDP,Socket,HTTPS

    TCP   HTTP   UDP三者的关系如下: TCP/IP是个协议组,可分为四个层次:网络接口层.网络层.传输层和应用层. 在网络层有IP协议.ICMP协议.ARP协议.RARP协议和BOOTP协 ...