zoukankan      html  css  js  c++  java
  • Unity3D学习笔记2——绘制一个带纹理的面

    1. 概述

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

    2. 详论

    2.1. 网格(Mesh)

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

    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文件夹下新建一个材质,并把想使用的纹理图片文件移到这个文件夹下:
    imglink1

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

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

    2.2.2. 使用材质

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

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

    2.3. 光照

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

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

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

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

    3. 代码

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

    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()
        {
            
        }
    }
    
  • 相关阅读:
    分享一个 @user 前端插件
    .net 的一个分词系统(jieba中文分词的.NET版本:jieba.NET)
    InvokeMember 使用(转http://blog.csdn.net/gooer/article/details/2927113)
    C#反射机制(转自Binfire博客)
    MVC中使用AuthorizeAttribute做身份验证操作
    javascript日期操作详解
    精通 JS正则表达式
    JavaScript 正则表达式
    Js获取当前日期时间及其它操作
    Django 模板中 变量 过滤器的使用方法
  • 原文地址:https://www.cnblogs.com/charlee44/p/14976513.html
Copyright © 2011-2022 走看看