王小兵 2022-01-19T00:17:40+08:00 spencer.wong@hotmail.com Writing Shader Code for the Universal RP 2021-12-09T00:00:00+08:00 王小兵 https://peakcoder.com/unity/2021/12/09/urp-shader URP中,RenderType可能不太重要了,在内置管线中,是用来做 Replacement Shaders 用的
但是在 URP 中不支持Replacement Shader,尽管有个 ForwardRenderer 的 overrideMaterail
每个Pass标签都需要标记特定的 LightMode,URP使用 single-pass forward renderer
所有只有一个 “UniversalFoward” 的 Pass,也不能同时渲染多个对象
也可以不加Tag,但是会破坏 SRP Batcher
建议在单独的 MeshRender 上使用独立的 Shader 或者材质
或者使用 Forward Renderer 上 overrideMaterial 的 Render Objects 特性

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Unity想弃用CG,推荐使用 HLSL(High level shading language)
不再有 fixed 类型,只有half 和 float
Cg 和 HLSL 被视为相同的语言
如果在 URP 中使用 CG 的标签,将与 URPShaderLibrary 冲突
因为变量和函数会被重复定义
现在请使用 HLSLPROGRAM, HLSLINCLUDE, ENDHLSL
不推荐用CGPROGRAM, ENDCG, CGINCLUDE

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
URP LightMode Tags:
Tags{“LightMode” = “XXX”}
UniversalForward:前向渲染物件之用
ShadowCaster: 投射阴影之用
DepthOnly:只用来产生深度图
Mata:来用烘焙光照图之用
Universal2D :做2D游戏用的,用来替代前向渲染
UniversalGBuffer : 貌似与延迟渲染相关

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Pass 的 Name,应该全大写
可以用 UsePass 来引用
例如:UsePass “Custom/UnlitShaderExample/MyShader”
为了与 SPRBatcher 兼容,所有传递必须共享相同的 UnityPerMaterial CBUFFER
如果不匹配,则出错

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
HLSL 数据类型
bool - true / false.
float - 32位浮点数,用在比如世界坐标,纹理坐标,复杂的函数计算
half - 16位浮点数,用于短向量、方向、颜色,模型空间位置
double - 64位浮点数,不能用于输入输出,要使用double,得声明为一对unit再用asuint把double打包到uint对中,再用asdouble函数解包
fixed - 只能用于内建管线,URP不支持,用half替代
real - 好像只用于URP,如果平台指定了用half(#define PREFER_HALF 0),否则就是float类型
int - 32位有符号整形
uint - 32位无符号整形(GLES2不支持,会用int替代)

vector - 类型可以直接在基础数据后添加维度
例如:float4, half3, int2
访问可以用xyzw或者rgba访问

HLSL数据类型3 – 矩阵
matrix类型可以直接在基础数据后添加 维度 x 维度
例如:float4x4, int4x3, half2x1
即表达 4行4列的float,4行3列的int,2行1列的half
float3x3 m = { 0, 1, 2, 3, 4, 5, 6, 7, 8};
float3 row0 = m[0]; // 0, 1, 2
float r1c2 = m[1][2]; // 5
乘法,使用mul进行
mul(m, row0)
第1个列数必须与第2个行数相同

HLSL数据类型4 – 数组
ShaderLab 材质属性面板 Properties 不支持数组,只能从C#中设置
必须在 Shader 中指定数组的大小,例如
float array[10];
float4x4 array2[10];

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
纹理和采样
定义:
TEXTURE2D(textureName);
SAMPLER(sampler_textureName);
缓存区:
从C#中使用material.SetBuffer 或者 Shader.SetGlobalBuffer
例如:StructuredBuffer buffer;

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
宏(macro)
define MUL2(x,y) ((x)(y))
可以做一些语法糖,例如:
define TRANSFORM_TEX(tex, name) (tex.xy
name##_ST.xy + name##_ST.zw)
o.uv = TRANSFORM_TEX(in.uv, _MainTex) =>
o.uv = (in.uv.xy * _MainTex_ST.xy + _MainTex.ST_zw)

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
每个 Pass, UnityPerMaterial CBUFFER 都是相同的
CBUFFER需要包含所有公用的属性(即与ShaderLab中的Properties相同)
它不能包含其它未公开的属性以及纹理采样器
虽然不需要通过C# material.SetColor/SetFloat等
但多 Material 实例具有不同的值,这会产生问题,SRP Batcher会将他们一起批处理
1、如果您有未公开的变量,请始终使用Shader.SetGlobalColor / Float
以使它们在所有材质实例中保持不变。
2、如果每个材料都不同,则通过Shaderlab属性块将它们公开,然后将它们添加到 CBUFFER 中

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
HLSLINCLUDE
#include “Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl”
CBUFFER_START(UnityPerMaterial) float4 _BaseMap_ST; float4 _BaseColor; CBUFFER_END
ENDHLSL
Core.hlsl文件是URP的内置核心文件
比如如果要使用灯光,则添加 Lighting.hlsl文件

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Vertex Shader 阶段
在内置 Shader 中,使用 UnityObjectToClipPos 将模型空间转换到裁剪空间
URP 中使用 TransformObjectToHClip 函数(在 SpaceTransforms.hlsl 中有定义)
URP 中也可以使用 GetVertexPositionInputs 函数(在Core.hlsh中有定义)
得到的 VertexPositionInputs 结构体包含以下内容
positionWS = positionWorldSpace
positionVS = positionViewSpace
positionCS = positionClipSpace
positionNDC = position in Normalised Device Coordinates
我们可以直接使用上述代码,即便含有未使用到的变量
因为 Shader 编译器会自动对上述代码进行优化
法线 & 切线
VertexNormalInputs normalInputs = GetVertexNormalInputs(IN.normalOS, IN.tangentOS);
GetVertexNormalInputs 将模型空间法线和切线转换为世界空间
包含 normalWS, tangentWS, bitangetWS

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Fragment Shader 阶段
可以使用 SAMPLE_TEXTURE2D 宏进行采样
URP 不支持 Surface Shader
URP 的一些光照文件在 Lighting.hlsl 中
可以用来处理例如 UniversalFragmentPBR

以下代码展示了阴影相关的宏
#pragma multi_compile _ _MAIN_LIGHT_SHADOWS
#pragma multi_compile _ _MAIN_LIGHT_SHADOWS_CASCADE
#pragma multi_compile _ _SHADOWS_SOFT
#include “Packages/com.unity.render-pipelines.universal/ShaderLibrary/Lighting.hlsl”

原文链接

]]>
Unity 构建 Android Custom Gradle 2021-08-02T00:00:00+08:00 王小兵 https://peakcoder.com/unity/2021/08/02/unity-gradle Unity 2019.3之后的 Gradle Project 包含两个module
1] UnityLibrary
包含Unity runtime 和工程数据,是个 Library moudle,可以嵌入到其他android工程
2] Launcher
包含应用名称icon,是application moudle 启动Unity

Unity Custom 配置
1) baseProjectTemplate.gradle => root/build.gradle
顶层的 build.gradle 用于定义适用于项目中所有模块的构建配置

2) launcherTemplate.gradle => root/launcher/build.gradle
模块级build文件,包含有关如何构建 Android 应用程序(bundling、签名、分包)的说明,依赖于 unityLibrary 项目,输出.apk或者.aab

3) mainTemplate.gradle => root/unityLibrary/build.gradle
模块级build文件,输出.aar文件,一般性操作覆盖这个文件就好

4) gradleTemplate.properties => gradle.properties
gradle 属性文件. 可以在其中配置项目全局 Gradle 设置,如 Gradle 守护程序的最大堆大小

5) proguard-user.txt => proguard-unity.txt
构建系统会应用一组适当的规则以使用其内置的缩减工具(如 R8)

6) LauncherManifest.xml => root/launcher/src/main/AndroidManifest.xml

ant maven gradle 都是 java 的构建工具
ant maven 使用 xml
ant 无法管理依赖,maven 使用xml不够简洁
gradle 使用 groovy 或者 kotlin 语言

]]>
UE4入门Roadmap 2021-06-13T00:00:00+08:00 王小兵 https://peakcoder.com/ue4/2021/06/13/ue4-roadmap 1.UE4介绍

UE4介绍 UE4和Unity对比

2.模板介绍和工程创建

安装UE4 创建工程 模块选择, 编辑器介绍

3.Actor操作

Actor介绍(放置,变换,分组,合并) 常见放置Actor 静态网格物体 BSP画刷模式 Landscape地形系统 草地工具

4.蓝图

蓝图介绍 蓝图快速入门指南(Launchpad) 案例-横版游戏 案例-第一人称控制

5.UMG基础+案例

UI创建和显示 UI组件事件绑定 UMG UI设计快速入门指南

6.物理系统和射线

碰撞事件和触发事件 射线检测系统 APEX可破坏网格 第一人称射击游戏

7.动画系统

时间轴 Matinee Sequencer Composure

8.行为树

行为树介绍 行为树节点 行为树快速入门指南

9.材质系统+案例

材质编辑器 基本材质概念 特殊效果(法线贴图,菲涅尔,自发光,彩色半透明阴影 等) 自定义材质函数

10.Paper2D系统

创建Flipbooks 2D物理和动画 2D图集

11.C++脚本基础

C++与蓝图 标签介绍 案例:第一人称射击教程

–EOF–

]]>
URP Tilt-Shift Effect 2021-05-24T00:00:00+08:00 王小兵 https://peakcoder.com/unity3d/2021/05/24/tilt-shift 使用URP + RenderFeature 实现的 Tilt-Shift 移轴摄影效果。github

以上.

–EOF–

]]>
SSD 移动硬盘格式的坑 2021-04-13T00:00:00+08:00 王小兵 https://peakcoder.com/ssd/2021/04/13/ssd 因为穷,个人 MBP 的硬盘只有256G,故狗东买了一块闪迪 1TSSD 移动硬盘作为辅助存储.

公司用PC,回家 MacBook,初衷是两种OS可以读写. 以下是我在选择硬盘格式时候遇到的一些坑.

1] 一开始使用的 exFAT 格式

因为这格式倆 OS 都可直接读写.但在拷贝一个Unity工程到硬盘的时候,发现在 NTFS 60G 到移动硬盘里变 400 多G了,靠北!我可只有1个T而已啊. 一番google之后发现:32G 以上的 exFAT 格式硬盘默认簇大小128K,即使大小不到1K的文件也要占128K. 又Unity工程文件全是细碎小文件,故膨胀至此.

2] 使用 NTFS

NTFS簇只有4K,应该就不会浪费空间了.在使用Mounty啊之类的软件之后Mac也能写硬盘.似乎..完美了. 但当老夫发现无法在硬盘打开创建Unity工程!提示The project is on case sensitive file system.Case sensitive file systems are not supported at the moment.Please move the project folder to a case insensitive file system. 又一番google,好吧,NTFS是大小写敏感的,只是Win默认关闭了. 在Mac上大小写敏感,而且还关不掉,汗,只能放弃这格式了.

3] 再使用的 exFAT 格式

算了还是使用exFAT吧,因为之前检索发现 exFAT 直接使用4K簇大小,只要容量不超过16T也是可以的.但默认格式化的时候最小簇只能设 64K 微软太恶意了! 能不能把簇改小呢?又双叒叕一番google发现对于系统自带的format命令行格式化程序则没有对exFAT文件系统施加任何人为限制,那么解决方案自然就是:先以管理员身份运行CMD命令提示符,注意空格输入:Format X: /FS:exFAT /Q /A:4096 /Y 即可将任意类型的盘快速格式化为exFAT-4K簇,其中X:为要格式化卷的盘符,/A:参数为自行指定一个簇大小.或者直接使用DiskGenius等第三方软件来格式化为exFAT也是可以的.

似乎又完美了,都可读写,速度也没有太影响.

但天不遂人愿,又有新的问题,因为只能在 NTFS 格式硬盘上创建软连接,所以在 exFAT 格式的盘上,Unity2019package 全都会拷一份到项目内. 这也还好了,因为用Mac APFS 也一直如此,但只会拷贝一次,第二次打开就很快了.但是 WinexFAT 的硬盘,Unity每次都会拷贝!很慢啊,这绝对 Unity bug,太恶心了,但也只能 file a bugUnity 解决了,没啥办法,哎.

以上.

–EOF–

]]>
新应用「晴书」发布 2020-12-24T00:00:00+08:00 王小兵 https://peakcoder.com/%E7%8B%AC%E7%AB%8B%E5%BC%80%E5%8F%91/2020/12/24/new-app

虽说苹果爸爸圣诞放假暂停审核,但还是在平安夜approve了,ready for sale. 欢迎大家下载。

PS: 开发此App的动机之一是为了泡姑娘,估计追不到了…

–EOF–

]]>
Unity3d gradle 编译后处理 2020-12-14T00:00:00+08:00 王小兵 https://peakcoder.com/android/2020/12/14/gradle-copy-file Unity 可以在 Android 目录直接放置 java 源文件,加上自定义 gradle 配置文件,使得接入第三方的 SDK 变得十分优雅。 Unity 使用 gradle 编译,直接导出 apk ,会在 tmp 文件下面先导出名为 gradleOut 的 android studio 工程。 在 as 工程导出后、编译前,可以做一些文件拷贝处理等工作,例如在接入 Firebase SDK 时需要拷贝 json文件到 launcher 目录。 代码入下:

using UnityEditor;
using UnityEditor.Android;
using UnityEngine;
using System.IO;
public class AndroidPostBuildProcessor : IPostGenerateGradleAndroidProject
{
    public int callbackOrder
    {
        get
        {
            return 0;
        }
    }
    void IPostGenerateGradleAndroidProject.OnPostGenerateGradleAndroidProject(string path)
    {
        Debug.Log("Bulid path : " + path);
        path = path.Replace("unityLibrary", "launcher");
        var json = path + "/google-services.json";
        File.Copy("Assets/Plugins/Android/google-services.json", json);
    }
}

–EOF–

]]>
Android ANR 2020-10-14T00:00:00+08:00 王小兵 https://peakcoder.com/android/2020/10/14/android-anr ANR全称:Application Not Responding,也就是应用程序无响应。 logcat 定位不到具体哪个线程导致 ANR,可以通过 ANR 日志分析来定位问题。

当app出现ANR时会在data/anr/目录下生成traces.txt日志文件。每次发生ANR时都会删除旧的traces文件,重新创建新文件。Android只保留最后一次发生ANR时的信息。 可以使用adb命令导出traces文件:

adb pull /data/anr/traces.txt

默认导出文件路径在 adb 命令行运行的当前的目录。

一般trace文件顶部的线程即为ANR的原因。

–EOF–

]]>
NavMeshAgent SetDestination Error 2020-06-18T00:00:00+08:00 王小兵 https://peakcoder.com/unity3d/2020/06/18/navmesh-bug 使用 NavMeshAgentSetDestination函数,一直报错 "SetDestination" can only be called on an active agent that has been placed on a NavMesh. 导致寻路失败。

导航网格生成完好,Destination的点使用 NavMesh.SamplePosition 验证过,也定会在可行走区域内。

Debug许久未果,后在Unity Forum找到答案。

If you create a NavMeshAgent and set its position via transform.position=... and then try to SetDestination, it fails because the NavMeshAgent did not recognize the position change and does not know that it already is on the NavMesh. Use NavMeshAgent.Warp instead of transform.position to initialize the position before calling SetDestination.

开始时直接使用transfrom.poistion赋值,agent未识别位置变化,不知道自己已在导航网格之上,可在初始时调用Wrap函数来初始化agent的位置。

示例代码如下:

agent.Warp(tank.BornPosition);

–EOF–

]]>
Unity Tips (#2) 2020-06-08T00:00:00+08:00 王小兵 https://peakcoder.com/unity3d%20tips/2020/06/08/unity-tips-2 使用 ContextMenu Attribute 不运行 Unity, 执行 MonoBehavior 函数 示例代码如下:

[ContextMenu("ResizeDialogueText")]
private void ResizeDialogueTextHeight()
{
	var height = dialogueText.preferredHeight;
	var size = dialogueBgRect.sizeDelta;
	size.y = height + 60f;
	dialogueBgRect.sizeDelta = size;

	var pos = dialogueText.transform.localPosition;
	pos.y = height + 30f;
	dialogueText.transform.localPosition = pos;
}

Diagram

–EOF–

]]>