汽车3D展示01

一、新建Unity项目

1、新建工程

1)、打开Unity Hub。新建一个项目工程,注意我用的是Unity2020.3.48版本的。

注意这几步,点击新建项目,等待数秒,一个Unity的工程就新建好了。

2、导入资源

1)、我们需要的模型资源已经打包好了,用的时候直接导入到Unity就行。模型资源我会放在文章末尾的资源中,有需要的可以自己下载!

3、工程项目的开发

1)、我们来看一下上一步中导入的资源,在项目的位置和资源文件内容。

2)、在Assets文件夹下新建一个Scenes文件夹。在Scenes文件夹下新建一个场景。打开场景,在场景中新建一个Scene文件夹。将Resource文件夹下的Car模型放在Scene文件夹下。我们会看到这样的场景。

3)、我们需要新建一个地面Ground。

我们可以看到下面这个Ground背景,如下图所示:

4)、接下来我们需要创建很多的网格线。如下图

4、网格数据的创建

1)、新建RectMesh.cs文件,用于创建Rect网格数据。

2)、新建一个PrimitiveBase.cs作为基类。PrimitiveBase.cs的具体代码如下:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

[RequireComponent(typeof(MeshFilter), typeof(MeshRenderer))]
[ExecuteInEditMode]

public class PrimitiveBase : MonoBehaviour
{

    public Vector3 offset;
    protected MeshFilter meshFilter;
    public Transform cacheTransform;

    protected Vector3[] vertices;
    protected int[] triangles;
    protected Vector2[] uvs;

    private void Awake()
    {
        Init();
        InitMesh();
    }
    public void Init()
    {
        cacheTransform = this.transform;
        meshFilter = GetComponent<MeshFilter>();
        meshFilter.sharedMesh = new Mesh();
    }

    protected virtual void InitMesh()
    {

    }
    protected virtual void UpdateShape()
    {

    }

    protected void UpdateMesh()
    {
        if(meshFilter.sharedMesh == null)
        {
            meshFilter.sharedMesh = new Mesh();
        }
        meshFilter.sharedMesh.vertices = vertices;
        meshFilter.sharedMesh.triangles = triangles;
        meshFilter.sharedMesh.uv = uvs;
    }

    private void OnValidate()
    {
        InitMesh();
    }
}

代码的具体含义,需要自己去研究了,这里涉及到OpenGL的相关知识,有需要的朋友,可以去百度搜索相关的资料。

3)、RectMesh.cs文件的内容:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using DG.Tweening;

public class RectMesh : PrimitiveBase
{
    public float m_Width;
    public float m_Length;
    public enum PivotAlign
    {
        Left,
        Center,
        Right
    }
    public PivotAlign widthAlign = PivotAlign.Center;
    public PivotAlign lengthAlign = PivotAlign.Center;

    protected override void InitMesh()
    {
        if (cacheTransform == null || meshFilter == null)
        {
            Init();
        }
        triangles = new int[] { 0, 2, 3, 0, 3, 1 };
        uvs = new Vector2[4];
        uvs[0].x = 0;
        uvs[0].y = 0;

        uvs[1].x = 1;
        uvs[1].y = 0;

        uvs[2].x = 0;
        uvs[2].y = 1;

        uvs[3].x = 1;
        uvs[3].y = 1;

        UpdateShape();
    }

    protected override void UpdateShape()
    {
        Vector3 localPos = offset;
        float w2 = m_Width * 0.5f;
        float l2 = m_Length * 0.5f;

        vertices = new Vector3[4];
        float x0, z0, x1, z1, x2, z2, x3, z3;
        x0 = z0 = x1 = z1 = x2 = z2 = x3 = z3 = 0;
        switch(widthAlign)
        {
            case PivotAlign.Left:
                x0 = 0f;
                x1 = m_Width;
                x2 = 0;
                x3 = m_Width;
                break;
            case PivotAlign.Center:
                x0 = -w2;
                x1 = w2;
                x2 = -w2;
                x3 = w2;
                break;
            case PivotAlign.Right:
                x0 = -m_Width;
                x1 = 0f;
                x2 = -m_Width;
                x3 = 0f;
                break;
        }
        switch(lengthAlign)
        {
            case PivotAlign.Left:
                z0 = 0;
                z1 = 0;
                z2 = m_Length;
                z3 = m_Length;
                break;
            case PivotAlign.Center:
                z0 = -l2;
                z1 = -l2;
                z2 = l2;
                z3 = l2;
                break;
            case PivotAlign.Right:
                z0 = -m_Length;
                z1 = -m_Length;
                z2 = 0;
                z3 = 0f;
                break;
        }
        vertices[0].x = localPos.x + x0;
        vertices[0].y = localPos.y;
        vertices[0].z = localPos.z + z0;

        vertices[1].x = localPos.x + x1;
        vertices[1].y = localPos.y;
        vertices[1].z = localPos.z + z1;

        vertices[2].x = localPos.x + x2;
        vertices[2].y = localPos.y;
        vertices[2].z = localPos.z + z2;

        vertices[3].x = localPos.x + x3;
        vertices[3].y = localPos.y;
        vertices[3].z = localPos.z + z3;
        UpdateMesh();
    }

}

4)、新建RingMesh.cs文件,用于创建圆形网格数据。具体代码如下:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using DG.Tweening;

public class RingMesh : PrimitiveBase
{
    public int segment = 1;
    public float ringWidth;
    public float _ringRadius;
    public float _angleBegin;
    public float _angleEnd;

    protected override void InitMesh()
    {
        if(cacheTransform == null || meshFilter == null)
        {
            Init();
        }
        segment = segment > 0 ? segment : 1;
        triangles = new int[segment*2*3];
        for(int i = 0;i < segment;i++)
        {
            int k = i * 6;
            int j = i * 2;
            triangles[k] = j;
            triangles[k + 1] = j + 2;
            triangles[k + 2] = j + 3;
            triangles[k + 3] = j;
            triangles[k + 4] = j + 3;
            triangles[k + 5] = j + 1;
        }
        int vertexCount = segment * 2 + 2;
        uvs = new Vector2[vertexCount];
        float singleUV = 1f / segment;
        float uvY = 0f;
        for(int i =0;i < vertexCount;i+=2)
        {
            uvs[i].x = 0f;
            uvs[i + 1].x= 1f;
            uvs[i].y = uvY;
            uvY += singleUV;
        }
        UpdateShape();
    }

    protected override void UpdateShape()
    {
        int vertexCount = segment * 2 + 2;
        vertices = new Vector3[vertexCount];

        float angle = _angleBegin * Mathf.Deg2Rad;
        float wHalf = ringWidth * 0.5f;
        float sin = Mathf.Sin(angle);
        float cos = Mathf.Cos(angle);

        float minRingRadius = _ringRadius - wHalf;
        float maxRingRadius = _ringRadius + wHalf;
        Vector3 localPos = offset;

        float x = cos * minRingRadius + localPos.x;
        float y = localPos.y;
        float z = sin * minRingRadius + localPos.z;

        vertices[0].x = x;
        vertices[0].y = y;
        vertices[0].z = z;

        x = cos * maxRingRadius + localPos.x;
        y = sin * maxRingRadius + localPos.z;

        vertices[1].x = x;
        vertices[1].y = y;
        vertices[1].z = z;

        float singleAngle = (_angleEnd - _angleBegin)/segment*Mathf.Deg2Rad;
        for(int i =0;i < segment;i++)
        {
            angle += singleAngle;
            sin = Mathf.Sin(angle);
            cos = Mathf.Cos(angle);
            x = cos * minRingRadius + localPos.x;
            y = localPos.y;
            z = sin * minRingRadius + localPos.z;
            vertices[i * 2 + 2] = new Vector3(x,y,z);

            x = cos * maxRingRadius + localPos.x;
            y = localPos.y;
            z = sin * maxRingRadius + localPos.z;
            vertices[i * 2 + 3] = new Vector3(x,y,z);
        }
        UpdateMesh();
    }
}

至此,我们自己创建的Mesh网格数据已经写好了,接下来我们去Unity工程中,创建相应的网格。

二、Rect和Ring网格数据的创建

1、Rect和Ring网格数据的创建

1)、新建空的GameObject。具体的看下图:

找到一一对应的网格数据脚本,设置一下Materials。就可以了。具体的参数和网格数据我已经写好了。资源放在了最后面。

2)、下图是具体的效果,可以看一下。

2、直线的动画和曲线的动画

1)、这里我们需要一个插件,用于制作动画的插件,比较方便。

就是这个插件,我已经放工程文件里面了,自己取。

2)、先在RectMesh.cs文件中添加一段动画。

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using DG.Tweening;

public class RectMesh : PrimitiveBase
{
    public float m_Width;
    public float m_Length;
    public float length
    {
        get { return m_Length; }
        set { m_Length = value; }
    }
    public enum PivotAlign
    {
        Left,
        Center,
        Right
    }
    public PivotAlign widthAlign = PivotAlign.Center;
    public PivotAlign lengthAlign = PivotAlign.Center;

    protected override void InitMesh()
    {
        if (cacheTransform == null || meshFilter == null)
        {
            Init();
        }
        triangles = new int[] { 0, 2, 3, 0, 3, 1 };
        uvs = new Vector2[4];
        uvs[0].x = 0;
        uvs[0].y = 0;

        uvs[1].x = 1;
        uvs[1].y = 0;

        uvs[2].x = 0;
        uvs[2].y = 1;

        uvs[3].x = 1;
        uvs[3].y = 1;

        UpdateShape();
    }

    protected override void UpdateShape()
    {
        Vector3 localPos = offset;
        float w2 = m_Width * 0.5f;
        float l2 = m_Length * 0.5f;

        vertices = new Vector3[4];
        float x0, z0, x1, z1, x2, z2, x3, z3;
        x0 = z0 = x1 = z1 = x2 = z2 = x3 = z3 = 0;
        switch(widthAlign)
        {
            case PivotAlign.Left:
                x0 = 0f;
                x1 = m_Width;
                x2 = 0;
                x3 = m_Width;
                break;
            case PivotAlign.Center:
                x0 = -w2;
                x1 = w2;
                x2 = -w2;
                x3 = w2;
                break;
            case PivotAlign.Right:
                x0 = -m_Width;
                x1 = 0f;
                x2 = -m_Width;
                x3 = 0f;
                break;
        }
        switch(lengthAlign)
        {
            case PivotAlign.Left:
                z0 = 0;
                z1 = 0;
                z2 = m_Length;
                z3 = m_Length;
                break;
            case PivotAlign.Center:
                z0 = -l2;
                z1 = -l2;
                z2 = l2;
                z3 = l2;
                break;
            case PivotAlign.Right:
                z0 = -m_Length;
                z1 = -m_Length;
                z2 = 0;
                z3 = 0f;
                break;
        }
        vertices[0].x = localPos.x + x0;
        vertices[0].y = localPos.y;
        vertices[0].z = localPos.z + z0;

        vertices[1].x = localPos.x + x1;
        vertices[1].y = localPos.y;
        vertices[1].z = localPos.z + z1;

        vertices[2].x = localPos.x + x2;
        vertices[2].y = localPos.y;
        vertices[2].z = localPos.z + z2;

        vertices[3].x = localPos.x + x3;
        vertices[3].y = localPos.y;
        vertices[3].z = localPos.z + z3;
        UpdateMesh();
    }

    public Tweener DoLength(float endValue,float duration,float delay)
    {
        return DOTween.To(() => m_Length, x => length = x, endValue, duration).SetDelay(delay);
    }
}

2)、创建一个MeshAnimBase.cs文件,动画的基类。

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class MeshAnimBase : MonoBehaviour
{
    public float minDuration = 0.3f;//动画时间
    public float maxDuration = 0.7f;
    public float minDelay = 0.3f;//动画延时
    public float maxDelay = 0.8f;
    public bool animAtStart = false; //动画是否播放标志

    public virtual void StartAnimation(bool forward)
    {

    }

}

3)、创建一个RectMeshAnim.cs文件,矩形动画组件

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class RectMeshAnim : MeshAnimBase
{
    private RectMesh[] rectMeshes;
    private float[] lengths;
    private int count;

    private void Start()
    {
        rectMeshes = gameObject.GetComponentsInChildren<RectMesh>();
        count = rectMeshes.Length;
        lengths = new float[count];
        for(int i =0;i < count;i++)
        {
            lengths[i] = rectMeshes[i].length;
        }
    }

    public override void StartAnimation(bool forward)
    {
        if(forward)
        {
            PlayForwardAnimation();
        }
        else
        {
            PlayBackwardAnimation();
        }
    }
    private void SetBeginState()
    {
        for(int i =0;i < count;i++)
        {
            rectMeshes[i].length = 0;
        }
    }

    private void PlayForwardAnimation()
    {
        float duration;
        float delay;
        for(int i =0;i < count;i++)
        {
            duration = Random.Range(minDuration,maxDuration);
            delay = Random.Range(minDelay,maxDelay);
            rectMeshes[i].DoLength(lengths[i],duration,delay);
        }
    }

    private void PlayBackwardAnimation()
    {
        float duration;
        float delay;
        for (int i = 0; i < count; i++)
        {
            duration = Random.Range(minDuration, maxDuration);
            delay = Random.Range(minDelay, maxDelay);
            rectMeshes[i].DoLength(0, duration, delay);
        }
    }
}

4)、先在RingMesh.cs文件中添加一段动画。

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using DG.Tweening;

public class RingMesh : PrimitiveBase
{
    public int segment = 1;
    public float ringWidth;
    public float _ringRadius;
    public float _angleBegin;
    public float _angleEnd;

    public float AngleBegin
    {
        get { return _angleBegin; }
        set { _angleBegin = value;UpdateShape(); }
    }
    public float AngleEnd
    {
        get { return _angleEnd; }
        set { _angleEnd = value;UpdateShape(); }
    }
    protected override void InitMesh()
    {
        if(cacheTransform == null || meshFilter == null)
        {
            Init();
        }
        segment = segment > 0 ? segment : 1;
        triangles = new int[segment*2*3];
        for(int i = 0;i < segment;i++)
        {
            int k = i * 6;
            int j = i * 2;
            triangles[k] = j;
            triangles[k + 1] = j + 2;
            triangles[k + 2] = j + 3;
            triangles[k + 3] = j;
            triangles[k + 4] = j + 3;
            triangles[k + 5] = j + 1;
        }
        int vertexCount = segment * 2 + 2;
        uvs = new Vector2[vertexCount];
        float singleUV = 1f / segment;
        float uvY = 0f;
        for(int i =0;i < vertexCount;i+=2)
        {
            uvs[i].x = 0f;
            uvs[i + 1].x= 1f;
            uvs[i].y = uvY;
            uvY += singleUV;
        }
        UpdateShape();
    }

    protected override void UpdateShape()
    {
        int vertexCount = segment * 2 + 2;
        vertices = new Vector3[vertexCount];

        float angle = _angleBegin * Mathf.Deg2Rad;
        float wHalf = ringWidth * 0.5f;
        float sin = Mathf.Sin(angle);
        float cos = Mathf.Cos(angle);

        float minRingRadius = _ringRadius - wHalf;
        float maxRingRadius = _ringRadius + wHalf;
        Vector3 localPos = offset;

        float x = cos * minRingRadius + localPos.x;
        float y = localPos.y;
        float z = sin * minRingRadius + localPos.z;

        vertices[0].x = x;
        vertices[0].y = y;
        vertices[0].z = z;

        x = cos * maxRingRadius + localPos.x;
        y = sin * maxRingRadius + localPos.z;

        vertices[1].x = x;
        vertices[1].y = y;
        vertices[1].z = z;

        float singleAngle = (_angleEnd - _angleBegin)/segment*Mathf.Deg2Rad;
        for(int i =0;i < segment;i++)
        {
            angle += singleAngle;
            sin = Mathf.Sin(angle);
            cos = Mathf.Cos(angle);
            x = cos * minRingRadius + localPos.x;
            y = localPos.y;
            z = sin * minRingRadius + localPos.z;
            vertices[i * 2 + 2] = new Vector3(x,y,z);

            x = cos * maxRingRadius + localPos.x;
            y = localPos.y;
            z = sin * maxRingRadius + localPos.z;
            vertices[i * 2 + 3] = new Vector3(x,y,z);
        }
        UpdateMesh();
    }

    public Tweener DoEndAngle(float endValue,float duration,float delay)
    {
        return DOTween.To(() => AngleEnd, x => AngleEnd = x, endValue, duration).SetDelay(delay);
    }
}

5)、创建一个RingMeshAnim.cs动画文件

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class RingMeshAnim : MeshAnimBase
{
    private RingMesh[] ringMeshes;
    private float[] endAngles;

    private int count;

    private void Start()
    {
        ringMeshes = gameObject.GetComponentsInChildren<RingMesh>();
        count = ringMeshes.Length;
        endAngles = new float[count];
        for(int i =0;i < count;i++)
        {
            endAngles[i] = ringMeshes[i].AngleEnd;
        }
        SetBeginState();
    }

    public override void StartAnimation(bool forward)
    {
        if(forward)
        {
            PlayForwardAnimation();
        }
        else
        {
            PlayBackwardAnimation();
        }
    }
    private void SetBeginState()
    {
        for(int i =0;i < count;i++)
        {
            ringMeshes[i].AngleBegin = 0f;
            ringMeshes[i].AngleEnd = 0f;
        }
    }

    private void PlayForwardAnimation()
    {
        float duration;
        float delay;
        for(int i =0;i < count;i++)
        {
            duration = Random.Range(minDuration,maxDuration);
            delay = Random.Range(minDelay,maxDelay);
            ringMeshes[i].DoEndAngle(endAngles[i],duration,delay);
        }
    }
    private void PlayBackwardAnimation()
    {
        float duration;
        float delay;
        for (int i = 0; i < count; i++)
        {
            duration = Random.Range(minDuration, maxDuration);
            delay = Random.Range(minDelay, maxDelay);
            ringMeshes[i].DoEndAngle(0, duration, delay);
        }
    }
}

  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

weixin_41392061

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值