杂谈Unity3D的single channel texture

请尊重原作者的工作,转载时请务必注明转载自:www.xionggf.com 经实测,在Unity3D 2020.2.6f1版本中,在导入纹理的钩子代码中,如果设置TextureImporter.textureType = TextureImporterType.SingleChannel,以及TextureImporterPlatformSettings.format = TextureImporterFormat.R8是一张2048的贴图,导入后其格式 根据Unity的纹理格式文档描述: 当TextureImporter.textureType为TextureImporterType.SingleChannel时,除了R8之外,可选的格式有: 据UWA的人说,R Compressed 4 bit应该是但在本版本的Unity中,其对应的TextureImporterFormat.COM枚举值应该是EAC_R。 根据Unity的纹理格式文档描述: R Compressed EAC 4 bit是一个High-quality compressed R (single-channel) 纹理。一个256x256的纹理,在内存中其大小为32KB。在Android平台下,OpenGLES2.0版本是不支持该格式的,如果指定了该格式,则会自动解压为 【ETC2 fallback】 标签项所指定的纹理格式。 考虑到现在Android手机早就已经是支持OpenGLES3了,所以大胆使用此格式,作为单通道贴图的导入格式。 参考网页 best-texture-format-for-a-single-channel Crunched single channel texture an-introduction-to-texture-compression-in-unity Unity Editor下判断图片是否带alpha通道 Unity 中纹理压缩的方式 – 搁浅の砖厂 Recommended, default, and supported texture formats, by platform C# (CSharp) UnityEditor TextureImporterSettings示例 https://huailiang.github.io/blog/2022/astc/

Animancer的Transition参数手册(翻译)

请尊重原作者的工作,转载时请务必注明转载自:www.xionggf.com 原文地址 Transitions 与其硬编码淡入淡出的持续时间(hard-coding the fade durations),开始和结束时间,动画剪辑的播放速度和动画事件,不如使用transition机制。此机制可以在编辑模式下的可视化地编辑它们。由非程序员在Inspector面板中定义这些细节,无需编辑和重新编译任何脚本。 Animancer中包含的每个State类都有其自己的Transition Type,其中包含与之相关的各种详细信息,以便在将其传递给AnimancerComponent.Play(ITransition)时,这些详细信息可用来创建该State类型。例如,当播放一个AnimationClip对象(即一个动画片段剪辑)时,一个ClipState.Transition将创建一个ClipState实例对象。如下代码所示: using Animancer; using UnityEngine; public class TransitionExample : MonoBehaviour { [SerializeField] private AnimancerComponent _Animancer; [SerializeField] private ClipState.Transition _Animation; private void OnEnable() { _Animancer.Play(_Animation); } } 对应的inspector显示如下图: 这个示例详细演示如何使用transitions。 Fields 字段名字 代码值 inspector截图 Animation Clip Fade Duration FadeDuration Speed Speed Start Time NormalizedStartTime End Time Events.NormalizedEndTime Events Events 各个属性的说明如下表 字段名字 说明 Animation 要播放的那个animation clip Fade Duration 从上一个动画淡入淡出到新动画所需的时间。此值不能为负,并且将其设置为0 sill会使动画立即播放。不管使用哪个字段输入值, 此时间字段始终被序列化为秒 Speed 动画以其正常速度的倍数播放的速度。负值会使它向后播放(因此可能希望将Start Time设置为1x,以便从末尾开始向后播放 Start Time 如果启用,播放时动画时刻将立即跳到该值。否则,它将显示默认值:0x(正速度)或1x(负速度)。如果动画的AnimancerNode.

Animancer的States(翻译)

请尊重原作者的工作,转载时请务必注明转载自:www.xionggf.com 原文地址 State 当播放一段动画剪辑(animation clip)时,Animancer会创建一个ClipState来管理它并跟踪其进度。ClipState是最常见的一种AnimancerState,除此之外,有其他类型的AnimancerState,例如Controller States和 Mixer States。这些用来在一个state中管理多个动画剪辑。 执行AnimancerComponent.Play函数播放一个animation clip,就返回一个AnimancerState对象,如下代码所示: void PlayAnimation(AnimancerComponent animancer, AnimationClip clip) { // Play the animation and control its state: var state = animancer.Play(clip); state.Time = ... state.NormalizedTime = ... state.Speed = ... state.OnEnd = ... } 也可以自己访问和创建状态,而无需立即播放它们: code description var state = animancer.States.GetOrCreate(clip); 访问状态而不播放状态(该Play方法在内部使用此状态)。 var state = animancer.States[clip]; 获取状态(如果存在)(否则为null)。 var state = animancer.States.Create(key, clip); 即使该动画已经存在,也要创建一个新状态。注意必须为每个状态提供不同的key。 var state = new ClipState(animancer, clip); 创建一个新状态而不给它一个Key。可以使用其AnimancerState.Key属性分配一个。 Keys 当用AnimancerComponent.Play方法创建一个state时,这个state存储在一个内部的Dictionary容器中,通过指定某个key,用以在以后用这个key来检索使用该state。 默认地,该state所播放的那段动画剪辑所对应的AnimationClip实例对象,将作为该state的key值 NameAnimancerComponent将重载其GetKey方法,NameAnimancerComponent类不再使用它播放的AnimationClip对象,而是使用这个动画剪辑的名字字符串去作为key。但在启动时,可以在inspector面板中,在Animation中预先注册好这个 void PlayAnimation(AnimancerComponent animancer, AnimationClip clip) { // Trying to play an animation before registering it does nothing.

Unity3D的Animator中的animation transition参数细节

请尊重原作者的工作,转载时请务必注明转载自:www.xionggf.com 选项 描述 Has Exit Time 如果设置为true,则仅在指定的动画剪辑已经播放了给定百分比之后,才启用动画剪辑过渡(transition)。 如果禁用,则将在满足其过渡条件后,立即进行切换。 如果要创建由若干个动画剪辑组成的序列,请将其设置为true。 Exit Time 这是满足“Has Exit Time”选项勾选后,指定的播放动画长度的百分比(0-1范围)。 例如,如果将其设置为0.5,则在播放了50%的动画剪辑后,当满足转换条件后,动画的状态将转换。 Fixed Duration 这个属性将和下一个属性“ Transition Duration (s)”结合使用。如果本选项启用,的财产与下一个过渡期间结合在一起。 如果启用,则Transition Duration (s) 项以秒为单位;如果关闭,则以动画播放时间的百分比表示。 Transition Duration (s) 动画状态过渡所需的时间。 这是从一个动画剪辑过渡到另一个所用的时间。 在过渡期间动画剪辑会被混合在一起。 过渡时间越长,会让动画剪辑转换得更平滑些,否则就转换得更锐利。一个好的默认值是大约0.25。 Transition Offset 选项会把待处理的目标动画开始时刻做偏移。该值以动画剪辑的播放百分比表示。 比如将其设置为0.3。意思是说,当从动画剪辑A过渡到动画剪辑B时,那么A过渡到B之后,会从B的30%处开始播放,而不会从B的开始刻度处开始播放。 Interruption Source 此设置告诉Unity某个动画剪辑过渡。是否可以被其他过渡打断。 例如动画系统下有一个默认的Idle动画,Idle动画有Jump动画分支和Walk动画分支,而Walk动画分支下又有一个Jump1动画分支,当我们同时满足两个Jump动画的切换条件时,Interruption Source就可以判断优先从哪个动画源切换到Jump或Jump1。Interruption Source中四个选项如下表中的几个选项的一个 Interruption Source的各个选项表 选项 描述 None 关闭Interruption Source选项 Current State: 从当前源打断 Next State 从下一个源打断 Current State then Next State 优先从当前源打断,如果当前源不能切换到下一个状态则从下一个源打断。 Next State then Current State 和上一个选项相反 Ordered Interruption If set to false, this lets the transition be interrupted by other transitions independently of their order.

Unity3D的Color Space细节解析

请尊重原作者的工作,转载时请务必注明转载自:www.xionggf.com 参考网页 https://zhuanlan.zhihu.com/p/36507196 https://zhuanlan.zhihu.com/p/93216787 https://blog.csdn.net/candycat1992/article/details/46228771 https://developer.nvidia.com/gpugems/GPUGems3 http://www.klayge.org/2011/02/26/gamma%E7%9A%84%E4%BC%A0%E8%AF%B4/ https://zhuanlan.zhihu.com/p/36507196 https://www.kinematicsoup.com/news/2016/6/15/gamma-and-linear-space-what-they-are-how-they-differ https://zhuanlan.zhihu.com/p/66558476 https://www.cambridgeincolour.com/tutorials/gamma-correction.htm https://zhuanlan.zhihu.com/p/37679604 https://zhuanlan.zhihu.com/p/271011254

Understanding C# async / await 第3章

Understanding C# async / await 第1章原文地址 Understanding C# async / await 第2章原文地址 Understanding C# async / await 第3章原文地址 以下是基于你提供的内容的总结和解读,保留示例代码和关键细节: 理解 C# 的 async / await (3):运行时上下文 1. 概述 在前两篇文章中,我们探讨了 async 和 await 的编译过程和 Awaitable-Awaiter 模式。本文将深入探讨 await 在运行时的上下文处理机制,特别是如何通过 ExecutionContext 和 SynchronizationContext 解决跨线程问题。 2. 跨线程问题 在 WPF 应用程序中,以下代码可以正常工作: this.Button.Click += async (sender, e) => { string html = await new WebClient().DownloadStringTaskAsync("https://weblogs.asp.net/dixin"); this.TextBox.Text = html; }; 但如果将其改写为 Task.ContinueWith() 的回调形式: this.Button.Click += (sender, e) => { new WebClient().

Understanding C# async / await 第2章

Understanding C# async / await 第1章原文地址 Understanding C# async / await 第2章原文地址 Understanding C# async / await 第3章原文地址 理解 C# 的 async / await (2):Awaitable-Awaiter 模式 1. 什么是 Awaitable? 在 C# 中,任何具有 GetAwaiter() 方法的对象都是 awaitable 的。Task 是最常见的 awaitable 类型,但其他类型也可以实现这一模式。例如: Task<int> task = new Task<int>(() => 0); int result = await task.ConfigureAwait(false); // 返回 ConfiguredTaskAwaitable<TResult> ConfiguredTaskAwaitable<TResult> 是一个 awaitable 类型,但它并不是 Task。 2. Awaitable-Awaiter 模式 通过观察不同的 awaitable / awaiter 类型,可以总结出以下规则: Awaitable 对象必须有一个 GetAwaiter() 方法(实例方法或扩展方法)。 Awaiter 对象必须满足以下条件: 实现 INotifyCompletion 或 ICriticalNotifyCompletion 接口。 有一个 IsCompleted 属性,返回布尔值。 有一个 GetResult() 方法,返回 void 或一个结果。 这种模式与 可迭代-迭代器模式(IEnumerable / IEnumerator)非常相似。

Understanding C# async / await 第1章

Understanding C# async / await 第1章原文地址 Understanding C# async / await 第2章原文地址 Understanding C# async / await 第3章原文地址 以下是基于你提供的内容的总结和解读,保留示例代码和关键细节: 理解 C# 的 async / await (1):编译过程 1. 概述 C# 的 async 和 await 关键字为异步编程提供了极大的便利。本文将深入探讨这些语法糖背后的实际代码实现。 2. 准备工作 首先,定义一些辅助方法: internal class HelperMethods { private static void IO() { using (WebClient client = new WebClient()) { Enumerable.Repeat("http://weblogs.asp.net/dixin", 10).Select(client.DownloadString).ToArray(); } } internal static int Method(int arg0, int arg1) { int result = arg0 + arg1; IO(); // 模拟长时间运行的 IO 操作 return result; } internal static Task<int> MethodTask(int arg0, int arg1) { Task<int> task = new Task<int>(() => Method(arg0, arg1)); task.

lua优化经验总结

请尊重原作者的工作,转载时请务必注明转载自:www.xionggf.com 这是我在做一些手游项目时的lua优化经验总结。 注意清空table操作的效率问题 在Lua中,通常要清空一个table,很常见的方法就是直接赋值一个新的空table给指向table的变量:例如: local t = {“I am a table”} t = {} –- 现在t指向的table就是一个空的新建的table了。 这样子虽然逻辑上没什么问题,但t原来指向的那个table实质上就是一个“野table”了,它的何时被清理掉依赖于lua的gc操作。如果t本身就是存储着一些原生数字类型的数组的话,这种={}的清空操作是比较低效的。如果在每帧每秒都被调用的函数中,清空一个既有的table,可以采用以下的代码: -- [[这样子才是全部清空一个table中的所有项,如果将pairs函数改用ipairs函数则只会清空数组项,而不清空hash项]] for i, _ in pairs(t) do -- 不需要kv对中的value值,所以用哑元_代替 t[i] = nil end 利用逻辑判断的短路判定特性优化代码 对于逻辑或(or)操作,只要有一个判断条件为true,则结果为true。逻辑与操作,只要有一个判断条件为false,结果即为false,根据这个特性,在多条件判断时,将获取条件耗费性能最大的函数,挪到最后,尽可能地减少计算。例如: 逻辑与(and)操作,只要有一个判断条件为false,结果即为false。所以对于全逻辑与的操作,在计算判断条件时,应该每计算一次就判断一次,只要有一个为false,就立即得到判定逻辑与计算最终结果为false: 字符串常见问题 和Java,C#,Python等语言类似,一个字符串(对象)对应着一个常量字符串,一旦该字符串声明完毕,其指向的字符串内容即不可更改,所以如果有以下的代码: local s1 = “I” local s2 = “ am” local s3 = “ Lua” local s = s1..s2..s3 在第一个连字符操作完成后,会生成一个匿名的常量字符串,尔后该匿名字符串再和s3进行拼接,再生成一个新的字符串赋值给变量s。也就是说,Lua中的所有字符串,都不会发生“in place”操作,一切会对本字符串的内容发生了修改的操作,必然会导致一个新的字符串的产生。如果是存在着较多的字符串连接操作的话,可以使用table来模拟C#的StringBuilder,如下: -- table.concat函数所处理的表中,表项值只接受字符串和数字 function concat_string(s1,s2,s3,s4,s5,s6) -- 如果预先知道了要拼接多少个字符串,在定义table时可以预先 -- 开好多少个空位而不是直接创建空表,这样子有利于性能提升 local t = {nil,nil,nil,nil,nil} t.name = “I am table t” -- table.

Unity3D动画中Root Motion的概念和使用

请尊重原作者的工作,转载时请务必注明转载自:www.xionggf.com Unity3D的Mecanim动画系统可以直接复用3DS MAX中制作的动画文件中的位移,这个就是通过applyRootMotion选项来达成的,我们只需要在使用Animator控制动画播放的同时,设置Animator组件的applyRootMotion字段为true就可以了。 applyRootMotion,从字面上理解来看,是“应用于根节点的运动”,官方文档的解释如下: The Root Transform is a projection on the Y plane of the Body Transform and is computed at runtime. At every frame, a change in the Root Transform is computed. This change in transform is then applied to the Game Object to make it move. 直接翻译的意思是: root transform是指body transform在在Y平面上的投影(即Y=0的平面,可以理解为模型所站立的“地面”。且这个投影是在运行时执行计算。在每一帧,root transform的每一个变化都会被计算。然后这些变化将会作用到game object上,使得它发生运动 也就是说,root motion就是指:在动画中物体产生的位移,可以在运行时,让绑定了Animator组件的game object,也发生实际的位移。且这个位移,是根据播放动画中每一帧物体的位移,在 X 和 Z 轴上投影计算而得。 对于某些技能动画,整个动画是有一定位移的,但是动画的位移是动作设计师在设计时根据动作需要调出来的,位移是跟动作的幅度直接相关和匹配的。那么在释放技能的时候就只需要直接播放动画,只要应用这个 Root Motion 的特性,就可以很好的完成角色在播放动作的同时进行移动,动作播放完毕之后就在动画结束帧角色所在的位置。而不要额外地做计算工作。接下来看下animation clip inspector面板上若干和root motion有关的属性选项 animation clip inspector 界面上的一些属性介绍 以下是Unity 2019.