Unity基础:材质与纹理入门——给物体穿上“衣服“

Unity基础:材质与纹理入门------给物体穿上"衣服"

大家好,欢迎回到Unity教程系列。上一篇文章我们学会了如何创建和操作基本的3D物体,但你可能会觉得------那些白花花或纯色的方块看起来太无聊了。今天这篇文章,我们要让游戏物体变得赏心悦目起来。

材质和纹理是游戏视觉表现的基石。它们决定了场景中的每个物体的外观------墙壁是木头还是砖石,角色是穿着布衣还是铠甲,地面是草地还是沙漠。理解了材质与纹理的工作原理,你就能给游戏世界"穿上衣服",让它变得生动而丰富。

一、材质与纹理的基本概念

1.1 什么是材质(Material)

💡 材质(Material)是定义物体表面外观的数据集合。它告诉渲染引擎:这个物体表面应该是什么颜色、有多少反光、是粗糙还是光滑、是否透明、是否发光等等。

一个材质本质上是一个Shader(着色器)+ 一组参数值的组合。Shader决定了"怎么算颜色",材质的参数决定了"具体算什么颜色"。

类比理解:如果把Shader比作一道菜的配方(决定怎么做),材质就是按照这个配方做出来的具体一道菜(放了多少盐、多少辣椒)。

1.2 什么是纹理(Texture)

💡 纹理(Texture)是一张二维图片,它被"包裹"在3D模型的表面,提供精细的视觉细节。纹理是材质最重要的参数之一------没有纹理,物体就是纯色的;有了纹理,物体可以有木纹、砖纹、布料纹理等丰富的细节。

常见的纹理类型

  • Albedo / Base Map(基色贴图):定义物体表面的基本颜色和图案。这是最常用的纹理,比如一块木板的木纹、一面墙的砖纹。
  • Normal Map(法线贴图):模拟表面凹凸细节而不增加模型面数。蓝色调的图片,让低面数模型看起来有高面数模型的细节。
  • Metallic Map(金属度贴图):指定表面的哪些部分是金属、哪些部分不是。白色区域是金属,黑色区域不是。
  • Smoothness / Roughness Map(光滑度贴图):指定表面的哪些区域更光滑、哪些更粗糙。
  • Emission Map(自发光贴图):指定表面的哪些区域会自发光(如机器人的眼睛、能量核心等)。
  • Height Map(高度贴图):提供表面的高度信息,用于视差映射等高级效果。
  • Ambient Occlusion Map(环境光遮蔽贴图):模拟角落和缝隙中的环境光阴影。

1.3 材质、纹理和Shader的关系

这三者之间的关系可以用一句话概括:Shader是渲染算法,材质是算法的参数集,纹理是参数的一种(图片类型的参数)

复制代码
Shader (Standard) ────定义了"基于物理的渲染(PBR)"的计算方法
    │
    └── Material (Mat_Wood) ────使用Standard Shader,并设置了具体的参数
            ├── Albedo: wood_texture.png(木材贴图作为基色)
            ├── Normal Map: wood_normal.png(木材的法线贴图)
            ├── Metallic: 0(木材不是金属)
            ├── Smoothness: 0.3(木材比较粗糙)
            └── Tiling: (1, 1)

二、创建和应用材质

2.1 在Unity中创建材质

① 在Project窗口中,进入你想要存放材质的文件夹(如果没有Materials文件夹,先创建一个)。

② 右键 → Create → Material。

③ 新材质出现在Project窗口中,命名为"M_FirstMaterial"(建议材质以M_前缀命名,方便搜索和管理)。

④ 选中材质,在Inspector中看到材质的属性面板。

2.2 材质属性面板详解

以Unity内置的Standard Shader为例(Built-in渲染管线),材质面板的主要属性:

Rendering Mode(渲染模式)

  • Opaque(不透明):默认模式,用于完全不透明的物体(墙壁、石头、木箱等)。这是性能最好的模式。
  • Cutout(镂空):用于有完全透明区域的物体(树叶、栅栏的铁丝网),配合Alpha Cutoff阈值使用。要么完全透明,要么完全不透明。
  • Fade(渐隐):物体整体可以半透明,适合淡入淡出效果。但有一些光照计算上的限制。
  • Transparent(透明):用于玻璃、水等需要真实透明度的物体,支持不同区域的不同透明度。

Albedo(基色/反照率)

  • 颜色选择器:设置物体的基本颜色
  • 纹理槽:拖拽贴图到这里作为基色纹理
  • 颜色与纹理的关系:纹理的每个像素颜色会乘以这里设置的颜色。如果颜色设为白色,纹理以原始颜色显示;如果颜色设为红色,纹理整体偏红。

Metallic(金属度):0为完全非金属(电介质),1为完全金属。真实世界中的物体要么是金属要么不是(很少有中间值),所以通常设为0或1。光滑的非金属(如光滑塑料)和光滑的金属(如不锈钢)看起来完全不同------金属会反射出有色高光。

Smoothness(光滑度):0为完全粗糙(漫反射),1为完全光滑(镜面反射)。金属和非金属都可以有不同的光滑度。

Normal Map(法线贴图):给表面添加凹凸细节。法线贴图是一张蓝紫色的特殊贴图,通过改变每个像素的法线方向来模拟凹凸不平的表面效果。

Height Map(高度贴图):配合视差映射(Parallax Mapping)使用,提供更强的深度感和立体感。

Emission(自发光):让材质从内部发光。可以设置发光颜色、强度和发光贴图。用于制作灯光面板、屏幕、魔法符文、能量核心等发光物体。注意:自发光材质在Baked GI中可以影响周围的静态物体。

Tiling(平铺)和Offset(偏移)

  • Tiling的X和Y值控制纹理在物体表面的重复次数。设为(2,2)意味着纹理在水平方向和垂直方向各重复2次,图案变得更密集。
  • Offset控制纹理的偏移量,用于微调纹理在物体表面的位置。

2.3 给物体应用材质

有三种方式给GameObject应用材质:

方式一:拖拽(最常用)

将材质从Project窗口直接拖到Scene视图中的物体上。松手后物体立即改变外观。

方式二:从Inspector赋值

① 选中物体

② 在Inspector中找到MeshRenderer组件

③ 在Materials数组中找到Element 0

④ 将材质拖到槽位中,或点击槽位右侧的圆形选择器搜索材质

方式三:拖到Hierarchy

将材质从Project窗口拖到Hierarchy中的GameObject名称上。

2.4 多个材质与子网格

一个MeshRenderer可以包含多个材质槽(对应模型的不同子网格SubMesh)。例如一个角色模型可能分成了"身体"和"武器"两个子网格,在Materials数组中分别使用不同的材质。

在代码中操作材质:

csharp 复制代码
// 获取并修改物体的第一个材质
// 注意:这会创建材质实例的副本!
Material mat = GetComponent<Renderer>().material;
mat.color = Color.red;

// 获取共享材质(不会创建实例副本,推荐用于批量操作)
Material sharedMat = GetComponent<Renderer>().sharedMaterial;

// 获取所有材质
Material[] materials = GetComponent<Renderer>().materials;
materials[0].color = Color.blue;
GetComponent<Renderer>().materials = materials;

⚠️ 注意 materialsharedMaterial 的区别:

  • material:返回该物体的材质实例副本。修改它只会影响这一个物体,但会增加DrawCall。
  • sharedMaterial:返回共享的材质资源。修改它会影响所有使用该材质的物体,但不会创建副本。

如果在运行时修改了material属性,Unity会自动创建该材质的副本(称为Material Instance),这会导致额外的内存占用和DrawCall。如果确实需要运行时修改大量物体的材质属性,建议使用 MaterialPropertyBlock

三、纹理的导入与设置

3.1 获取纹理资源

你可以从以下途径获取纹理:

Unity Asset Store:搜索"Free Textures",有大量免费的纹理包可以直接下载导入。

免费纹理网站

自己制作:使用Photoshop、GIMP、Substance Designer等工具制作自定义纹理。

3.2 导入纹理到Unity

最简单的方式:将图片文件(PNG、JPG、TGA等)直接从文件管理器拖拽到Unity的Project窗口中。

导入后,Unity会自动处理纹理并显示在Project窗口中。选中纹理,在Inspector中可以看到纹理导入设置(Texture Import Settings):

Texture Type(纹理类型):这是最重要的设置,决定了纹理的用途:

  • Default:默认类型,用于3D模型的纹理
  • Normal Map:法线贴图,Unity会进行特殊处理
  • Sprite (2D and UI):用于2D精灵和UI元素
  • Lightmap:光照贴图专用
  • Editor GUI and Legacy GUI:编辑器界面用
  • Cursor:自定义鼠标光标
  • Cookie:灯光Cookie纹理
  • Single Channel:单通道纹理

Texture Shape(纹理形状)

  • 2D:普通2D纹理(最常用)
  • Cube:立方体贴图(天空盒、环境反射用)

sRGB (Color Texture):如果纹理是颜色信息(如Albedo贴图),勾选此选项。如果是数据纹理(如法线贴图、金属度贴图),需要取消勾选以确保数据精度不被颜色空间转换影响。

Alpha Source:Alpha通道的来源。可以是从纹理文件本身读取,或者从灰度图生成。

Generate Mip Maps:是否生成MipMap(多级渐远纹理)。MipMap可以优化远距离的纹理渲染质量并提升性能,但会增加约33%的内存占用。对于3D场景中的纹理,一般建议开启。

Max Size:纹理的最大尺寸限制。例如设为1024,则导入的4K纹理会被缩小到1024×1024。这是控制纹理内存占用的重要设置------在移动平台上,通常把非关键纹理控制在512或1024以下。

Compression:压缩格式。不同平台有不同的最佳压缩格式:

  • PC:DXT(RGB)或BC7(RGBA高质量)
  • iOS:ASTC(最佳选择)
  • Android:ETC2(通用兼容)或ASTC(较新设备)

3.3 纹理的过滤模式与包裹模式

Filter Mode(过滤模式)

  • Point (no filter):最近邻采样。像素风格明显,适合像素风游戏。
  • Bilinear:双线性过滤。在4个相邻像素之间插值,质量适中,性能适中。
  • Trilinear:三线性过滤。在双线性基础上还在MipMap级别之间插值。质量最好但内存带宽开销最大。

Aniso Level(各向异性过滤级别):提高倾斜角度观察纹理时的清晰度。对于地面纹理特别有用。值为0时不使用,值越高效果越好但性能开销越大。

**Wrap Mode(包裹模式)**控制纹理UV坐标超出0-1范围时的行为:

  • Repeat(重复):纹理在超出范围时重复平铺。适合地板、墙壁等需要连续纹理的场合。
  • Clamp(钳制):纹理边缘像素被拉伸以填充超出区域。适合UI元素、独立图标等。
  • Mirror(镜像):纹理以镜像方式重复。
  • Mirror Once:镜像一次后钳制。

四、动手实践

4.1 创建木箱材质

① 创建一个新材质,命名为"M_WoodCrate"。

② 将Albedo颜色设为偏暖的棕色。

③ 将Metallic设为0(木材不是金属)。

④ 将Smoothness设为0.2-0.3(木材比较粗糙)。

⑤ 如果有法线贴图,拖到Normal Map槽中,你会看到木材纹理出现了明显的凹凸感。

⑥ 将材质拖到场景中的一个Cube上------现在它看起来像一个木箱了。

4.2 做一面砖墙

① 创建新材质,命名为"M_BrickWall"。

② Albedo颜色偏红棕色。

③ 由于墙壁通常很大,适当提高Tiling值。将Tiling的X和Y都设为(3,3)或更高,让纹理图案更密集。

④ Metallic设为0,Smoothness设为0.1。

⑤ 将材质应用到墙壁Cube上。

4.3 创建一个金属球

① 创建新材质,命名为"M_PolishedMetal"。

② 将Albedo颜色设为深灰色或暗金色。

③ 将Metallic设为1(完全金属)。

④ 将Smoothness设为0.7-0.9(光滑金属)。

⑤ 将材质应用到球体上。观察------球体现在看起来像一个真正的金属球,能反射周围环境(通过天空盒Cubemap)。

4.4 制作发光物体

① 创建新材质,命名为"M_GlowMagic"。

② Albedo设为白色或浅色。

③ 勾选Emission选项。

④ 将Emission的颜色设为亮色(比如亮蓝色或亮橙色),调节强度。

⑤ 将材质应用到场景中的一个物体上。即使在暗处,这个物体也会发出光芒。

五、代码中动态操作材质

5.1 修改材质属性

csharp 复制代码
using UnityEngine;

public class MaterialController : MonoBehaviour
{
    private Renderer rend;
    
    void Start()
    {
        rend = GetComponent<Renderer>();
    }
    
    // 改变颜色
    public void ChangeColor(Color color)
    {
        rend.material.color = color;
    }
    
    // 修改金属度(使用Shader属性名)
    public void SetMetallic(float value)
    {
        rend.material.SetFloat("_Metallic", Mathf.Clamp01(value));
    }
    
    // 修改光滑度
    public void SetSmoothness(float value)
    {
        rend.material.SetFloat("_Glossiness", Mathf.Clamp01(value));
    }
    
    // 闪烁效果协程
    public System.Collections.IEnumerator Flicker(float duration, float interval)
    {
        float elapsed = 0;
        Color originalColor = rend.material.color;
        
        while (elapsed < duration)
        {
            rend.material.color = originalColor * Random.Range(0.3f, 1f);
            yield return new WaitForSeconds(interval);
            elapsed += interval;
        }
        
        rend.material.color = originalColor;
    }
}

5.2 MaterialPropertyBlock------避免创建材质副本

当需要在运行时修改材质属性时,直接使用 renderer.material 会创建材质实例的副本,增加内存占用和DrawCall。对于批量物体的属性修改,更好的做法是使用 MaterialPropertyBlock

csharp 复制代码
using UnityEngine;

public class EfficientMaterialChange : MonoBehaviour
{
    private Renderer rend;
    private MaterialPropertyBlock propBlock;
    
    void Start()
    {
        rend = GetComponent<Renderer>();
        propBlock = new MaterialPropertyBlock();
    }
    
    public void SetColorWithoutInstance(Color color)
    {
        // 使用MaterialPropertyBlock不会创建材质副本
        rend.GetPropertyBlock(propBlock);
        propBlock.SetColor("_Color", color);
        rend.SetPropertyBlock(propBlock);
    }
}

六、纹理导入常见问题

6.1 纹理显示模糊

降低Max Size可以减小纹理内存占用,但设置过小会导致模糊。确保Max Size不小于纹理在屏幕上实际需要的分辨率。对于UI和近距离观察的纹理,保持较高的Max Size。

6.2 纹理重复太多(或太少)

调整Tiling值。Tiling越大,纹理在物体表面重复越多次。一般大面积的地面和墙壁需要较大的Tiling值(2-5),而小型道具通常用1即可。

6.3 材质在Build后显示异常

检查Shader是否被正确打包。在Graphics Settings中确保使用的Shader被包含在"Always Included Shaders"列表中,或者在资源中有引用。

七、本篇总结

✅ 本文核心知识点回顾:

  • 材质(Material)定义物体表面外观------颜色、金属度、光滑度、透明度等
  • 纹理(Texture)是二维图片,为材质提供精细的视觉细节
  • Albedo、Normal Map、Metallic、Smoothness是PBR材质的核心属性
  • 纹理导入设置中的Max Size和Compression直接影响运行时的内存占用
  • renderer.material会创建材质实例副本,批量修改应使用sharedMaterial或MaterialPropertyBlock
  • Tiling控制纹理的平铺密度,Offset控制纹理的位置偏移

📝 下一篇文章将学习Camera相机组件------透视投影与正交投影的区别,以及如何通过控制相机来决定玩家看到什么。

动手任务

① 创建至少5个不同外观的材质(木材、金属、石头、玻璃、发光)

② 尝试下载免费纹理贴图并导入到材质中使用

③ 调整Tiling和Offset,观察纹理变化

④ 写一个简单脚本,在运行时动态改变物体的颜色


关于作者:拥有多年Unity开发经验的游戏开发者,专注Unity系统化教学与最佳实践分享。欢迎在评论区交流讨论!

相关推荐
ellis19701 小时前
u3d插件xLua[二]例2:U3DScripting,例3:UIEvent分析
unity·lua
派葛穆11 小时前
Unity-UI 输入框功能
ui·unity·游戏引擎
玖玥拾11 小时前
Unity3D RPG 入门项目(一)开场动画/人物移动/摄像机跟随场景切换
unity·游戏引擎
2401_8949155313 小时前
GEO 搜索优化完整源码从零部署:环境配置、集群搭建全流程
开发语言·python·tcp/ip·算法·unity
WarPigs14 小时前
PC端加载安卓AB包资源显示紫色的问题
unity
scott.cgi17 小时前
Unity使用AndroidX获取,导航栏与虚拟键盘的高度
unity·androidx·keyboard·导航栏高度·虚拟键盘高度·判断键盘关闭·获取虚拟键盘高度
丁小未18 小时前
Unity车机地图Tile流式渲染系统高性能架构方案
unity·架构·ecs·dots·车机系统·车机系统架构图
LONGZETECH1 天前
工业实训仿真设计实践:电机拆装软件的 DAG 流程建模、工具精度分级与数据体系搭建
大数据·算法·unity·架构·汽车
音乐宝贝家1 天前
吉他十大品牌技术分档(2026):参数视角下的选购地图
新媒体运营·媒体·材质·用户运营·内容运营