前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Unity3D学习笔记2——绘制一个带纹理的面

Unity3D学习笔记2——绘制一个带纹理的面

作者头像
charlee44
发布2021-07-13 11:30:38
9720
发布2021-07-13 11:30:38
举报
文章被收录于专栏:代码编写世界代码编写世界

目录

    1. 概述
    1. 详论
    • 2.1. 网格(Mesh)
      • 2.1.1. 顶点
      • 2.1.2. 顶点索引
    • 2.2. 材质(Material)
      • 2.2.1. 创建材质
      • 2.2.2. 使用材质
    • 2.3. 光照
    1. 代码

1. 概述

上一篇文章《Unity3D学习笔记1——绘制一个三角形》中介绍了Unity3D的HelloWorld——绘制一个简单的三角形。不过这个三角形太简单了,连材质都没有。那么这里就将三角形扩展为一个矩形的面,并且为这个面贴上纹理。

2. 详论

2.1. 网格(Mesh)

前面说到网格是渲染物体的骨架,因此还是先要把渲染物体的架子搭好。改进一下上一篇文章中的创建Mesh的代码:

代码语言:javascript
复制
Mesh mesh = new Mesh();
mesh.name = name;

Vector3[] vertices = new Vector3[4]
{
    new Vector3(-5, -5, 0),
    new Vector3(-5, 5, 0),
    new Vector3(5, -5, 0),
    new Vector3(5, 5, 0),
};
mesh.vertices = vertices;

Vector2[] uv = new Vector2[4]
{
    new Vector2(0, 0),
    new Vector2(0, 1),
    new Vector2(1, 0),
    new Vector2(1, 1),
};
mesh.uv = uv;

Vector3[] normals = new Vector3[4]
{
    new Vector3(0, 0, -1),
    new Vector3(0, 0, -1),
    new Vector3(0, 0, -1),
    new Vector3(0, 0, -1),
};
mesh.normals = normals;
//mesh.RecalculateNormals();

int[] triangles = new int[6] { 0, 1, 2, 1, 3, 2 };
mesh.triangles = triangles;

GameObject newGameObject = new GameObject(name);
MeshFilter mf = newGameObject.AddComponent<MeshFilter>();
mf.sharedMesh = mesh;

2.1.1. 顶点

因为我们要创建一个矩形的面,所以需要创建四个顶点。仍然是像之前创建三角面的顶点一样,赋予顶点的空间位置属性xyz坐标。同时,我们还给Mesh赋予了4个uv坐标,4个法向量normal。uv坐标是用来计算纹理坐标的,也就是当物体贴上纹理之后的纹理坐标位置;法向量是用来参与光照计算的,如果缺少法向量,很多材质的效果不正确。可以通过mesh.RecalculateNormals()让Unity3D自己计算法向量。

位置(position/vertice)、纹理坐标(uv/texCoord)、法向量(normal)是经常用到了三个顶点属性,但是顶点属性也不仅仅只有三个,甚至可以根据需要自定义。

2.1.2. 顶点索引

一个矩形面确定了四个顶点,但是需要划分成两个三角形,每个三角形引用3个顶点索引,也就是6个顶点索引。当然我们也可以使用6个顶点,按照自然顺序来确定顶点索引。但是这样一来,就浪费了空间存储。这也是使用顶点索引的好处,可以节省空间,毕竟Mesh中的很多顶点是共用的。

2.2. 材质(Material)

接下来我们在Unity3D编辑器中创建一个材质,并且在C#脚本中将这个材质给到我们创建的面上。

2.2.1. 创建材质

材质和纹理(图片)在Unity3D中被认为是一种资源,要加载他们需要特定的办法。一种比较简单的办法是使用Resources.Load。

在Assets目录下创建一个名为Resources的文件夹,只有使用这个目录下的资源,使用Resources.Load才能找到。在Resources文件夹下新建一个材质,并把想使用的纹理图片文件移到这个文件夹下:

点击新建的材质,在Inspector视图中,将纹理图片挂载到这个材质上:

Unity3D新建的材质默认为标准,是一种PBR材质,由多种贴图混合而成。我们这里暂时只设置Albedo贴图,也就是基本颜色贴图。实际使用时,右边的颜色拾取也能影响到贴图效果,在有贴图时,可以将其拾取成白色。

2.2.2. 使用材质

在编辑器中把材质创建好之后,在脚本中就可以直接使用创建好的材质了:

代码语言:javascript
复制
MeshRenderer meshRenderer = newGameObject.AddComponent<MeshRenderer>();                
Material material = Resources.Load<Material>("MaterialDemo");   
meshRenderer.material = material;

2.3. 光照

点击Play,会发现虽然显示了一个带纹理的面,但是面的颜色显得很暗:

这是因为光照的位置不对,材质缺少对光照的影响。那么我们调整默认光照Directional Light的Transform,将其调整到和摄像机的位置一致:

这个时候的光照正好对准了面的正中间:

最终Game视图中的面也按照正常亮度显示了:

3. 代码

全部的C#脚本代码如下:

代码语言:javascript
复制
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 = GreateQuad();
        triangleGameObject.transform.parent = main.transform;
    }

    GameObject GreateQuad()
    {
        string name = "quad";

        Mesh mesh = new Mesh();
        mesh.name = name;

        Vector3[] vertices = new Vector3[4]
        {
            new Vector3(-5, -5, 0),
            new Vector3(-5, 5, 0),
            new Vector3(5, -5, 0),
            new Vector3(5, 5, 0),
        };
        mesh.vertices = vertices;

        Vector2[] uv = new Vector2[4]
        {
            new Vector2(0, 0),
            new Vector2(0, 1),
            new Vector2(1, 0),
            new Vector2(1, 1),
        };
        mesh.uv = uv;

        Vector3[] normals = new Vector3[4]
        {
            new Vector3(0, 0, -1),
            new Vector3(0, 0, -1),
            new Vector3(0, 0, -1),
            new Vector3(0, 0, -1),
        };
        mesh.normals = normals;
        //mesh.RecalculateNormals();

        int[] triangles = new int[6] { 0, 1, 2, 1, 3, 2 };
        mesh.triangles = triangles;
               
        GameObject newGameObject = new GameObject(name);
        MeshFilter mf = newGameObject.AddComponent<MeshFilter>();
        mf.sharedMesh = mesh;

        MeshRenderer meshRenderer = newGameObject.AddComponent<MeshRenderer>();                
        Material material = Resources.Load<Material>("MaterialDemo");   
        meshRenderer.material = material;

        return newGameObject;
    }

    // Update is called once per frame
    void Update()
    {
        
    }
}
本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2021-07-06 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 1. 概述
  • 2. 详论
    • 2.1. 网格(Mesh)
      • 2.1.1. 顶点
      • 2.1.2. 顶点索引
    • 2.2. 材质(Material)
      • 2.2.1. 创建材质
      • 2.2.2. 使用材质
    • 2.3. 光照
    • 3. 代码
    相关产品与服务
    图像处理
    图像处理基于腾讯云深度学习等人工智能技术,提供综合性的图像优化处理服务,包括图像质量评估、图像清晰度增强、图像智能裁剪等。
    领券
    问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档