当前位置: 首页 > article >正文

自由学习记录(16)

动画相关复习(2)

 如果图片太大,可以拖动摄像机,、,视口范围整体变小

ctrl cv复制整个关键帧的属性

PSD(Photoshop Document)

  1. 文件大小:PSD 是 Photoshop 的标准文件格式,通常最大支持 2GB 的文件大小。
  2. 功能:支持多种图层(如文本图层、形状图层、调整图层等)、通道、路径和其他 Photoshop 特性。
  3. 兼容性:PSD 文件可以在大多数 Photoshop 版本中打开,并且被其他一些图形编辑软件部分支持。

PSB(Photoshop Big Document)

  1. 文件大小:PSB 是专为处理超大文件而设计的,最大支持 4EB(约 4,000 TB)的文件大小。适用于需要高分辨率或大量图层的项目。
  2. 功能:与 PSD 文件相似,支持多种图层、通道等功能,但可以处理更多的内容和更复杂的项目。
  3. 兼容性:PSB 文件的兼容性不如 PSD 文件。它们主要在 Photoshop 中使用,其他软件可能无法完全支持。

 

 

CCD Fabrik Limb

ScreenToWorldPoint

参数

  • Vector3:输入的屏幕坐标(X,Y,Z),其中 X 和 Y 是屏幕像素坐标,Z 是从摄像机到目标的距离(通常使用 nearClipPlanefarClipPlane)。

注意事项

  • 确保 Z 值合理,因为它会影响转换后的深度。
  • 使用此方法时,屏幕坐标的原点在左下角,Y 值通常需要转换。

 

Library是记录你怎么分组的,把哪些图放哪些组里

Library Asset则是对你这整个Library的存储,方便将分组移植到别的上面使用 

Resolver则是管理单个位置的图可以用哪些

 

sr.SetCategoryAndLabel(cate,label);

只用一个psb文件里就有所有图的话想做换装功能,在一个psb里编辑分组然后直接拖到场景上使用就好了,会自动帮你创建Library并且关联你的Asset分组信息,创建你的各个Resolver的部位

各个装备都在同一个文件里 ,可以直接在一个psb里把所有要用的resolver图都安排好位置,共享同一套骨骼

当resolver图在两张或更多不同的psb里,分开使用,想凑到一块时,那就自己手动创建全程,

两个psb里直接复制粘贴骨骼信息,然后就可以直接自己创建Library Asset去定义组,一张一张的关联图片,达到效果

第二种方法更加灵活一点,因为图片都是可以自己一张一张设置的,但是骨骼的同化可能要花点时间,毕竟哪有那么好的事,第一张图的骨骼直接可以复制粘贴到第二张图上啊

C++原生数组增强for

#include <iostream>

int main() {
    int arr[] = {1, 2, 3, 4, 5};
    const int size = sizeof(arr) / sizeof(arr[0]); // 计算数组大小

    // 使用增强for循环遍历原生数组
    for (const auto& element : arr) {
        std::cout << element << " ";
    }
    std::cout << std::endl;

    return 0;
}
  • auto关键字用于自动推导变量的类型。在这里,它会根据arr的元素类型推导出element的类型。
  • 优势:使用auto可以让代码更简洁,不需要显式地指定元素的类型。
  • &表示element是对数组中每个元素的引用,而不是元素的副本。这意味着你对element的操作不会创建额外的副本,直接操作原始数据。
  • 优势:使用引用可以提高效率,尤其是在处理大型对象时,因为避免了不必要的复制。
  • const表示element是一个只读引用,这意味着你不能修改element的值。
  • 优势:使用const可以避免意外修改元素,并使意图更清晰。

 如果使用auto而不加&,例如auto element,则会创建元素的副本,你也可以修改副本,但不会影响原数组中的元素。

去掉const后,你将能够修改元素,但要小心可能会影响原始数组的值。

加不加const和数组没关系,在于每个变量的定义

传入数组参数简化写法

#include <iostream>
#include <vector>

class Node {
public:
    // 指向其他节点的指针数组
    std::vector<Node*> children;

    // 添加一个子节点
    void addChild(Node* child) {
        children.push_back(child);
    }

    // 一次添加多个子节点
    void addChildren(const std::vector<Node*>& newChildren) {
        for (Node* child : newChildren) {
            children.push_back(child);
        }
    }
};

int main() {
    Node node1, node2, node3, node4;

    // 直接在添加子节点时创建vector
    node1.addChildren({ &node2, &node3, &node4 });

    // 输出子节点数量
    std::cout << "Node 1 has " << node1.children.size() << " children." << std::endl;

    return 0;
}

 如果要使用变长参数传入多个节点

#include <iostream>
#include <vector>

class Node {
public:
    std::vector<Node*> children;

    void addChild(Node* child) {
        children.push_back(child);
    }

    // 使用变长模板参数添加多个子节点
    template<typename... Args>
    void addChildren(Args... args) {
        // 将变长参数转为列表,并添加到children中
        (children.push_back(args), ...);
    }
};

int main() {
    Node node1, node2, node3, node4;

    // 使用变长参数一次添加多个子节点
    node1.addChildren(&node2, &node3, &node4);

    // 输出子节点数量
    std::cout << "Node 1 has " << node1.children.size() << " children." << std::endl;

    return 0;
}

c的变长参数的原理

#include <iostream>
#include <cstdarg>

class Node {
public:
    std::vector<Node*> children;

    void addChildren(int count, ...) {
        va_list args;
        va_start(args, count);
        for (int i = 0; i < count; ++i) {
            Node* child = va_arg(args, Node*);
            children.push_back(child);
        }
        va_end(args);
    }
};

int main() {
    Node node1, node2, node3, node4;

    // 使用C风格的变长参数
    node1.addChildren(3, &node2, &node3, &node4);

    std::cout << "Node 1 has " << node1.children.size() << " children." << std::endl;

    return 0;
}

 模版

typename 是 C++ 中的一个关键字,用于指示一个名字是类型(type),尤其是在模板上下文中。它的主要作用是在模板中表明某个参数或嵌套依赖名称确实是一个类型。

用法

模板参数

在模板中,typename 用于定义模板参数。例如:

template<typename T>
void func(T value) {
    // 这里 T 是一个类型参数
}

template<typename ...T>

参数包...T 表示一个参数包,可以接受零个或多个类型。T 是一个类型列表的名字,具体的类型将在使用模板时指定。

#include <iostream>

// 打印任意数量的参数
template<typename... T>
void printValues(const T&... values) {
    (std::cout << ... << values) << std::endl; // C++17 折叠表达式
}

int main() {
    printValues(1, 2.5, "Hello", 'A'); // 可以传递不同类型的参数
    return 0;
}

写了一个process的重载方法,两个重载各有自己的类型模版,

rest...象征着之后所有的参数包起来,一定要是rest和...绑定起来才能用,然后这种包可以用折叠表达式去简化步骤 

...和rest的顺序要注意

 也不可以多加东西

C7518 折叠表达式至少需要 "/std:c++17"

#include <iostream>
#include <string>
#include <type_traits>

// 处理整数
void process(int value) {
    std::cout << "Processing int: " << value << std::endl;
}

// 处理浮点数
void process(double value) {
    std::cout << "Processing double: " << value << std::endl;
}

// 处理字符串
void process(const char* value) {
    std::cout << "Processing string: " << value << std::endl;
}

// 处理字符
void process(char value) {
    std::cout << "Processing char: " << value << std::endl;
}

// 使用参数包处理多个参数
template<typename... K>
void processAll(K... rest) {
    (process(rest), ...); // 使用折叠表达式调用对应的处理函数
}

int main() {
    processAll(1, 2.5, "Hello", 'A'); // 处理多个参数
    return 0;
}

其中 rest 是参数包中的所有元素。这意味着对于参数包中的每个元素,都会调用 process 函数。

识别顺序

  1. 参数包的展开:在调用 processAll 时,假设你传入了多个参数(例如 1, 2.5, "Hello", 'A'),这些参数会被捕获到 rest 中。

  2. 展开顺序:在展开时,折叠表达式会按参数的顺序依次调用 process,所以顺序是从左到右。具体来说,rest 中的第一个元素会首先传递给 process,接着是第二个元素,以此类推。

 (std::cout << ... << values) 是一个左折叠表达式

折叠表达式解析

  1. 折叠表达式结构

    • printValues 函数中,const Args&... values 定义了一个参数包,可以接受任意数量的参数。
    • 当你调用 (std::cout << ... << values) 时,编译器会将 values 中的所有元素逐一展开并应用 << 操作符。
  2. 展开和应用

    • 假设 values 中有多个元素,比如 1, 2.5, "Hello", 'A',展开后会形成:

      std::cout << 1 << 2.5 << "Hello" << 'A'

    • 这是一个连锁操作,所有的 << 操作符都直接连接在一起。
  3. 为什么不能分割

    语法要求:在使用折叠表达式时,... 必须直接放在操作符前面,表示要对整个参数包应用该操作。如果你试图将 ...values 分割开,编译器将无法理解你想要的操作,因为它需要一个明确的上下文来知道要对哪些元素应用操作符。左折叠的特性:左折叠表达式的意义在于从第一个元素开始,依次将操作符应用到后面的元素上。如果你拆分了它,编译器会失去这种结构,无法正确解析。

动画相关复习

点击骨骼针根部,选择其为父骨骼

create bone 右键,就可以脱离

sublime Text打开,这里储存的都是skin相关的东西

右键show in explorer找文件所在位置

进入图片编辑选择的类型

Local Identifier in File

"Local Identifier in File"是指在Unity的资源(如Prefab、材质、动画等)文件中使用的唯一标识符。这个标识符主要用于帮助Unity在不同的场景和项目中识别和管理对象。

主要功能和作用

  1. 唯一性

    • 每个资源文件在Unity项目中都会有一个唯一的Local Identifier。这个标识符确保了即使在不同场景或项目中,Unity也能正确地引用和识别这些资源。
  2. 引用管理

    • 当一个对象在场景中被引用时,Unity会使用Local Identifier来保持对该对象的引用。这使得在场景中的对象可以与资源文件中的对象保持一致,即使它们被移动或重命名。
  3. 数据完整性

    • Local Identifier在序列化过程中非常重要,它确保了在场景加载和资源管理时数据的一致性。通过使用这些标识符,Unity能够正确地处理场景中对象的状态和属性

具体示例

例如,假设你有一个角色Prefab,并在多个场景中使用了它。每次在场景中放置这个Prefab时,Unity都会为该实例分配一个Local Identifier。当你对Prefab进行修改时(例如,更新动画或材质),Unity能够通过Local Identifier识别所有引用了这个Prefab的实例,并确保它们都更新为最新的版本。

注意事项

  • 在版本控制系统中,Local Identifier有时可能导致冲突,特别是在多人协作时。如果一个文件的Local Identifier被修改或丢失,可能会导致场景中引用的对象变得无效。
  • 因此,在管理和协作开发时,确保资源文件的完整性和一致性是非常重要的。

Animation Clip

相关参数

Legacy

  • 定义:Legacy是一个标志,用于指示一个Animation Clip是否应该被视为旧版动画。这通常与Unity的动画系统(Animator)相对。
  • 作用
    • 当你将一个Animation Clip设置为Legacy时,这个Clip会被Unity的旧版动画系统使用,而不是Animator Controller。这意味着它可以直接与Animation组件一起使用。(但现在老版基本上都淘汰完了,放老的系统上播放都放不了)
    • 如果你的项目中使用的是旧版动画,或者需要简单的动画播放,你可以将Animation Clip标记为Legacy。

Wrap Mode

  • 定义:Wrap Mode是控制Animation Clip播放方式的属性,定义了动画结束后如何处理播放。
  • 选项
    • Default:使用Unity的默认设置(很多说default的都是在ProjectSettings里)
    • Once:动画播放一次,然后停止。
    • Loop:动画循环播放,一直重复。
    • Ping Pong:动画在正向和反向之间循环播放。
    • Clamp Forever:动画播放到最后一帧后保持在最后一帧,直到再次播放。(就是一直赖着,像亚里士多德的那个乌龟故事一样,每次都走但就是没走完)

Bounds

  • 定义:Bounds是一个属性,用于定义Animation Clip的空间边界。这通常是一个3D包围盒,表示动画在三维空间中占据的区域
  • 作用
    • Bounds在进行动画预计算和碰撞检测时非常重要。它可以帮助Unity优化渲染和碰撞检测,因为它可以提前计算出动画可能影响的区域。
    • 设置合适的Bounds有助于提高性能,特别是在处理复杂的场景和大量对象时。
  • 使用场景
    • 通常在制作角色动画、粒子效果或任何可能影响场景中对象的位置时,都需要考虑Bounds的设置。

Clip Binding(只是概念)

  1. 绑定的属性

    • Clip Binding允许你指定要动画化的具体属性,比如物体的位置、旋转、缩放、材质属性、音量等。通过绑定这些属性,动画片段在播放时会自动更新这些值。
    • 例如,如果你希望角色的手在动画中挥动,你需要将手部的旋转属性绑定到相应的Animation Clip中
  2. 如何创建和管理绑定

    • 在Unity中,你可以通过Animation窗口来创建和管理Clip Binding。在编辑Animation Clip时,你可以选择要动画化的属性,并为它们添加关键帧。
    • 添加关键帧时,Unity会自动为这些属性生成绑定。你可以通过调整这些关键帧的值,来控制动画在特定时间点的表现。

了解相关的概念

Animation Layers

Animation Layers允许在同一角色上叠加多个动画。

权重和混合

  • 每个层都有一个权重属性,决定了该层动画对最终输出的影响。比如,如果你有一个“行走”层和一个“挥手”层,你可以通过调整挥手层的权重来控制挥手动作的强度。当权重为0时,该层的动画将不会影响角色的运动;当权重为1时,该层的动画完全覆盖在基础层上。
  • 在一个新层上添加“挥手”动画,并设定其权重。这样,当角色在走路时,你可以根据游戏逻辑(例如,玩家按下特定按键)来增加挥手层的权重,使角色在走路时顺便挥手。

Animation Events

Animation Events是功能强大的工具,允许你在动画的特定时间点触发脚本函数。例如,你可以在角色跳跃动画的最高点添加一个事件,来播放音效或者创建粒子效果。

Avatar和Rigging

Avatar是角色的骨架定义,它不仅指定了骨骼结构,还包含了角色的运动方式。Rigging是为模型创建骨骼和关节的过程,使其能够进行动画。Unity中的Avatar系统使得你可以轻松重用动画在不同的角色上,前提是这些角色的骨架结构相似。你可以使用Humanoid Avatar来为人物角色设置标准的动画系统。

Animator Controller

Animator Controller是Unity中的动画状态机,它让你定义不同的动画状态及其之间的过渡。每个状态可以关联一个或多个Animation Clip

Root Motion

Root Motion允许动画中包含的位移信息直接影响角色在场景中的位置。这意味着角色可以随着动画自然地移动,而不是通过脚本手动控制

Procedural Animation

Procedural Animation是一种基于实时计算生成动画的技术。与预制的Animation Clip不同,Procedural Animation能够根据当前的游戏状态动态生成动作。例如,在一个平台跳跃游戏中,角色的跳跃高度可以根据玩家按键的力度进行调整。这样,你可以为角色的运动提供更高的自由度和反应能力。

Animation Compression

Animation Compression技术可以有效地减少Animation Clip的内存占用。Unity提供了不同的压缩选项,比如位置、旋转和缩放的压缩。在选择压缩类型时,可能会影响动画的质量,因此在性能和质量之间需要找到一个平衡点。适当的压缩可以显著提升游戏性能,尤其是在移动设备上。

Spine

Spine 是一个专门用于 2D 动画的工具,广泛应用在 Unity 中。

1. 基本概念

  • 骨骼动画:Spine 通过定义角色的骨骼结构来控制动画。每个部件(例如手、脚、头等)都可以与一个或多个骨骼关联,从而实现精确的运动控制。

  • 插值:Spine 使用插值技术来平滑过渡,允许角色在不同关键帧之间流畅移动。

  • 网格变形:除了简单的骨骼动画外,Spine 还支持网格变形,允许开发者对角色的形状进行细致的调整。

2. Spine 的工作流程

  • 设计角色:在 Spine 中,首先需要创建角色的骨骼结构,然后为不同的部件(如手、脚、衣服等)添加网格。可以从外部图形工具(如 Photoshop 或 Illustrator)导入图像资源

  • 动画制作:使用 Spine 的动画工具,开发者可以通过关键帧设置骨骼的位置、旋转和缩放,制作出各种动画(如走路、跳跃、攻击等)。

  • 导出动画:完成动画后,可以将其导出为 JSON 或 binary 格式,包含动画数据和骨骼信息。

3. 在 Unity 中使用 Spine

  • 导入 Spine 资源:在 Unity 中使用 Spine 时,通常会使用 Spine-Unity 插件。可以通过 Unity 的包管理器或直接从 GitHub 下载并导入。

  • 加载动画:通过代码或编辑器将导出的 Spine 资源加载到 Unity 项目中。Unity 会根据导出的数据自动创建动画控制器

  • 动画控制:可以使用 SkeletonAnimation 组件来播放,停止,切换 Spine 动画

为毛偏要叫这个?

1. “Skeleton”(骨骼)

  • 骨骼动画:这个术语源于3D动画领域,指的是使用骨骼结构来控制角色的动画。在 Spine 中,角色的动画是通过定义骨骼(Skeleton)并将角色的各个部件(如手、脚、头等)附加到这些骨骼上来实现的。

  • 层次结构:骨骼通常是以层次结构组织的,可以通过旋转、移动和缩放骨骼来影响与之连接的部分。这种方式使得动画制作变得更加灵活和高效。

2. “Animation”(动画)

  • 动画效果:SkeletonAnimation 组件的核心作用是播放和管理通过 Spine 创建的动画。这包括对不同动画状态的切换、播放速率的控制事件的触发等。

  • 动态表现:通过 SkeletonAnimation,开发者可以在游戏中实时展示角色的各种动画状态,从而使角色更生动、真实。

4. 动态批处理(Dynamic Batching)

  • Spine 支持动态批处理,可以有效减少 Draw Call,提高渲染效率。

  • 动态批处理是图形渲染中的一种优化技术,旨在减少绘制调用(Draw Calls)的数量,从而提高渲染性能。在 Unity 等游戏引擎中,动态批处理通过将多个小的、相似的物体合并成一个绘制调用来实现。

    绘制调用(Draw Call)

  • 定义:绘制调用是向图形处理单元(GPU)发送渲染指令的请求。每次请求都会导致 CPU 和 GPU 之间的通信因此频繁的绘制调用会降低性能

  • 影响因素:每个独立的物体(如角色、环境模型等)通常需要单独的绘制调用。对于场景中有大量小物体的情况,这种开销会显著增加。

  • 合并渲染数据:动态批处理会在运行时将具有相同材质的物体合并,以减少绘制调用的数量。只有在满足某些条件时,这种合并才会发生,例如:

    • 物体使用相同的材质

    • 物体的变换(位置、旋转、缩放)没有频繁变化

  • 使用顶点缓冲区:合并的物体的顶点数据会存储在一个顶点缓冲区中,这样一次性传送给 GPU,减少了多次调用的开销。

使用条件

  • 相同的材质:物体必须使用相同的材质,这样才能合并在一起。

  • 顶点数量限制:合并的物体的总顶点数通常不能超过 GPU 的限制(在 Unity 中,通常限制在 900 个顶点以内)。

  • 不使用某些特性:一些图形特性(如光照贴图、阴影、透明度等)可能会导致物体不能参与动态批处理。

动态批处理与静态批处理的比较

  • 动态批处理:适用于动态场景中的动态物体,能够在运行时合并物体,适应物体的变化。

  • 静态批处理:适用于不动的物体,通常在场景构建时就已经合并,并在运行时保持不变。静态批处理的合并效率更高,适用于不经常变化的环境元素。

网格(Mesh)

网格(Mesh)是一个由多个顶点(点)、边和面组成的几何体结构,用于表示2D或3D物体的形状。在计算机图形学中,网格是最常见的表示对象的方式。

网格的组成部分:
  1. 顶点(Vertex):网格的基本单位,表示三维空间中的一个点。多个顶点组合形成边和面。

  2. (Edge):连接两个顶点的线段。边可以形成面。

  3. (Face):由三个或多个顶点组成的平面区域。对于3D网格,面通常是三角形或四边形。


http://www.kler.cn/a/374086.html

相关文章:

  • 问:Redis为什么这么快?
  • 摩科智能化一体化防盗门(物联网)项目
  • Android Handler消息机制(五)-HandlerThread完全解析
  • 数据结构-希尔排序(ShellSort)笔记
  • MS01SF1 精准测距UWB模组助力露天采矿中的人车定位安全和作业效率提升
  • 网站安全,WAF网站保护暴力破解
  • 自监督强化学习:对比预测编码(CPC)算法深度解析
  • winSCP使用root账户登录群晖
  • 【AI开源项目】Botpress - 开源智能聊天机器人平台及其部署方案
  • C++STL——list
  • 论文速读:完全测试时域适应(Test-time Adaptation)目标检测(CVPR2024)
  • python 制作 发货单 (生成 html, pdf)
  • 算法效率的计算
  • C++设计模式结构型模式———适配器模式
  • 分类算法——支持向量机 详解
  • CSS 入门:美化网页的魔法
  • Unity3D URP应用与优化详解
  • idea运行maven项目提示jar不存在,但jar实际上是存在的
  • 【网络安全】揭示 Web 缓存污染与欺骗漏洞
  • 聊一聊Qt中的Slider和ProgressBar
  • 【JS学习】04. JS基础语法-函数
  • 一致校验关系一致校验矩阵
  • 渗透测试-百日筑基—文件上传篇特征截断渲染%00绕过——下篇
  • 大数据-200 数据挖掘 机器学习理论 - 决策树 数据集划分 决策树生成 ID3 C4.5
  • Java面试经典 150 题.P55. 跳跃游戏(009)
  • <HarmonyOS第一课>HarmonyOS SDK开放能力简介的课后习题