OceaBase开发者大会落地上海!4月20日共同探索数据库前沿趋势!报名戳 了解详情
写点什么

Unity 引擎与 C#脚本简介

  • 2019-08-21
  • 本文字数:3380 字

    阅读完需:约 11 分钟

Unity引擎与C#脚本简介

1. Unity 编辑器基础

从原理上讲,游戏开发就是将一系列变动的场景呈现在玩家面前,并根据玩家的输入修改游戏画面;而游戏画面则是通过调用目标操作系统上的图形图像库来绘制的。比较知名的图形图像库有 Windows 上的 DirectX,*nix 系统、macOS 和 iOS 等系统上用到的 OpenGL 以及 Android 用到的 Vulkan 等。


一般来讲,底层的图形图像 API 只能进行最基本的三角形绘制,但是,因为是通过计算机的 GPU 进行的操作,具有并行计算的优势,在短短六十分之一秒时间内,也可以绘制出成千上万个三角形,而这么多小三角形堆叠起来看,视觉效果也就和真实场景差别不大了。



图一:古墓丽影劳拉变化图


现代游戏引擎一般都会把游戏人物的“建模”工作交给第三方,引擎本身只负责游戏场景和人物的绘制以及内部交互逻辑。第三方建模软件通过模拟人物的真实 3D 外观来将虚拟人物表面“三角形化”,附带上游戏人物在做出不同动作时的外观数据,最后生成游戏引擎可识别格式的文件,这个过程就是所谓的 3D 建模。



图二:绘制流程


3D 模型制作完成后,会由游戏引擎进行绘制,这个过程一般称作“着色”(Shading)。着色的核心是叫做“着色器(Shader)”的 GPU 程序 - GPU 通过输入一些参数信息,然后执行着色器程序就能生成最终的游戏图像。


GPU 需要的参数信息主要有两种:一是纹理,二是材质。


纹理是指一个模型的表面,可以理解成一件衣服平铺起来的样子。如果是一个三维物体,其表面的纹理可以想象成是把它的表面拆开,然后压扁后的样子。什么是材质呢?材质(Material)从字面上理解的话就是材料,比如木头和大理石,看起来就是不一样的效果。同样的纹理,用不一样的材质来绘制,会得到不一样的效果图,因为材质有一些关键的参数,会影响着色器的绘制效果。


比较重要的一个参数是反射率(Albedo)。


光滑材质的反射率比较高,看起来就会亮一些。在自然白光的照射下,这样的材质看起来会偏白,如果沿着光照方向看过去,会出现光斑效果(太阳光照射下的湖面看起来会有一种很耀眼的效果)。粗糙材质的反射率比较低,看起来就比较柔和。典型的高反射率材质比如光滑的金属表面,典型的低反射率材质有布料、地面等。在 3D 场景中,反射率高的物体受周围物体的影响更大。譬如,一个平静的湖面会倒映出地面的建筑物。因此,高反射率的材质通常需要更多的绘制步骤。



图三:一个金属球体在场景中的效果图


材质的另一个重要参数是法向图(Normal Map)。


法向就是物体表面的方向。法向图表示的是材质的表面细节,比如凹槽、斑点、凸起或者空洞等,法向图通常以纹理图来表示。然而不同于一般的纹理图,法向图的每个像素点称作“纹素(texel)”,它表示的是纹理在此位置处的光照反射方向,纹素的 RGB 分量分别对应反射方向的 XYZ 分量。



图四:法向图示例


一个 3D 模型的表面纹理被分割成一个个小三角形,而法向图就表示此表面的每个像素点位置的光照反射方向。方向不同的三角形绘制出来和周围的三角形看起来颜色是不同的,从而产生了视觉上的凸起/凹陷效果。这种物体的表面细节,如果在 3D 建模阶段通过修改模型外观的方式来实现的话,会增加很多物体表面的细小的绘制操作。通过材质的法向图来实现,将物体“表面”和物体的实际皮肤剥离开了,可以实现同一个人物穿上不同衣服的效果。



图五:绘制效果图


如上图所示,右边的物体采用左边的法向图来绘制,注意看凸起位置的颜色

2. C#脚本语言

2.1 为什么需要脚本?

长久以来,游戏引擎开发都采用底层语言如 C++来进行,这对于游戏上层开发来说,并不友好。很难想象如果使用一款引擎修改某个人物的动作,还需要直接调用 C++底层的接口,这样既不安全,也不方便。因此,一般引擎从设计之初就会把封装好的绘制接口通过某些上层语言暴露出来,给游戏制作方使用。这些上层语言就叫做游戏脚本语言。


lua 是脚本语言里面比较流行的一种,因其虚拟机小巧、API 丰富、可灵活定制而深受游戏引擎开发商的喜爱。Unity 使用了 C#和 Unity Script(现已废弃)来作为脚本语言。C#语言因为建立在


.NET IL 之上而具有跨平台扩展性。这样,游戏开发者只需要一套代码就可在多个平台运行。



图六:.NET CIL 和 CLR

2.2 IL 是什么?

IL(Intermediate Language,在.NET 平台下是 CIL,Common Intermediate Language)是一种中间语言格式,类似于 Java 的字节码(byte code),这种格式的代码需要一个虚拟机来“解释”执行。IL 的所有指令都是基于虚拟堆栈的:调用函数前,先将参数 push 到虚拟堆栈里面;函数执行的时候,从虚拟堆栈里面取出参数,然后将结果压入虚拟堆栈。由于调用方式简单,IL 语言的指令集也比较精简。


IL 作为脚本语言的独到之处在于可以将 C#上层语言的各种特性(如泛型、协程等)转换成基本的 IL 指令集,但是这样的转换也是有代价的 — 转换后的 IL 指令比普通的函数调用多出数倍。因此,在游戏开发中,不宜在每一帧中都进行这一类的调用。


另外,IL 语言执行需要一个虚拟机翻译成目标平台的机器码,虽然.NET 虚拟机已经比较高效了(可参考.NET 与 Java 的对比),但是和平台原生代码比起来,依然有一些差距。在 iOS 平台上,由于苹果禁止使用 JIT 方式,IL 指令需要预先编译成目标平台库文件,然后在最终二进制文件打包的时候作为第三方库链接进去。Unity 游戏几乎所有的游戏逻辑都是通过脚本来实现的,一个大型游戏,成千上万个脚本,AOT 方式打包造成的效率低下,是不得不考虑的问题。因此,Unity 在 5.3.4 版本中引入了 il2cpp 技术。

2.3 il2cpp 原理

顾名思义,il2cpp 就是把中间语言转换成 cpp 代码的工具。上面我们讲到,在 iOS 平台上,由于无法使用 JIT 方式执行 IL 指令,所以需要先将游戏脚本打包成 .NET Managed Assembly(这里的 Managed 是指二进制文件是在.NET 层面打包的,可能会依赖.NET 底层库,可以理解为“安全的”库文件。另外有些库文件是通过直接封装 C/C++接口方式生成的,由于有如指针之类的底层内存操作,所以称作是 Unmanaged Assembly),然后和 .NET CLR 的 Assembly 链接之后生成最终的平台二进制文件。il2cpp 的作用是去掉链接 .NET CLR 的步骤,将 C#脚本生成的 Managed Assembly“翻译”成 C++文件,最后用目标平台的编译器编译这些 C++文件来生成最终的游戏可执行文件。



图七:il2cpp 工作原理示意图


il2cpp 会先读取.NET 二进制文件,解析其中的符号,然后将其中 C#方法转换成对应的 C 方法。虽然名为 il2cpp,但其实它只用到了很少部分的 C++特性,绝大多数转换后的代码都是 C 函数。



图八:il2cpp 转换后的代码示例


在游戏运行前,il2cpp 会启动一个小的虚拟机,用于动态解析 C 方法。其会将所有方法的签名放在一个叫做 global-metadata.dat 的文件里,方法调用的时候会先从此文件里读取 C 函数地址,然后再调用。


获取函数指针的方法是这个:


inline Il2CppMethodPointer il2cpp_codegen_resolve_icall (const char* name){    Il2CppMethodPointer method = il2cpp::vm::InternalCalls::Resolve (name);    if (!method)    {        il2cpp::vm::Exception::Raise(il2cpp::vm::Exception::GetMissingMethodException(name));    }    return method;}
复制代码


图九:获取函数指针


Unity 确保了所有采用 il2cpp 平台实现的游戏,其 metadata 的格式都是一样的。metadata 加载时采用了内存映射技术,上述函数实际上会从一张内存的数据表里查找方法名对应的键值,也即目标函数的地址。


为何 Unity 要采用文件来记录方法名?一是游戏有动态解析方法的需求;再者是这样可以隐藏掉游戏内部逻辑的实现,起到一部分混淆的作用;最后还有一个重要的原因是 Unity 编辑器里可以设置脚本执行时候的延迟时间,而这些信息可以很方便的放在文件里。


Unity C#层面的接口暴露给游戏开发者,开发者通过 C#脚本编写游戏逻辑,然后通过 il2cpp 将脚本翻译成 C++文件,接着链接上 Unity C#接口的底层 C++实现,最终生成游戏的二进制文件,这就是 Unity 游戏开发的大致过程。


按照 Unity 的说法,通过 il2cpp 方式打包有多种好处:


跨平台兼容性更好。基本上所有游戏平台都支持 C++代码,而 .NET/Mono 运行时却不一定能在所有平台上运行;


效率更高。Unity 给出的数据显示采用 il2cpp 打包之后,游戏的执行效率提升了 1.5 到 2.0 倍。


以上就是游戏开发的一些基本知识。


本文转载自公众号小时光茶舍(ID:gh_7322a0f167b5)。


原文链接:


Unity引擎与C#脚本简介


2019-08-21 10:1915786

评论

发布
暂无评论
发现更多内容

DxO PhotoLab 7 for Mac v7.2.0.42激活版

影影绰绰一往直前

喜讯!云起无垠斩获“东升杯”国际创业大赛“优秀奖”

云起无垠

一键生成PPT!让AI成为您的最佳帮手!

飞桨PaddlePaddle

人工智能 深度学习 PPT

如何将 Python 项目打包成 exe,另带卸载功能!

北桥苏

Python GUI pyinstaller tkinter Inno Setup Compiler

软件测试/测试开发丨名企私教服务加盟全栈开发与自动化测试班

测试人

人工智能 软件测试

VideoPad Video Editor for Mac v13.81注册激活版

影影绰绰一往直前

DxO PureRAW for Mac v3.8.0中文激活版(RAW照片处理器)

影影绰绰一往直前

怀念一代传奇,陈皓与他的《左耳听风:传奇程序员练级攻略》

博文视点Broadview

In-depth comparison of QCN9074, QCN9024 and QCN9274 Qualcomm Wi-Fi chip families

wallysSK

如何优化 RAG 系统的性能表现?10 条实用策略

Baihai IDP

深度学习 程序员 AI 白海科技 rag

Fine-Tuning: 精调大模型训练的关键步骤

百度开发者中心

大模型

法线贴图实现地形模型皱褶、凹凸不平的纹理效果

3D建模设计

3D渲染 材质纹理贴图

DxO PhotoLab 6 for Mac v6.12.0.62激活版

影影绰绰一往直前

IPQ6010 vs. IPQ4019: The battle of Qualcomm chips and WIFI 6 vs WIFI 5

wallysSK

实时湖仓技术选型,企业如何借实时湖仓赢在“数据驱动”时代

袋鼠云数栈

大数据 数据湖 湖仓一体 实时湖仓

LLAMA预训练:大模型的潜力与挑战

百度开发者中心

人工智能 深度学习 大模型

大模型微调:适应新任务的强大工具

百度开发者中心

深度学习 大模型 Prompt

ON1 Photo RAW 2024 for Mac中文直装版下载

影影绰绰一往直前

2023 年中国金融级分布式数据库市场报告:TiDB 位列领导者梯队,创新能力与增长指数表现突出

编程猫

Find Any File for Mac v2.4.2b2免激活版

影影绰绰一往直前

得物商家域精准测试实践

得物技术

测试

Native Instruments Komplete Kontrol for mac激活版

影影绰绰一往直前

WonderPen妙笔 for Mac v2.4.2中文激活版

影影绰绰一往直前

未来LED小间距显示屏竞争的焦点在哪里

Dylan

中国 产业‘’ LED LED显示屏 市场

科学启智,AI赋能:AI for Science塑造多学科研究新范式

飞桨PaddlePaddle

人工智能 开发者 AI for Science WAVE SUMMIT

Databend 源码阅读: Meta-service 数据结构

Databend

淘宝商品评论数据接口(Taobao.item_review)

tbapi

淘宝API接口 淘宝商品评论接口 天猫商品评论接口 淘宝评论内容接口 天猫评论内容接口

ApeCoin DAO猿岛质押游戏系统开发:APE开岛屿-质押藏宝箱获得代币

l8l259l3365

百度搜索创新大赛,一场2800人的技术狂欢

百度Geek说

人工智能 企业号12月PK榜 百度搜索技术大赛

Unclutter for mac v2.2.5中文激活版

影影绰绰一往直前

软件测试/测试开发|测试开发线下高薪私教班助力你的职场晋升

霍格沃兹测试开发学社

Unity引擎与C#脚本简介_语言 & 开发_jojokzhang_InfoQ精选文章