# u3d&&blender&&unity3d

# 发布为webgl时候报错

#### 报错内容

```text
Unable to parse Build/RobotTest.framework.js.gz! This can happen if build compression 
was enabled but web server hosting the content was misconfigured to not serve the file 
with HTTP Response Header "Content-Encoding: gzip" present. Check browser 
Console and Devtools Network tab to debug.

```

#### 修改设置

- Edit -&gt; Project Settings -&gt; Player -&gt; WebGL settings -&gt; Publishing Settings -&gt; Decompression Fallback
- 勾选 **Decompression Fallback**

[![](https://iovhm.com/book/uploads/images/gallery/2024-09/scaled-1680-/rvFP4OA8bQMnNTt8-image-1725611210999.png)](https://iovhm.com/book/uploads/images/gallery/2024-09/rvFP4OA8bQMnNTt8-image-1725611210999.png)

# 项目模板

- #### Unity3D URP管线（Universal Render Pipeline）【推荐】

Unity3D URP管线是Unity在2019年推出的一种轻量级渲染管线。它是对Unity内置管线的改进和优化，主要针对移动设备和低端硬件的性能优化。Unity3D URP管线的主要特点如下：

轻量级：Unity3D URP管线相较于Unity内置管线，更加轻量级，可以在移动设备和低端硬件上运行更流畅。

可高度自定义：Unity3D URP管线提供了高度自定义的渲染流程，开发者可以根据需求自由定制渲染效果。

渲染质量较低：由于轻量级的特性，Unity3D URP管线在渲染质量上相对较低，无法实现Unity内置管线中的一些高级渲染效果。

- #### Unity内置管线（Built-in Render Pipeline）

Unity内置管线是Unity3D最早推出的渲染管线，也是最常用的一种。它提供了一套完整的渲染功能，适用于大多数的游戏开发需求。Unity内置管线的主要特点如下：

渲染质量较高：Unity内置管线在图形渲染方面有着较高的质量，可以实现较为真实的光照和阴影效果。

功能丰富：Unity内置管线提供了多种渲染功能，如透明效果、反射效果、抗锯齿等，可以满足不同游戏的需求。

灵活性较低：Unity内置管线的渲染流程是固定的，开发者无法自定义渲染流程。

# 单位与参考

默认情况下，一个**cube**的长宽高为1x1x1,可以视做为现实物体的1米，既一个人为2个单位，以此类推来确定物体的高度，受重力影响，默认情况下，我们可以增加地形或一个plan，可以理解为平面和地板，可以阻止物体下落到的游戏之外。

而大多数物体（至少内置的几个基础组件中）的position的中心点在对象最中间，因此，当物体的position的Y设置为0时，物体会穿透到地板地板之外，此时需要调整物体Y以适应物体在相对位置上

由于u3d的脚本需要绑定到一个GameObject，通常会放置一个胶囊**Cylinder**，胶囊的默认高度为2，同样道理，需要将胶囊的Y提升到对应的高度以适应屏幕

#### 组织项目结构

默认情况下，u3d只生成了scene文件夹，并生成了一个默认场景，资源文件一股脑的全部丢在这个文件夹，资源管理，复制类的重用非常不方便。

可以按一个独立模块来管理资源

例如:

```
|Assets
|--welcome
|----scripts
|----assets
|------video
|------material
|--skybox
|----FS003
|--ui
|--level-A
|----assets
|------video
|------material
|----scripts
  

```

# 使用资源和插件

#### VSCODE扩展

- Unity：[https://marketplace.visualstudio.com/items?itemName=VisualStudioToolsForUnity.vstuc](https://marketplace.visualstudio.com/items?itemName=VisualStudioToolsForUnity.vstuc)
- C# Dev Kit：[https://marketplace.visualstudio.com/items?itemName=ms-dotnettools.csdevkit](https://marketplace.visualstudio.com/items?itemName=ms-dotnettools.csdevkit)
- C#:[https://marketplace.visualstudio.com/items?itemName=ms-dotnettools.csharp](https://marketplace.visualstudio.com/items?itemName=ms-dotnettools.csharp)
- .NET Install Tool：[https://marketplace.visualstudio.com/items?itemName=ms-dotnettools.vscode-dotnet-runtime](https://marketplace.visualstudio.com/items?itemName=ms-dotnettools.vscode-dotnet-runtime)

#### 资源网站

直接打开：[https://assetstore.unity.com/](https://assetstore.unity.com/) 或者在unity3d软件点击 **window &gt; asset store**

#### 常用资源

- UGUI
    
    
    - TextMeshPro，内置组件，中文字体支持
    - Input System，内置组件，输入与交互支持
    - Cinemachine，内置组件，摄像机增强
    - Violet Themed UI：[https://assetstore.unity.com/packages/2d/gui/violet-themed-ui-235559](https://assetstore.unity.com/packages/2d/gui/violet-themed-ui-235559)
- 辅助工具

Odin：编辑器增强，为cs脚本增加attribe后，在编辑器更好的使用（淘宝有售），[https://assetstore.unity.com/packages/tools/utilities/odin-inspector-and-serializer-89041](https://assetstore.unity.com/packages/tools/utilities/odin-inspector-and-serializer-89041)

角色控制器（暂时不知道怎么用的）： [https://assetstore.unity.com/packages/3d/characters/modular-first-person-controller-189884](https://assetstore.unity.com/packages/3d/characters/modular-first-person-controller-189884)

- 2D图表插件

XCharts：[https://github.com/XCharts-Team/XCharts](https://github.com/XCharts-Team/XCharts)

- 地形

[https://assetstore.unity.com/packages/3d/environments/landscapes/terrain-sample-asset-pack-145808](https://assetstore.unity.com/packages/3d/environments/landscapes/terrain-sample-asset-pack-145808)[https://assetstore.unity.com/packages/p/grass-flowers-pack-free-138810](https://assetstore.unity.com/packages/p/grass-flowers-pack-free-138810)

- 天空

Fantasy Skybox FREE：[https://assetstore.unity.com/packages/2d/textures-materials/sky/fantasy-skybox-free-18353](https://assetstore.unity.com/packages/2d/textures-materials/sky/fantasy-skybox-free-18353)

- 草地
- 水

[https://assetstore.unity.com/packages/2d/textures-materials/water/simple-water-shader-urp-191449](https://assetstore.unity.com/packages/2d/textures-materials/water/simple-water-shader-urp-191449)

- 树

[https://assetstore.unity.com/packages/3d/vegetation/trees/mobile-tree-package-18866](https://assetstore.unity.com/packages/3d/vegetation/trees/mobile-tree-package-18866)[https://assetstore.unity.com/packages/3d/vegetation/trees/realistic-tree-9-rainbow-tree-54622](https://assetstore.unity.com/packages/3d/vegetation/trees/realistic-tree-9-rainbow-tree-54622)

# 摄像机&&主灯光&&基础场景

在大多数45度伪3D场景下的摄像机与灯光的最佳参数为：

[![](https://iovhm.com/book/uploads/images/gallery/2024-09/scaled-1680-/NS02r31khnevCTzj-image-1725775817919.png)](https://iovhm.com/book/uploads/images/gallery/2024-09/NS02r31khnevCTzj-image-1725775817919.png)

#### 默认视角

[![](https://iovhm.com/book/uploads/images/gallery/2025-01/scaled-1680-/GHcegH9tNuUD7SkA-image-1737045011222.png)](https://iovhm.com/book/uploads/images/gallery/2025-01/GHcegH9tNuUD7SkA-image-1737045011222.png)

#### 摄像机

摄像机的**Z轴**指向物体

- 位置
    
    
    - x:10
    - y:10
    - z:-10
- 角度
    
    
    - x:35-40之间
    - y:-45
    - z:0
- 视口大小
    
    
    - field of view:28-35,既35毫米焦段镜头

#### 主灯光

光照角度的**X轴**影响被照射物体

- 位置
    
    
    - x:10
    - y:10
    - z:10
- 角度
    
    
    - x:135
    - y:45
    - z:0
- color:光照颜色 FFF4D6
- intensity:光照强度,数值越大，场景越亮（可能过爆）

此时，物体的阴影在物体左侧，如果按平面上北下南，左西右东，应该属于上午

如果要物体的阴影在物体右侧，则设置为

- 位置 
    - x:-10
    - y:10
    - z:-10
- 角度 
    - x:45
    - y:45
    - z:0

[![](https://iovhm.com/book/uploads/images/gallery/2024-09/scaled-1680-/WU7sGpY1QscwxD5a-image-1725777164184.png)](https://iovhm.com/book/uploads/images/gallery/2024-09/WU7sGpY1QscwxD5a-image-1725777164184.png)

- 摄像机size 在正交摄像机情况下，每1个单位代表100px，你如你有一张532px的地图，要想刚好全部显示，则size为5.33，而宽度则取决于项目的发布宽度

# 创建天空

#### 创建材质

- 从菜单栏中，单击 **Assets &gt; Create &gt; Material**
- 在 Shader 下拉选单中，单击 Skybox，然后单击要使用的天空盒着色器
- [![](https://iovhm.com/book/uploads/images/gallery/2024-09/scaled-1680-/kOoIvOBfhlLBPxEL-image-1725708688808.png)](https://iovhm.com/book/uploads/images/gallery/2024-09/kOoIvOBfhlLBPxEL-image-1725708688808.png)
- 为天空设置贴图
    
    [![](https://iovhm.com/book/uploads/images/gallery/2024-09/scaled-1680-/pDRkbN8JNhpDR1fp-image-1725708741530.png)](https://iovhm.com/book/uploads/images/gallery/2024-09/pDRkbN8JNhpDR1fp-image-1725708741530.png)
- 将材质拖入场景
- 删除和切换天空材质 从菜单栏中，单击 **Window &gt; Rendering**点击 **Environment**选项卡
    
    [![](https://iovhm.com/book/uploads/images/gallery/2024-09/scaled-1680-/OyJG9X6qMssNxGvn-image-1725708898799.png)](https://iovhm.com/book/uploads/images/gallery/2024-09/OyJG9X6qMssNxGvn-image-1725708898799.png)

#### 免费材质下载链接

[https://assetstore.unity.com/packages/2d/textures-materials/sky/fantasy-skybox-free-18353](https://assetstore.unity.com/packages/2d/textures-materials/sky/fantasy-skybox-free-18353)

#### 下一步：创建地形

[https://iovhm.com/book/books/u3dblend/page/26e35](https://iovhm.com/book/books/u3dblend/page/26e35)

# 第三人称控制

#### 必要插件（官方内置插件）

- Cinemachine
- Input System

#### 开始使用

- 创建一个空的GameObject,改名为PersionGroup
- 在PersionGroup之下创建一个胶囊(cylinder)，取名为Persion
- 在Persion之下创建一个立方体(cube),调整大小和位置，使其成为这如下图的形状，目的是为了确认目标的方向，如下图的参数为：

[![](https://iovhm.com/book/uploads/images/gallery/2025-01/scaled-1680-/VkfAW2hm0KKjKx8Z-image-1736222843610.png)](https://iovhm.com/book/uploads/images/gallery/2025-01/VkfAW2hm0KKjKx8Z-image-1736222843610.png)

**此两个步骤可以省略，只是示意一下这是一个任务角色**

- 在PersionGroup之下创建一个空物体，改名为Lookme，用于摄像机跟随关注目标，设置positon:0,0,0
- 增加一个虚拟摄像机，右键或者GameObject菜单-&gt;Cine machine-&gt;Virtual Camera，改名为ThirdPersonCamera，选中摄像机后，在BODY面板中，更改摄像机类型为3rd Person Follow(第三人称视角跟随)
- 将Lookmet拖到3rd摄像机的follow中

[![](https://iovhm.com/book/uploads/images/gallery/2025-01/scaled-1680-/3n4bGGoeo9XA4vrI-image-1736224369634.png)](https://iovhm.com/book/uploads/images/gallery/2025-01/3n4bGGoeo9XA4vrI-image-1736224369634.png)

- 调整摄像机的位置和视角 
    - Third Person Camera lens面板下的参数： 
        - Vertical Fov:视口大小，默认值60，有点类似镜头焦段
        - dutch：镜头水平方向旋转，默认值为0
    - Third Person Camera body面板下的参数 
        - Shoulder Offset：直接调整3rd虚拟摄像机的位置
        - Vertical Arm Length：控制摄像机在垂直方向的位置
        - Camera Side：控制摄像机水平方向的位置
        - Camera Distance：控制摄像机垂直方向的位置

虽然调整lookme的position也可以控制摄像机的视角，但是还是应该调整**Third Person Camera**，因为lookme与被跟随的物体不在一个中心点的话，会导致跟随非常奇怪，无法使角色一直在正中间。最终得到的效果如下：

[![](https://iovhm.com/book/uploads/images/gallery/2025-01/scaled-1680-/NbG0Xc1zxQQh1wtC-image-1736227654544.png)](https://iovhm.com/book/uploads/images/gallery/2025-01/NbG0Xc1zxQQh1wtC-image-1736227654544.png)

#### 增加鼠标和键盘控制

- 在PersionGroup上增加搜索input,选择player input组件，选择或者create actions

[![](https://iovhm.com/book/uploads/images/gallery/2025-01/scaled-1680-/ABMaQmBxQMPM7X7x-image-1736228201450.png)](https://iovhm.com/book/uploads/images/gallery/2025-01/ABMaQmBxQMPM7X7x-image-1736228201450.png)

- 增加2个脚本ThirdPersonCameraLook.cs和ThirdPersonCameraMove.cs一个用于旋转，一个用于移动
- 用于旋转的**ThirdPersonCameraLook.cs**，将脚本挂载到PersionGroups上

```csharp
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.InputSystem;

public class ThirdPersonCameraLook : MonoBehaviour
{
    private GameObject mainCamera;

    [Header("Cinemachine")]
    [Tooltip("跟随目标")]
    public GameObject CameraTarget;

    [Tooltip("向上的最大角度")]
    public float TopClamp = 70.0f;

    [Tooltip("向下的最大角度")]
    public float BottomClamp = 0.0f;

    [Tooltip("相机旋转速度")]
    public float RotationSpeed = 1.0f;

    // 输入阈值
    private const float threshold = 0.01f;
    // 相机目标的 Y 轴旋转角度
    private float cinemachineTargetYaw;
    // 相机目标的 X 轴旋转角度
    private float cinemachineTargetPitch;
    // 存储玩家输入的视角变化
    private Vector2 lookup;
    // 标记是否正在旋转
    private bool isRotateing = false;
    void Start()
    {
        if (mainCamera == null)
        {
            // 查找并存储主相机对象
            mainCamera = GameObject.FindGameObjectWithTag("MainCamera");
        }
        // 初始化相机目标的 Y 轴旋转角度
        cinemachineTargetYaw = CameraTarget.transform.rotation.eulerAngles.y;
    }

    // Update is called once per frame
    void Update()
    {
        // 检查鼠标右键是否按下
        isRotateing = Mouse.current.rightButton.isPressed;
        // 如果正在旋转且输入的平方长度大于等于阈值，则更新相机目标的旋转角度
        if (isRotateing && lookup.sqrMagnitude >= threshold)
        {
            cinemachineTargetYaw += lookup.x;
            cinemachineTargetPitch += lookup.y;
        }
        // 限制相机目标的旋转角度在合理范围内
        cinemachineTargetYaw = ClampAngle(cinemachineTargetYaw, float.MinValue, float.MaxValue);
        cinemachineTargetPitch = ClampAngle(cinemachineTargetPitch, BottomClamp, TopClamp);

        // 使用插值函数平滑过渡相机的旋转，如果同时加了移动组件，不建议使用平滑旋转
        // Quaternion targetRotation = Quaternion.Euler(cinemachineTargetPitch, cinemachineTargetYaw, 0.0f);
        // CameraTarget.transform.rotation = Quaternion.Lerp(CameraTarget.transform.rotation, targetRotation, Time.deltaTime * RotationSpeed);
        // 控制相机的旋转
        CameraTarget.transform.rotation = Quaternion.Euler(cinemachineTargetPitch, cinemachineTargetYaw, 0.0f);
    }
    // 限制角度在指定范围内
    private static float ClampAngle(float angle, float min, float max)
    {
        if (angle < -360.0f)
        {
            angle += 360.0f;
        }
        if (angle > 360.0f)
        {
            angle -= 360.0f;
        }
        return Mathf.Clamp(angle, min, max);
    }

    public void OnLook(InputValue value)
    { // 处理玩家输入的视角变化
        lookup = value.Get<Vector2>();
    }
}



```

- 用于角色移动d**ThirdPersonCameraLook.cs**，将脚本挂载到PersionGroup上

```csharp
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.InputSystem;

public class ThirdPersonCameraMove : MonoBehaviour
{

    // 主摄像机对象引用
    private GameObject mainCamera;
    // 角色控制器对象引用
    private CharacterController controller;

    // 移动输入值
    private Vector2 moveValue;

    //   移动速度
    [Tooltip("移动速度")]
    public float speed = 1.0f;
    // 目标旋转角度
    private float targetRotation = 0.0f;

    // 平滑旋转时间
    public float RotationSmoothTime = 0.1f;
    // 旋转速度
    private float rotationVelocity = 0.0f;

    void Start()
    {
        if (mainCamera == null)
        {
            mainCamera = GameObject.FindGameObjectWithTag("MainCamera");
        }
        // 获取角色控制器对象
        controller = GetComponent<CharacterController>();
    }


    void Update()
    {
        // 记录原始的Y方向数值
        Vector3 velocity = new Vector3(0, -1, 0);
        if (moveValue != Vector2.zero)
        {
            // 计算输入方向，转换为世界坐标
            Vector3 inputDir = new Vector3(moveValue.x, 0.0f, moveValue.y).normalized;
            // 计算目标旋转角度
            targetRotation = Mathf.Atan2(inputDir.x, inputDir.z) * Mathf.Rad2Deg + mainCamera.transform.eulerAngles.y;

            // 平滑旋转
            float rotation = Mathf.SmoothDampAngle(transform.eulerAngles.y, targetRotation, ref rotationVelocity, RotationSmoothTime);
            // 旋转角色
            transform.rotation = Quaternion.Euler(0.0f, rotation, 0.0f);
            // 计算移动方向
            Vector3 targetDir = Quaternion.Euler(0.0f, targetRotation, 0.0f) * Vector3.forward;
             // 记录原始的Y方向数值
            velocity += targetDir.normalized * (speed * Time.deltaTime);
            // 移动角色
            // controller.Move(targetDir.normalized * (speed * Time.deltaTime));
        }
    }

    void OnMove(InputValue inputValue)
    {
        moveValue = inputValue.Get<Vector2>();
    }

}


```

- 为PersonGroup增加组件**Character Controller**,调整center的Y值，因为**Character Controller**可以看做是为PersonGroup增加了一个网格胶囊，此时可以打开网格线模式，可以看到**Character Controlle**增加的网格胶囊有一部分在地板之下，因此需要将Center调整到与PersonGroupw完全一致

[![](https://iovhm.com/book/uploads/images/gallery/2025-01/scaled-1680-/j6CfYgzTLpHOFqTN-image-1736266617899.png)](https://iovhm.com/book/uploads/images/gallery/2025-01/j6CfYgzTLpHOFqTN-image-1736266617899.png)

# 使用视频

如果场景中的内容全部使用模型渲染，除了耗费性能，还额外增加l很多工作。如果使用视频，则可以省却很多事情

#### 使用视频播放器

- 在场景中增加一个GameObject,改名为Video1,增加组件**Video Player**,将**Main Camern**拖入到Camera属性设置中

[![](https://iovhm.com/book/uploads/images/gallery/2025-01/scaled-1680-/JaNWIp7FyLK6vo4Z-image-1736308273034.png)](https://iovhm.com/book/uploads/images/gallery/2025-01/JaNWIp7FyLK6vo4Z-image-1736308273034.png)

#### 四种渲染方式

- Camera Far Plane:渲染在远景，可以被其他物体遮挡，当做氛围背景使用
- Camera Near Plane:渲染在近景，遮挡一切物体，可以当做引导视频使用、场景切换

可以将同一个摄像机关联到2个Video上，一个设置为远景模式，一个设置为近景，调整不同的alpha通道，实现一些特效效果

[![](https://iovhm.com/book/uploads/images/gallery/2025-01/scaled-1680-/Evy7K5PVV2Yb3bvm-image-1736311135437.png)](https://iovhm.com/book/uploads/images/gallery/2025-01/Evy7K5PVV2Yb3bvm-image-1736311135437.png)

- Material Override:顾名思义，可以覆盖材质，新建一个Quad，在**Video1**对象的**Render**中选择Quad，但是此时，视频看上去灰蒙蒙一片，那是因为Quad的默认材质会影响渲染效果;可以新建一个材质，将shader设置为**Universal Render Pipeline/Unlit**。这个方法适用于游戏内的广告牌，电视机、投影仪等。将材质的**surface type**修改 **transparent**，可以实现透明效果\*\*
- Render Texture:渲染到贴图，这个会更麻烦一些，第一实现效果是和渲染到材质差不多，后面在补充

#### 使用视频作为场景过度

可以播放一个前景视频，作为启动动画或者场景切换动画，然后切换到另外的场景

[https://iovhm.com/book/books/u3dblenderunity3d/page/01161](https://iovhm.com/book/books/u3dblenderunity3d/page/01161)

# 场景&&场景切换

一个scene就是一个场景（关卡），打开file-&gt;build Settings,将场景添加到scenes in build中，拖拽排序，第一个场景为游戏启动的默认场景，

[![](https://iovhm.com/book/uploads/images/gallery/2025-01/scaled-1680-/CqyxgFEHxnNg0r8Y-image-1736318717824.png)](https://iovhm.com/book/uploads/images/gallery/2025-01/CqyxgFEHxnNg0r8Y-image-1736318717824.png)

多个场景之间切换代码如下

```csharp
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class LoadScreen : MonoBehaviour
{
    // 暂时还不清楚这个名字不在scenes文件夹或者在子文件夹会有什么影响
    public string SceneName = "SampleScene";
    // 延迟时间
    public float Delay = 5f;
    void Start()
    {
        // 5秒后自动切换场景
        StartCoroutine(ChangeSceneAfterDelay(Delay));
    }
    // 切换场景
    private IEnumerator ChangeSceneAfterDelay(float delay)
    {
        // 等待delay秒
        yield return new WaitForSeconds(delay);
        // 切换场景
        UnityEngine.SceneManagement.SceneManager.LoadScene(SceneName);
    }
    void Update()
    {

    }
}


```

#### 后台运行

默认情况下，游戏到后台后就停止运行了，要设置在后台运行

菜单Edit-&gt;Project Settings-&gt;Player，右边的Resolution and Presentation选项卡中将Run In Background勾上

[![](https://iovhm.com/book/uploads/images/gallery/2025-01/scaled-1680-/vDY4KjTw5yMT41mB-image-1736320186081.png)](https://iovhm.com/book/uploads/images/gallery/2025-01/vDY4KjTw5yMT41mB-image-1736320186081.png)

# 用户界面和UI系统

u3d有2个UI系统，一个是传统的UGUI，一个是UI TOOL KIT,现在网上大部分教程都是UGUI的，而且UGUI主要以图片为主，可以做出更好看的效果，本文也使用UGUI

#### 开始

为便于观察，可以将编辑器设置为2D模式

[![](https://iovhm.com/book/uploads/images/gallery/2025-01/scaled-1680-/7HMD1vIoJQfuFEyp-image-1736397717035.png)](https://iovhm.com/book/uploads/images/gallery/2025-01/7HMD1vIoJQfuFEyp-image-1736397717035.png)

**在层级管理器上右键-&gt;ui-&gt;canvas**，此时编辑器将自动增加一个EventSystem,EventSystemy用于处理输入事件。

也可以直接增加一个image控件，编辑器也会自动帮忙增加canvas和Eventy System，所有的UI组件实际上都扩自image,可以在image上增加组件，此时，这个image就变成了一个按钮，可以处理按钮事件了。

##### 使用中文字体

**window-&gt;TextMeshPro-&gt;Font Assets Creator**

[![](https://iovhm.com/book/uploads/images/gallery/2025-01/scaled-1680-/lTpVCQm1ULvsHbl9-image-1736395317229.png)](https://iovhm.com/book/uploads/images/gallery/2025-01/lTpVCQm1ULvsHbl9-image-1736395317229.png)

**注意character set** 选择**characters from file**,并在项目创建一个txt文件，文件编码为utf8,把你需要使用的文字输入进去，即默认不会有文字

x想要获得得更清晰的显示效果，可以选择**Render Mode\*\*\*\*SMOOTH\_HINTED**，默认是**SDFAA**生产速度最快，但是显示效果一般

然后点击Generate Font atlas生成，最后点击保存，即可以使用中文字体了

#### 处理按钮事件

新增一个脚本**UiEvents.cs**，新建一个GameObject, 并将脚本挂载上去，回到button上，附件相关事件

```csharp
public class UiEvents : MonoBehaviour
{

    public void OnBtnStartGanmeClick()
    {
        Debug.Log("Button Clicked");
    }
}


```

[![](https://iovhm.com/book/uploads/images/gallery/2025-01/scaled-1680-/GsQZMgL27D16mzEJ-image-1736397523545.png)](https://iovhm.com/book/uploads/images/gallery/2025-01/GsQZMgL27D16mzEJ-image-1736397523545.png)

[![](https://iovhm.com/book/uploads/images/gallery/2025-01/scaled-1680-/HUREny7SfjrZAY68-image-1736397672311.png)](https://iovhm.com/book/uploads/images/gallery/2025-01/HUREny7SfjrZAY68-image-1736397672311.png)

#### 使用布局系统

使用锚点确定对其方式，可以按照我们常见的布局模式，使用Panel先画出区块，例如top,left，以适用自适应

[![](https://iovhm.com/book/uploads/images/gallery/2025-01/scaled-1680-/0A4LuFXNVBKBVHnP-image-1736397960587.png)](https://iovhm.com/book/uploads/images/gallery/2025-01/0A4LuFXNVBKBVHnP-image-1736397960587.png)

使用Panel先画出区块，例如top,left，以适用自适应

[![](https://iovhm.com/book/uploads/images/gallery/2025-01/scaled-1680-/UBw1UqHz9vM42BZW-image-1736398582800.png)](https://iovhm.com/book/uploads/images/gallery/2025-01/UBw1UqHz9vM42BZW-image-1736398582800.png)

增加一个GameObject,增加组件，搜索Layout，根据需要，选择网格布局、垂直布局、水平布局 [![](https://iovhm.com/book/uploads/images/gallery/2025-01/scaled-1680-/uynAddzGeckk6w5P-image-1736399345363.png)](https://iovhm.com/book/uploads/images/gallery/2025-01/uynAddzGeckk6w5P-image-1736399345363.png)

#### 常用组件

- Toggle（复选框）

[![](https://iovhm.com/book/uploads/images/gallery/2025-01/scaled-1680-/tkr1h39vzxwDzwId-image-1736516396807.png)](https://iovhm.com/book/uploads/images/gallery/2025-01/tkr1h39vzxwDzwId-image-1736516396807.png)

组件由Background（未选中状态），Checkmark（选中状态），Label（文字）三部分组成，可以分别设置单独的背景实现效果

- Slider（滑动动条）

[![](https://iovhm.com/book/uploads/images/gallery/2025-01/scaled-1680-/2dhmmswy5JKZWg0x-image-1736516793079.png)](https://iovhm.com/book/uploads/images/gallery/2025-01/2dhmmswy5JKZWg0x-image-1736516793079.png)

组件由三部分组成：Background（背景），Handle（滑块），Fill（填充）组成，既在最左边时，全部是背景，随着向右滑动，填充fill

- Scrollbar（滚动条） 滚动条由：Scrollbar（滚动条）、Handle（滑块）组成

[![](https://iovhm.com/book/uploads/images/gallery/2025-01/scaled-1680-/OXjv0CHjlVwUqvok-image-1736517559066.png)](https://iovhm.com/book/uploads/images/gallery/2025-01/OXjv0CHjlVwUqvok-image-1736517559066.png)

#### 注意事项

如果提示说新老版本的input system不兼容，需要在**EventSystem**上执行相关操作

[![](https://iovhm.com/book/uploads/images/gallery/2025-01/scaled-1680-/wXQoKhHnLVtHyTk3-image-1736527829447.png)](https://iovhm.com/book/uploads/images/gallery/2025-01/wXQoKhHnLVtHyTk3-image-1736527829447.png)

# 模型&&材质&&贴图

和真实世界一样，物体由骨架（框架、几何体、网格、Mesh）、材质（蒙皮、Material）、贴图（喷涂、texture）组合而来

- #### 模型（几何体、网格）：骨架，框架
    
    [![](https://iovhm.com/book/uploads/images/gallery/2024-09/scaled-1680-/RIyCbILaiVoVRaB9-image-1725852167381.png)](https://iovhm.com/book/uploads/images/gallery/2024-09/RIyCbILaiVoVRaB9-image-1725852167381.png)
- #### 材质：模拟真实世界的物体蒙皮，例如金属可以反光，塑料感，柔性、发光
- #### 贴图：将贴图应用于材质上，让3D物体显示对应的样式，例如木头样式，布料样式，类似真实世界的喷涂，在几何面上贴图
    
    
    - **一般贴图(漫反射贴图（albedo）)**直接作用与物体表面，就类似一张2D图片，通常有无缝拼图
    - **金属度贴图（metallic）**影响光照反射
    - **法线贴图（normal）**在凹凸的地方，因为面的朝向不同，使用法向贴图可以模拟出不同的凹陷感。 法向贴图由**RGB图的通道**组成，与大多数**三维软件的XYZ**轴对应，**R通道对应X轴，G通道对应Z轴，B通道对应Y轴**，各通道的色值影响凹陷的程度，0-128-255
- ##### 法向：既网格物体面的垂直方向叫做法向，在凹凸的地方，因为面的朝向不同，使用法向贴图可以模拟出不同的凹陷
    
    [![](https://iovhm.com/book/uploads/images/gallery/2024-09/scaled-1680-/aK73aGn4G58Fuxcg-image-1725852110486.png)](https://iovhm.com/book/uploads/images/gallery/2024-09/aK73aGn4G58Fuxcg-image-1725852110486.png)

#### 使用photoshop绘制材质贴图

##### 使用PS生成连续图

- 打开图片
- 滤镜 &gt; 其他 &gt; 位移,位移图片的一半大小
- 查看图片的链接情况，对显示不正常的地方进行修补
- 将原图扩大四倍，进行拼合查看整体情况

###### 使用PS生成法线图

- 打开图片
- 滤镜 &gt; 3D &gt; 生成法线图

###### 使用PS生成立方体贴图

- 立方体贴图，u3d会自动检测图片，空白地方可以留白色、黑色、或者透明(PNG)
- 白色，全反光；黑色，不反光
    
    [![](https://iovhm.com/book/uploads/images/gallery/2024-09/scaled-1680-/0umdfhHQ3UHzeSux-image-1725862672134.png)](https://iovhm.com/book/uploads/images/gallery/2024-09/0umdfhHQ3UHzeSux-image-1725862672134.png)

#### 其他软件

- <s>substance-3d-stager:导入内容、排列场景、应用材质和纹理、调整基于图像的照明和物理照明、保存不同分辨率的摄像机以及渲染逼真的图</s>
- substance-3d-sampler:通过调整和混合现有材质，或者从扫描件（单个或多个图像）中提取新材质来创建和迭代材质集合
- substance-3d-designer:材质创作软件。它允许您使用节点图从程序模式和噪波生成纹理，以及操纵位图
- <s>substance-3d-painter:D 绘画软件，可让您对 3D 网格进行纹理处理和渲染</s>
- <s>PixPlant 5：无缝贴图生成软件，付费软件</s>

# 创建地图

#### 安装地图扩展工具

在 **window &gt; package manager** 搜索 **terrain tools** ，安装地图编辑器扩展工具

- 下载资源包 
    - [https://assetstore.unity.com/packages/3d/environments/landscapes/terrain-sample-asset-pack-145808](https://assetstore.unity.com/packages/3d/environments/landscapes/terrain-sample-asset-pack-145808)
    - [https://assetstore.unity.com/packages/2d/textures-materials/nature/grass-flowers-pack-free-138810](https://assetstore.unity.com/packages/2d/textures-materials/nature/grass-flowers-pack-free-138810)

#### 增加地图

**GameObject &gt; 3D Object &gt; Terrain**

[![](https://iovhm.com/book/uploads/images/gallery/2024-09/scaled-1680-/kx4dxzcvpumUyWGI-image-1725732579273.png)](https://iovhm.com/book/uploads/images/gallery/2024-09/kx4dxzcvpumUyWGI-image-1725732579273.png)

#### 对地图进行设置

3d里面并没有一个固定的单位，有的仅是相对单位，例如一个立方体的高度为1，假设一个人的身高大约2米，可以根据此来换算地图的大小，地图的默认大小是1000，太大的地图消耗性能

[![](https://iovhm.com/book/uploads/images/gallery/2024-09/scaled-1680-/X4UhNk4GUQ4tALoE-image-1725710223329.png)](https://iovhm.com/book/uploads/images/gallery/2024-09/X4UhNk4GUQ4tALoE-image-1725710223329.png)

terrain width:地图宽，X方向大小 terrain lenght:地图的长，Y方向大小 *terrain height：视乎并没有用*

#### 使用地形工具进行绘制

- Set Height：将高度贴图调整为特定值。将地形整体设置高度20，否则后期地形凹陷没有效果
- Raise or Lower Terrain：使用画笔工具绘制高度贴图。按shift是负方向，既凹陷例如池塘

[![](https://iovhm.com/book/uploads/images/gallery/2024-09/scaled-1680-/CDlViOdC7A2EYpNx-image-1725710917333.png)](https://iovhm.com/book/uploads/images/gallery/2024-09/CDlViOdC7A2EYpNx-image-1725710917333.png)

- Paint Holes：隐藏地形的某些部分，挖洞，例如山洞
- Smooth Height：平滑高度贴图以柔化地形特征。
- Paint Texture：应用表面纹理
    
    第一张贴图是作用域全部，所以一般第一张选择沙石或者草地，后面张才可以自己绘制
- Stamp Terrain：在当前高度贴图之上标记画笔形状。

#### 植树

调整画刷大小和密度，密度太小可能种不下去，密度太大会选的很杂乱

[![](https://iovhm.com/book/uploads/images/gallery/2024-09/scaled-1680-/sB3R9nSfIHhn9rN2-image-1725713403466.png)](https://iovhm.com/book/uploads/images/gallery/2024-09/sB3R9nSfIHhn9rN2-image-1725713403466.png)

#### 种花

与植树大同小异，好处是可以同时种几种

[![](https://iovhm.com/book/uploads/images/gallery/2024-09/scaled-1680-/RxlVSW4O6WHtt6Ok-image-1725732042472.png)](https://iovhm.com/book/uploads/images/gallery/2024-09/RxlVSW4O6WHtt6Ok-image-1725732042472.png)

[![](https://iovhm.com/book/uploads/images/gallery/2024-09/scaled-1680-/FXqp7LJjEiL6zgCD-image-1725732237240.png)](https://iovhm.com/book/uploads/images/gallery/2024-09/FXqp7LJjEiL6zgCD-image-1725732237240.png)

#### 设置雾

# 粒子&&特效&&particle system

#### 学习视频

[https://www.bilibili.com/video/BV1yy4y1B7ir/?vd\_source=e5c89a4572347dbc9fec6b7a7ef56513](https://www.bilibili.com/video/BV1yy4y1B7ir/?vd_source=e5c89a4572347dbc9fec6b7a7ef56513)

#### 增加particle system

**右键 &gt; effects &gt; particle system**

为了更便于观察，可以去掉**selection outline**

[![](https://iovhm.com/book/uploads/images/gallery/2024-09/scaled-1680-/kyMb6adc1FHvf0T1-image-1725733235243.png)](https://iovhm.com/book/uploads/images/gallery/2024-09/kyMb6adc1FHvf0T1-image-1725733235243.png)

#### 基础使用

默认会有三个组件被选中，因为默认情况下在编辑器窗口不会自动预览，需要选择后才能预览，比较复杂的效果由多个效果组成，使用空组件也不能生效，可以先创建一个particle system，然后将默认的三个组件去掉，选中父组件，即可用预览

[![](https://iovhm.com/book/uploads/images/gallery/2024-09/scaled-1680-/NaU33AFKoBNjqZwC-image-1725733323313.png)](https://iovhm.com/book/uploads/images/gallery/2024-09/NaU33AFKoBNjqZwC-image-1725733323313.png)

- particle System：核心，主模块
    
    
    - duration：持续时间
    - looping：是否循环播放
    - Start Lifetime ：粒子的生存时间，既每个粒子可以存活多久
    - start speed：每个粒子的发射速度
    - start size:每个粒子的初始化大小
- Emission：核心组件，粒子发生器
    
    
    - rate over time : 一秒内发生多少个
    - Rate over Distance：根据移动距离决定发射的数量
    - bursts：爆发释放
- Shape：核心组件，形状发生器
    
    
    - shape:发生器形状 
        - cone:喇叭筒
- Renderer：核心组件，渲染器
    
    
    - Render Mode：渲染模式 
        - Billboard：原样渲染
        - Stretched Billboard：拉伸渲染，会变的扁平，有点拖尾的效果 
            - Speed Scale：拉伸的长度，太大会变形太多
            - Length Scale：拉伸宽度，1-2之间
- Color over Lifetime：颜色随着生命周期变化，可以设置渐变
- Size over Lifetime ： 大小随生命周期变化，可以设置区县
- Moise：噪声随机数
    
    
    - Strength：噪声强度
    - Frequency：噪声频率
    - Scroll Speed：受噪声图影响
- Collision：碰撞，选择需要发生碰撞的物体，物体需要有mesh collider组件
    
    
    - Dampen：损伤，设置为1触碰到就没了
    - bounce：反弹力度
    - Lifetime Loss：生命周期损失，百分比
- Lights：灯光效果，仅支持点光和
    
    
    - Ratio：发光粒子的比例，既有多少粒子参与发光
- Velocity over Lifetime ：生命周期内的轨迹，可以做螺旋效果
    
    
    - Linear ：线性偏移，表现为并不是直线移动，类似被风吹了的感觉
    - Orbital：轨迹偏移，可以作出螺旋效果，和前面这个结合，可以作出龙卷风效果
    - Radial ：发散效果，负值发散，正只聚拢
    - Speed Modifier：速度修改

# shader&&着色器

#### 什么是shader

3D世界物的显示与增加方式为步骤为：网格 &gt; 材质 &gt; 贴图

其中在材质步骤有诸多设置参数，其中一项重要选型为shader，既着色器，以告诉物体应该如何绘制，3D软件通常内置了很多shader，当内置shader无法满足我们要求的时候，需要自己实现shader

[![](https://iovhm.com/book/uploads/images/gallery/2024-09/scaled-1680-/qoKDrQIBYMLGUhC9-image-1725989324874.png)](https://iovhm.com/book/uploads/images/gallery/2024-09/qoKDrQIBYMLGUhC9-image-1725989324874.png)

为模型增加材质，通常可以：

- 先创建材质，将材质拖放到物体上
- 直接将贴图拖放到模型上，U3D将自动创建材质并关联

双击材质，既可以查看材质的相信情况

[![](https://iovhm.com/book/uploads/images/gallery/2024-09/scaled-1680-/GxPjRT8BPCtC8tUy-image-1725989510762.png)](https://iovhm.com/book/uploads/images/gallery/2024-09/GxPjRT8BPCtC8tUy-image-1725989510762.png)

当默认shader无法满足我们要求时，例如特殊，则我们需要自己定义shader

#### 创建shader

**create &gt; shader graph &gt; URP &gt; lit shader graph**

- lit shader graph:光照模型
- unlit shader graph：无光照模型

双击新建的shader文件，则进入shader编辑窗口，保存shader后（不保存的在选择界面看不到），可以在材质的shader选项选择当前自定义shader

**shader &gt; shader graphs &gt; new-cus-shaper**

[![](https://iovhm.com/book/uploads/images/gallery/2024-09/scaled-1680-/85A82qTqFAHgNVrK-image-1725991539890.png)](https://iovhm.com/book/uploads/images/gallery/2024-09/85A82qTqFAHgNVrK-image-1725991539890.png)

#### 开始编辑自定义shader

shader的主要工作流程如下，其工作原理为，3D物体在计算机进行显示的时候，总是需要将物体转换为具体的颜色信息输入到显示卡，通过对一系列的参数进行计算后，最终改变主要影响物体的两个主要参数

- 顶点着色器
- **片元着色器**
    - 根据其连线结果来看，主要输入点都是颜色信息和贴图信息，这一类用的最多

[![](https://iovhm.com/book/uploads/images/gallery/2024-09/scaled-1680-/6LtZ50wSuUgc7o7B-image-1725992012845.png)](https://iovhm.com/book/uploads/images/gallery/2024-09/6LtZ50wSuUgc7o7B-image-1725992012845.png)

各面板情况

[![](https://iovhm.com/book/uploads/images/gallery/2024-09/scaled-1680-/qkadBm9SsO5vgafJ-image-1725992371665.png)](https://iovhm.com/book/uploads/images/gallery/2024-09/qkadBm9SsO5vgafJ-image-1725992371665.png)

- ①输入参数：此处的参数可以在外部进行设置，
- ②参数计算：对参数进行计算的逻辑，不同的参数需要增加不同的节点计算之后，才可以链接到下一个节点
- ③片元着色器：计算结果影响颜色，贴图
- ④定点着色器：
- ⑤属性设置：对节点、参数进行设置
- ⑥预览窗口：实时预览渲染结果

#### 常用技巧

- Texture2D贴图通常不能直接输入到片元着色器，需要增加**Sample Texture 2D** （贴图取样）
- 当需要同时设置贴图或者颜色、多个颜色混合，需要增加**Multiply**乘法计算器进行混合
- 边缘发光**Fresnel Effect**（菲涅耳）

# adobe全家桶

[https://www.yuque.com/doolook/xvdbng/nkm8p1ws5dmf1ksc?singleDoc](https://www.yuque.com/doolook/xvdbng/nkm8p1ws5dmf1ksc?singleDoc)

# xcharts&&图表插件

#### 下载地址

[https://github.com/XCharts-Team/XCharts](https://github.com/XCharts-Team/XCharts)

[![](https://iovhm.com/book/uploads/images/gallery/2025-01/scaled-1680-/hRMSvNsAJ59BeHfw-image-1736934631162.png)](https://iovhm.com/book/uploads/images/gallery/2025-01/hRMSvNsAJ59BeHfw-image-1736934631162.png)

[![](https://iovhm.com/book/uploads/images/gallery/2025-01/scaled-1680-/jjZkoAZLSQge2WKN-image-1736934649123.png)](https://iovhm.com/book/uploads/images/gallery/2025-01/jjZkoAZLSQge2WKN-image-1736934649123.png)

#### 折线图

- Area Line

[![](https://iovhm.com/book/uploads/images/gallery/2025-01/scaled-1680-/cH0dTx4umTdVh0mJ-image-1736930754531.png)](https://iovhm.com/book/uploads/images/gallery/2025-01/cH0dTx4umTdVh0mJ-image-1736930754531.png)

- Basic Line

[![](https://iovhm.com/book/uploads/images/gallery/2025-01/scaled-1680-/YHV8rmFKPAkPLkeq-image-1736930784323.png)](https://iovhm.com/book/uploads/images/gallery/2025-01/YHV8rmFKPAkPLkeq-image-1736930784323.png)

主要指需要如上两个即可，其他的可以通过设置属性改变线条样式

- Dashed Line

可以通过 Line Stype -&gt; Type修改线条样式

[![](https://iovhm.com/book/uploads/images/gallery/2025-01/scaled-1680-/tj6LiSQcva9KMN5y-image-1736930837293.png)](https://iovhm.com/book/uploads/images/gallery/2025-01/tj6LiSQcva9KMN5y-image-1736930837293.png)

- Smooth Area Line

可以通过设置 Line Type设置，是曲线变成平滑曲线

[![](https://iovhm.com/book/uploads/images/gallery/2025-01/scaled-1680-/5r8nJRxrNDfDCUvt-image-1736930999558.png)](https://iovhm.com/book/uploads/images/gallery/2025-01/5r8nJRxrNDfDCUvt-image-1736930999558.png)

- Smooth Line

可以通过设置 Line Type设置，是曲线变成平滑曲线

[![](https://iovhm.com/book/uploads/images/gallery/2025-01/scaled-1680-/ObHDlhbXHxEliSJN-image-1736930955339.png)](https://iovhm.com/book/uploads/images/gallery/2025-01/ObHDlhbXHxEliSJN-image-1736930955339.png)

#### 柱状图

- Basic Bar

[![](https://iovhm.com/book/uploads/images/gallery/2025-01/scaled-1680-/CFGpUi9PtQ8TDs1r-image-1736931269111.png)](https://iovhm.com/book/uploads/images/gallery/2025-01/CFGpUi9PtQ8TDs1r-image-1736931269111.png)

- Basic Column

[![](https://iovhm.com/book/uploads/images/gallery/2025-01/scaled-1680-/1suAYxrkzulbfFDy-image-1736931457654.png)](https://iovhm.com/book/uploads/images/gallery/2025-01/1suAYxrkzulbfFDy-image-1736931457654.png)

实际上指需要如上两个即可，其他d可以通过调整Bar Type修改柱子样式

- Capsule Bar

可以通过修改Bar Type修改柱子样式

[![](https://iovhm.com/book/uploads/images/gallery/2025-01/scaled-1680-/TAkmQgc82GrJgOXS-image-1736931720895.png)](https://iovhm.com/book/uploads/images/gallery/2025-01/TAkmQgc82GrJgOXS-image-1736931720895.png)

#### 饼图

- Area Rose

[![](https://iovhm.com/book/uploads/images/gallery/2025-01/scaled-1680-/ktmKYgkrZnZxuOEG-image-1736932412124.png)](https://iovhm.com/book/uploads/images/gallery/2025-01/ktmKYgkrZnZxuOEG-image-1736932412124.png)

- Dount

[![](https://iovhm.com/book/uploads/images/gallery/2025-01/scaled-1680-/2R2k57gJSitb8AH4-image-1736932466433.png)](https://iovhm.com/book/uploads/images/gallery/2025-01/2R2k57gJSitb8AH4-image-1736932466433.png)

- Dount With Label

[![](https://iovhm.com/book/uploads/images/gallery/2025-01/scaled-1680-/AJLmN2SBctO0UI49-image-1736932594782.png)](https://iovhm.com/book/uploads/images/gallery/2025-01/AJLmN2SBctO0UI49-image-1736932594782.png)

- Pie

[![](https://iovhm.com/book/uploads/images/gallery/2025-01/scaled-1680-/f3I8E5pb1T8WosPd-image-1736932616125.png)](https://iovhm.com/book/uploads/images/gallery/2025-01/f3I8E5pb1T8WosPd-image-1736932616125.png)

- Pie With Label

[![](https://iovhm.com/book/uploads/images/gallery/2025-01/scaled-1680-/muX5Y3hTEsrdY3BU-image-1736932716521.png)](https://iovhm.com/book/uploads/images/gallery/2025-01/muX5Y3hTEsrdY3BU-image-1736932716521.png)

#### 雷达图

- Crile Radar

[![](https://iovhm.com/book/uploads/images/gallery/2025-01/scaled-1680-/4yblH3zJwSo4AyNy-image-1736932827897.png)](https://iovhm.com/book/uploads/images/gallery/2025-01/4yblH3zJwSo4AyNy-image-1736932827897.png)

- Polygon Radar

[![](https://iovhm.com/book/uploads/images/gallery/2025-01/scaled-1680-/An8R493Ox06xKRsy-image-1736932991181.png)](https://iovhm.com/book/uploads/images/gallery/2025-01/An8R493Ox06xKRsy-image-1736932991181.png)

# xcharts样式设置-折线图

#### 主要可自定义样式区域

[![](https://iovhm.com/book/uploads/images/gallery/2025-01/scaled-1680-/jnljREBKWbGuKHZQ-image-1736938097936.png)](https://iovhm.com/book/uploads/images/gallery/2025-01/jnljREBKWbGuKHZQ-image-1736938097936.png)

#### Area Style

[![](https://iovhm.com/book/uploads/images/gallery/2025-01/scaled-1680-/eOzoBIZisglXYQtX-image-1736938326782.png)](https://iovhm.com/book/uploads/images/gallery/2025-01/eOzoBIZisglXYQtX-image-1736938326782.png)

#### 线条样式

[![](https://iovhm.com/book/uploads/images/gallery/2025-01/scaled-1680-/8JwZ1v9RjwConXwf-image-1736950496921.png)](https://iovhm.com/book/uploads/images/gallery/2025-01/8JwZ1v9RjwConXwf-image-1736950496921.png)

#### 半透明背景

[![](https://iovhm.com/book/uploads/images/gallery/2025-01/scaled-1680-/XSzuH0BrAbTRtRty-image-1736952973527.png)](https://iovhm.com/book/uploads/images/gallery/2025-01/XSzuH0BrAbTRtRty-image-1736952973527.png)

[![](https://iovhm.com/book/uploads/images/gallery/2025-01/scaled-1680-/EmFfvCcmUSl4nKN2-image-1736953014293.png)](https://iovhm.com/book/uploads/images/gallery/2025-01/EmFfvCcmUSl4nKN2-image-1736953014293.png)

#### 鼠标悬停提示

**{.}{b}年:{c}万元**

[![](https://iovhm.com/book/uploads/images/gallery/2025-01/scaled-1680-/2AzG2keKgIK8TbJx-image-1736950986953.png)](https://iovhm.com/book/uploads/images/gallery/2025-01/2AzG2keKgIK8TbJx-image-1736950986953.png)

```csharp
/// ||提示框标题内容的字符串模版格式器。支持用 \n 换行。可以单独设置占位符{i}表示忽略不显示title。
/// 模板变量有{.}、{a}、{b}、{c}、{d}、{e}、{f}、{g}。<br/>
/// {.}为当前所指示或index为0的serie的对应颜色的圆点。<br/>
/// {a}为当前所指示或index为0的serie的系列名name。<br/>
/// {b}为当前所指示或index为0的serie的数据项serieData的name，或者类目值（如折线图的X轴）。<br/>
/// {c}为当前所指示或index为0的serie的y维（dimesion为1）的数值。<br/>
/// {d}为当前所指示或index为0的serie的y维（dimesion为1）百分比值，注意不带%号。<br/>
/// {e}为当前所指示或index为0的serie的数据项serieData的name。<br/>
/// {h}为当前所指示或index为0的serie的数据项serieData的十六进制颜色值。<br/>
/// {f}为数据总和。<br/>
/// {g}为数据总个数。<br/>
/// {y}为value所对应的y轴的类目值。<br/>
/// {.1}表示指定index为1的serie对应颜色的圆点。<br/>
/// {a1}、{b1}、{c1}中的1表示指定index为1的serie。<br/>
/// {c1:2}表示索引为1的serie的当前指示数据项的第3个数据（一个数据项有多个数据，index为2表示第3个数据）。<br/>
/// {c1:2-2}表示索引为1的serie的第3个数据项的第3个数据（也就是要指定第几个数据项时必须要指定第几个数据）。<br/>
/// {d1:2:f2}表示单独指定了数值的格式化字符串为f2（不指定时用numericFormatter）。<br/>
/// {d:0.##} 表示单独指定了数值的格式化字符串为 0.## （用于百分比，保留2位有效数同时又能避免使用 f2 而出现的类似于"100.00%"的情况 ）。<br/>
/// 示例："{a}:{c}"、"{a1}:{c1:f1}"、"{a1}:{c1:0:f1}"、"{a1}:{c1:1-1:f1}"

```

#### 使用代码填充数据

```csharp

public class LoadData : MonoBehaviour
{
    private Color initialColor = Color.white;
    private Color targetColor = Color.white;
    private Color currentColor = Color.white;
    public float updateInterval = 1.0f;
    private XCharts.Runtime.LineChart lineChart;
    [Title("目标对象")]
    public GameObject TargetObject;


    // Start is called before the first frame update
    void Start()
    {
        if (TargetObject != null)
        {
            // 根据tag查找对象
            lineChart = TargetObject.GetComponent<XCharts.Runtime.LineChart>();
            lineChart.ClearData();
            lineChart.AddXAxisData("2020");
            lineChart.AddXAxisData("2021");
            lineChart.AddXAxisData("2022");
            lineChart.AddXAxisData("2023");
            lineChart.AddXAxisData("2024");

            lineChart.AddData(0, 0, 100);
            lineChart.AddData(0, 1, 60);
            lineChart.AddData(0, 2, 15);
            lineChart.AddData(0, 3, 30);
            lineChart.AddData(0, 4, 77);

            // 初始化颜色
            initialColor = new Color(1.0f, 0.0f, 1.0f); // 紫色
            currentColor = initialColor;
            targetColor = new Color(1.0f, 1.0f, 1.0f); // 白色
        }

    }

    // Update is called once per frame
    void Update()
    {
        if (lineChart != null)
        {
            // 渐变修改series上的item style的background color
            var serie = lineChart.GetSerie(0);
            if (serie != null)
            {
                var itemStyle = serie.itemStyle;
                float time = Mathf.PingPong(Time.time / updateInterval, 1.0f);
                currentColor = Color.Lerp(initialColor, targetColor, time);
                itemStyle.backgroundColor = currentColor;
                serie.itemStyle = itemStyle;
            }
        }
    }
}



```

# xcharts样式设置-柱状图

#### 为单独的柱子设置样式

[![](https://iovhm.com/book/uploads/images/gallery/2025-01/scaled-1680-/F6pfa4J2ZAvsTrzB-image-1737013094656.png)](https://iovhm.com/book/uploads/images/gallery/2025-01/F6pfa4J2ZAvsTrzB-image-1737013094656.png)

#### 动画不起效果

柱状图直接修改Item Style后发现需要把鼠标放到图表上才起效果

[![](https://iovhm.com/book/uploads/images/gallery/2025-01/scaled-1680-/eaKxtiqxlKnEBE6p-image-1737008632320.png)](https://iovhm.com/book/uploads/images/gallery/2025-01/eaKxtiqxlKnEBE6p-image-1737008632320.png)

# blender基本操作

#### 快捷键

- 旋转：中键，默认的旋转视角为

[![](https://iovhm.com/book/uploads/images/gallery/2025-01/scaled-1680-/R6MCY29S3CYuEe3Z-image-1737044872798.png)](https://iovhm.com/book/uploads/images/gallery/2025-01/R6MCY29S3CYuEe3Z-image-1737044872798.png)

- 平移:shift+中键
- 缩放：滚轮
- 新建：shift+A
- 删除物品：选中物品后X或者删除键
- 移动物体：选择物体后**G**，XYZ约束移动方向
- 缩放物体：选择物体后**S**，XYZ约束移动方向
- 旋转物体物体：选择物体后**R**，XYZ约束移动方向
- 显示隐藏左边工具：T
- 显示隐藏右边信息：N
- 游标选项快捷键：shift+s
- 显示边长和面积，在编辑模式下，选择网格编辑模式菜单，选中测量中的边长和面积
- 对齐，按shfit选择，然后shift+s ，使用数字键盘进行选择。到活动项(8)指的是最后一个被选中的
- 使游标到默认中心:shift+c

[![](https://iovhm.com/book/uploads/images/gallery/2025-01/scaled-1680-/WmPPInBS3OzJ8nZz-image-1737044164920.png)](https://iovhm.com/book/uploads/images/gallery/2025-01/WmPPInBS3OzJ8nZz-image-1737044164920.png)

#### 恢复默认布局

文件（file）-&gt;默认(defaults)-&gt;加载初始设置(load factory settings) , 字体太小看不清，设置分辨率缩放。恢复默认设置后，中文汉化不完整，需要重新启动blender.

[![](https://iovhm.com/book/uploads/images/gallery/2025-01/scaled-1680-/CJKgMAhyBNgYGCFX-image-1737042930760.png)](https://iovhm.com/book/uploads/images/gallery/2025-01/CJKgMAhyBNgYGCFX-image-1737042930760.png)

# blender建筑插件&&building_tools

[https://github.com/ranjian0/building\_tools](https://github.com/ranjian0/building_tools)

#### 使用方法

[https://www.bilibili.com/video/BV1DQ4y1d7BT/](https://www.bilibili.com/video/BV1DQ4y1d7BT/)

# blender uv和贴图

#### 先为模型展UV

先增加UV贴图（默认情况下应该已经有一张了）

[![](https://iovhm.com/book/uploads/images/gallery/2025-01/scaled-1680-/yy7Ok7zadD5V2Oes-image-1737096607954.png)](https://iovhm.com/book/uploads/images/gallery/2025-01/yy7Ok7zadD5V2Oes-image-1737096607954.png)

点击基础色的小点

[![](https://iovhm.com/book/uploads/images/gallery/2025-01/scaled-1680-/8o6J6WGkYOobqxoR-image-1737096692584.png)](https://iovhm.com/book/uploads/images/gallery/2025-01/8o6J6WGkYOobqxoR-image-1737096692584.png)

选择图像纹理

[![](https://iovhm.com/book/uploads/images/gallery/2025-01/scaled-1680-/mCBXqdTNEnRQsZQZ-image-1737096761823.png)](https://iovhm.com/book/uploads/images/gallery/2025-01/mCBXqdTNEnRQsZQZ-image-1737096761823.png)

选择新建或者打开一张已经存在的纹理图

[![](https://iovhm.com/book/uploads/images/gallery/2025-01/scaled-1680-/DbStNy9SKpc6peeW-image-1737097180417.png)](https://iovhm.com/book/uploads/images/gallery/2025-01/DbStNy9SKpc6peeW-image-1737097180417.png)

方法二，打开UV编辑器，选择图像，新建，建议选择彩色栅格图，此时回到上一步，既可以选择到UV图片了

[![](https://iovhm.com/book/uploads/images/gallery/2025-01/scaled-1680-/J2SxE55kE4Og1Oxt-image-1737097829665.png)](https://iovhm.com/book/uploads/images/gallery/2025-01/J2SxE55kE4Og1Oxt-image-1737097829665.png)

可以选择这里将UV图片断开

[![](https://iovhm.com/book/uploads/images/gallery/2025-01/scaled-1680-/hjxCj5YlICi4oqk4-image-1737098258061.png)](https://iovhm.com/book/uploads/images/gallery/2025-01/hjxCj5YlICi4oqk4-image-1737098258061.png)

此时已经可以看到附加的默认纹理背景了，主要需要把材质预览模式打开

[![](https://iovhm.com/book/uploads/images/gallery/2025-01/scaled-1680-/tvTBx9O0HFNNiAPT-image-1737098558650.png)](https://iovhm.com/book/uploads/images/gallery/2025-01/tvTBx9O0HFNNiAPT-image-1737098558650.png)

打开纹理绘制窗口，可以直接在模型或者纹理上面进行画刷涂改，但是这个时候不方便，可以使用参考图进行绘制。在纹理窗口，加载一张片，作为画刷

[![](https://iovhm.com/book/uploads/images/gallery/2025-01/scaled-1680-/apGZFjutaOklWVb2-image-1737098564480.png)](https://iovhm.com/book/uploads/images/gallery/2025-01/apGZFjutaOklWVb2-image-1737098564480.png)

- 拼图：将图片纹理作为画刷
- 镂版：将图片贴（拓印）到模型上 
    - 鼠标右键：移动贴图
    - SHIFT+右键：缩放贴图
    - CTRL+右键：旋转贴图

[![](https://iovhm.com/book/uploads/images/gallery/2025-01/scaled-1680-/uMrNdZ4q1wsLZ000-image-1737101275002.png)](https://iovhm.com/book/uploads/images/gallery/2025-01/uMrNdZ4q1wsLZ000-image-1737101275002.png)

[![](https://iovhm.com/book/uploads/images/gallery/2025-01/scaled-1680-/d4hnBmDbOXSCRu58-image-1737101296668.png)](https://iovhm.com/book/uploads/images/gallery/2025-01/d4hnBmDbOXSCRu58-image-1737101296668.png)

[![](https://iovhm.com/book/uploads/images/gallery/2025-01/scaled-1680-/CZE5iyAKarL7QNKy-image-1737101788771.png)](https://iovhm.com/book/uploads/images/gallery/2025-01/CZE5iyAKarL7QNKy-image-1737101788771.png)

修改不同纹理参数，实现不同的效果涂抹，进行画刷涂抹，但是这图片适合高度重复的情况，例如草地，墙面等。可以修改必刷的纹理为镂版，

#### 设置外部编辑器为Photoshop

[![](https://iovhm.com/book/uploads/images/gallery/2025-01/scaled-1680-/OCBBholyjzwyxLAk-image-1737100698251.png)](https://iovhm.com/book/uploads/images/gallery/2025-01/OCBBholyjzwyxLAk-image-1737100698251.png)

# blender室内建筑&&Archimesh

#### 安装插件

- 系统内置常见**Archimesh**，插件已经存，但是未开启，
- 相关视频教程：
    
    
    - [https://www.bilibili.com/video/BV19z4y1a7bi](https://www.bilibili.com/video/BV19z4y1a7bi)
    - [https://www.bilibili.com/video/BV1sN4y1p7mN](https://www.bilibili.com/video/BV1sN4y1p7mN)
    - [https://www.bilibili.com/video/BV1eQ6DYrEy8](https://www.bilibili.com/video/BV1eQ6DYrEy8)

#### 使用方法一

打开面板

[![](https://iovhm.com/book/uploads/images/gallery/2025-01/scaled-1680-/mZq3ogvQZNajd3Fo-image-1737220954020.png)](https://iovhm.com/book/uploads/images/gallery/2025-01/mZq3ogvQZNajd3Fo-image-1737220954020.png)

导入户型图，进行临摹，调整墙面的长度、角度等

[![](https://iovhm.com/book/uploads/images/gallery/2025-01/scaled-1680-/uJE3N2cZYZexR6Z6-image-1737218259432.png)](https://iovhm.com/book/uploads/images/gallery/2025-01/uJE3N2cZYZexR6Z6-image-1737218259432.png)

增加屋顶的小尖尖

[![](https://iovhm.com/book/uploads/images/gallery/2025-01/scaled-1680-/4mHOF1tz2CxABkrz-image-1737218658598.png)](https://iovhm.com/book/uploads/images/gallery/2025-01/4mHOF1tz2CxABkrz-image-1737218658598.png)

制作屋顶瓦面

[![](https://iovhm.com/book/uploads/images/gallery/2025-01/scaled-1680-/oUTlo8U7aRgtgkNR-image-1737220210939.png)](https://iovhm.com/book/uploads/images/gallery/2025-01/oUTlo8U7aRgtgkNR-image-1737220210939.png)

然后添加们和窗口

##### 使用方法二

使用标注工具初步画出一个框框

[![](https://iovhm.com/book/uploads/images/gallery/2025-01/scaled-1680-/38PK8z4jTaCRJmMQ-image-1737217287102.png)](https://iovhm.com/book/uploads/images/gallery/2025-01/38PK8z4jTaCRJmMQ-image-1737217287102.png)

一键生成，然后调整

[![](https://iovhm.com/book/uploads/images/gallery/2025-01/scaled-1680-/ZaZkjt8YevOQ38nB-image-1737217332271.png)](https://iovhm.com/book/uploads/images/gallery/2025-01/ZaZkjt8YevOQ38nB-image-1737217332271.png)

# blender室内建筑插件&&ArchiPack

#### 插件介绍

插件名称

- 相关教程： 
    - [https://www.bilibili.com/video/BV1e2421F7bF](https://www.bilibili.com/video/BV1e2421F7bF)

#### 使用方法

调出工具箱 [![](https://iovhm.com/book/uploads/images/gallery/2025-01/scaled-1680-/WoczKOiMbylhJoNB-image-1737222599943.png)](https://iovhm.com/book/uploads/images/gallery/2025-01/WoczKOiMbylhJoNB-image-1737222599943.png)

# 我要学摄影

[![](https://iovhm.com/book/uploads/images/gallery/2025-02/scaled-1680-/NWzpCeeWo6T7vCVk-image-1739161889541.png)](https://iovhm.com/book/uploads/images/gallery/2025-02/NWzpCeeWo6T7vCVk-image-1739161889541.png)

[![](https://iovhm.com/book/uploads/images/gallery/2025-02/scaled-1680-/cbOiMVpOA0avQnXc-image-1739161912309.png)](https://iovhm.com/book/uploads/images/gallery/2025-02/cbOiMVpOA0avQnXc-image-1739161912309.png)

[![](https://iovhm.com/book/uploads/images/gallery/2025-02/scaled-1680-/wgN5Stq4Y5z0wCvc-image-1739162356785.png)](https://iovhm.com/book/uploads/images/gallery/2025-02/wgN5Stq4Y5z0wCvc-image-1739162356785.png)

[![](https://iovhm.com/book/uploads/images/gallery/2025-02/scaled-1680-/owIBhiCSOqroqAR6-image-1739162387022.png)](https://iovhm.com/book/uploads/images/gallery/2025-02/owIBhiCSOqroqAR6-image-1739162387022.png)

---

[![](https://iovhm.com/book/uploads/images/gallery/2025-11/scaled-1680-/tubUHMZzYeplPpw4-image-1762750453788.png)](https://iovhm.com/book/uploads/images/gallery/2025-11/tubUHMZzYeplPpw4-image-1762750453788.png)

[![](https://iovhm.com/book/uploads/images/gallery/2025-11/scaled-1680-/OsAFjuab13dlgqed-image-1762750482607.png)](https://iovhm.com/book/uploads/images/gallery/2025-11/OsAFjuab13dlgqed-image-1762750482607.png)

[![](https://iovhm.com/book/uploads/images/gallery/2025-02/scaled-1680-/MNnEd82VGD1dOkEK-image-1739161960448.png)](https://iovhm.com/book/uploads/images/gallery/2025-02/MNnEd82VGD1dOkEK-image-1739161960448.png)

[![](https://iovhm.com/book/uploads/images/gallery/2025-02/scaled-1680-/q3pmxnbn29h9eDGO-image-1739161972120.png)](https://iovhm.com/book/uploads/images/gallery/2025-02/q3pmxnbn29h9eDGO-image-1739161972120.png)

---

[![](https://iovhm.com/book/uploads/images/gallery/2025-02/scaled-1680-/y2V6eplW30oMHadI-image-1739161925716.png)](https://iovhm.com/book/uploads/images/gallery/2025-02/y2V6eplW30oMHadI-image-1739161925716.png)

[![](https://iovhm.com/book/uploads/images/gallery/2025-02/scaled-1680-/cFN8pKa0BY5ND4ve-image-1739161940710.png)](https://iovhm.com/book/uploads/images/gallery/2025-02/cFN8pKa0BY5ND4ve-image-1739161940710.png)

[![](https://iovhm.com/book/uploads/images/gallery/2025-02/scaled-1680-/H3OEdXn5fWy52LSF-image-1739161987152.png)](https://iovhm.com/book/uploads/images/gallery/2025-02/H3OEdXn5fWy52LSF-image-1739161987152.png)

[![](https://iovhm.com/book/uploads/images/gallery/2025-02/scaled-1680-/6oeXg4x6zFrVbsgW-image-1739161998141.png)](https://iovhm.com/book/uploads/images/gallery/2025-02/6oeXg4x6zFrVbsgW-image-1739161998141.png)

[![](https://iovhm.com/book/uploads/images/gallery/2025-02/scaled-1680-/jexYl3DaWHenfCp3-image-1739162012241.png)](https://iovhm.com/book/uploads/images/gallery/2025-02/jexYl3DaWHenfCp3-image-1739162012241.png)

[![](https://iovhm.com/book/uploads/images/gallery/2025-02/scaled-1680-/U5e9ocEYPsiqoXh2-image-1739162024568.png)](https://iovhm.com/book/uploads/images/gallery/2025-02/U5e9ocEYPsiqoXh2-image-1739162024568.png)

[![](https://iovhm.com/book/uploads/images/gallery/2025-02/scaled-1680-/h5emFEPMbZm2rv1d-image-1739163914598.png)](https://iovhm.com/book/uploads/images/gallery/2025-02/h5emFEPMbZm2rv1d-image-1739163914598.png)

# threejs快速入门

#### 场景

一个电影和动画由若干个片段组成，比如游戏中的一个地图副本，电影里面的一个连贯的动作，进入场景后动画开始播放，播放完成后循环播放或者进入下一个场景。与电影中的下一个场景原理一样

```js

// 创建一个场景
var scene = new THREE.Scene();


```

#### 相机

比如桌子上有一个橘子，使用你的手机摄像头实时预览拍照画面，相机的角度，远近可以影响拍照的内容。

```js

// 相机
var camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
camera.position.z = 5;

// 创建一个正交相机，一般用于2D
var camera  = new THREE.OrthographicCamera(-aspect * 5, aspect * 5, 5, -5, 0.1, 1000);


```

关于相机的三个重要参数： 角度，比如我们大部分游戏是45°角查看，长宽比比例，近景，远景

#### 渲染器

```js


var renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
// 增加到页面
document.getElementById("canva").appendChild(renderer.domElement);



```

#### 精灵

场景中的一切小部件，人，NPC，建筑等。

```
        // 骨架
        var box = new THREE.BoxGeometry(1, 1, 1);
        // 材质
        var material = new THREE.MeshBasicMaterial({ color: 0x00ff00 });
        // 网格蒙皮
        var cube = new THREE.Mesh(box, material);
        // 将立方体添加到场景
        scene.add(cube);

```

**重申：所有的三维都遵循三要素,由网格，材质，贴图格**，然后再渲染出来。因为我们这边是完全程序建模，所以多了一个几何体。

#### 动画

动画实际上是改变元素的一系列属性是使只运动,`requestAnimationFrame`可以在窗口不活动的时候停止运行，setTimeout会一执行，比较耗电

```js
       function animate() {

            requestAnimationFrame(animate);
            cube.rotation.x += 0.01;
            cube.rotation.y += 0.01;
            renderer.render(scene, camera);
        }
        animate();

```

#### 销毁对象

```js

// 清空场景
    scene.traverse((obj) => {
      // console.log("dispose", obj);
      if (obj.geometry) {
        obj.geometry.dispose();
      }
      if (obj.material) {
        obj.material.dispose();
      }
      if (obj.texture) {
        obj.texture.dispose();
      }
      scene.remove(obj);
      obj.geometry = null;
      obj.material = null;
      obj.texture = null;
      obj = null;
    });


```

# threejs的几个常用组件

#### 轨道控制器，OrbitControls

允许用户通过鼠标、触摸屏或键盘操作来旋转、缩放和平移相机，从而从不同角度观察场景。

```js
import { OrbitControls } from "@lib/three-r173/jsm/controls/OrbitControls.js";

  // 创建控制器
  const controls = new OrbitControls(camera, renderer.domElement);
  // // 禁止选中
  controls.enableRotate = false;
  // // 将平移从右键修改为左键
  controls.mouseButtons.LEFT = THREE.MOUSE.RIGHT;

  // 启用触摸控制
  controls.touches.ONE = THREE.TOUCH.PAN; // 单指触摸用于平移
  controls.touches.TWO = THREE.TOUCH.DOLLY_ROTATE; // 双指触摸用于缩

  // 最后，需要在动画循环中一直更新
  // controls.update();


```

#### 可以设置宽度线条

MeshLine 和 MeshLineMaterial 是用于在 three.js 中创建具有宽度和复杂效果的线条的工具，它们通常一起使用，以替代 three.js 内置的 THREE.Line，因为后者无法设置线条宽度

```js

import { MeshLine, MeshLineMaterial } from "three.meshline";

// 创建边框
function createThickLine(points, color, lineWidth) {
  var geometry = new THREE.BufferGeometry();
  geometry.setFromPoints(points.map((point) => new THREE.Vector3(point.x, point.y, 0)));

  var line = new MeshLine();
  line.setGeometry(geometry);

  var material = new MeshLineMaterial({
    color: color,
    lineWidth: lineWidth,
    transparent: true,
    opacity: 1.0,
    blending: THREE.NormalBlending,
    depthTest: false,
    depthWrite: false
  });

  var mesh = new THREE.Mesh(line.geometry, material);
  return mesh;
}



  // 绘制边框
  var line = createThickLine(points, 0x0099ff, 0.05);
  line.position.set(object.x * scale, -(object.y * scale), 0);
  line.renderOrder = 11;
  group.add(line);


```

#### 射线发射器

用于检测鼠标、触摸或其他交互事件与场景中物体的交点。它通过发射光线（Ray）并与场景中的几何体进行相交检测，从而实现诸如鼠标悬停高亮、点击选中物体等功能

```js

  // 创建射线投射器
  var raycaster = new THREE.Raycaster();
  var mouse = new THREE.Vector2();
  // 监听鼠标点击事件
  window.addEventListener("click", onMouseClick, false);


// 监听鼠标事件
function onMouseClick(event) {

    let mouse = _mouse;
    let raycaster = _raycaster;
    let camera = _camera;
    let scene = _scene;

    // 将鼠标位置归一化到[-1, 1]范围
    mouse.x = (event.clientX / window.innerWidth) * 2 - 1;
    mouse.y = -(event.clientY / window.innerHeight) * 2 + 1;

    // 更新射线投射器
    raycaster.setFromCamera(mouse, camera);

    // 计算射线与场景中对象的交集
    var intersects = raycaster.intersectObjects(scene.children, true);

    // 如果有交集，触发回调函数
    if (intersects.length > 0) {
        intersects.forEach(intersected => {
           // 物体被点击了
        });
    }
}


```

# threejs使用canvas绘制文字

在threeejs中显示中文文字还是有点麻烦的，又是要自己转换字体等等巴拉巴，干脆直接用图片代替算了

```js

// 创建文本
function createText(text, fontSize) {
  const scale = 0.01;
  let textLines = text.split("\n");
  if (textLines.length > 1) {
    let textLine2 = textLines[1];
    textLines.splice(1, 1); // 删除原来的元素
    for (let i = 0; i < textLine2.length; i += 7) {
      textLines.push(textLine2.substr(i, 7));
    }
  }

  currentCanvas.value = document.createElement("canvas", { antialias: true });
  const canvas = currentCanvas.value;
  const context = canvas.getContext("2d");
  context.imageSmoothingEnabled = true;
  context.imageSmoothingQuality = "high";

  // 创建2X图以提高文字的清晰度
  const font = fontSize * 2 + "px Arial";
  context.font = font;
  // 计算文字的宽度
  const textMetrics = context.measureText(text);
  canvas.width = textMetrics.width + 20;
  let textLineHeight = fontSize * 2 * 1.2; // 行高约为字体的1.2倍
  canvas.height = textLineHeight * (textLines.length + 1); // 计算有多少行

  // 清除画布
  context.clearRect(0, 0, canvas.width, canvas.height);

  context.font = font;
  context.textAlign = "center";
  context.textBaseline = "middle";
  context.fillStyle = "rgba(255,255, 255, 1)";

  let textY = textLineHeight;
  context.fillText(textLines[0], canvas.width / 2, textY);

  context.fillStyle = "rgba(255,255, 255, 1)";
  // 每行显示7个字符
  for (let i = 1; i < textLines.length; i++) {
    textY += textLineHeight;
    context.fillText(textLines[i], canvas.width / 2, textY);
  }

  // 创建纹理
  const texture = new THREE.CanvasTexture(canvas);
  texture.needsUpdate = true;

  // 创建几何体和材质
  const geometry = new THREE.PlaneGeometry((canvas.width / 2) * scale, (canvas.height / 2) * scale);
  const material = new THREE.MeshBasicMaterial({ map: texture, opacity: 1, transparent: true });

  // 创建网格
  const mesh = new THREE.Mesh(geometry, material);
  return mesh;
}



```

# blender插件

- BoxCutter
-