
TiXL 自定义 Shader 算子完全指南从预设到像素、点、粒子、网格与 SDF 的全流程实战【免费下载链接】t3TiXL is an open source software to create realtime motion graphics.项目地址: https://gitcode.com/GitHub_Trending/t3/t3本文基于 TiXL 官方高级文档 UsingCustomShaders.md 并结合仓库源码编写。Custom Shader Operators自定义 Shader 算子把 TiXL 的预设系统与着色器管线结合在一起让开发者只需要编写一个 shader 函数函数体算子就会自动将其包裹进一个完整的 shader、即时编译并把编译错误直接显示在编辑器里。读完本文你将掌握六个自定义算子CustomPixelShader / CustomPointShader / CustomForce / CustomVertexShader / CustomFaceShader / CustomSDF的输入输出契约、模板机制、内置辅助函数、四元数工具与 Field 采样接口能直接写出可复用的实时特效。六个自定义 Shader 算子一览自 v4.1 起TiXL 提供了六个模板化template-based的自定义 shader 算子覆盖图像、点、粒子、网格与距离场五大场景[CustomPixelShader]— 为纹理的每一个像素计算颜色像素着色器。[CustomPointShader]— 移动、旋转、缩放并给点缓冲中的点着色计算着色器。[CustomForce]— 为粒子系统中的粒子施加自定义力。[CustomVertexShader]— 位移并给网格顶点着色。[CustomFaceShader]— 操作网格三角形包括将三角形炸开分解。[CustomSDF]— 定义一个距离场SDF接入 field / raymarching 管线。在仓库中这些算子的实例分别位于 Operators/Lib/Symbols 目录image/use/CustomPixelShader.t3、point/modify/CustomPointShader.t3、particle/force/CustomForce.t3、mesh/modify/CustomVertexShader.t3、mesh/modify/CustomFaceShader.t3、field/generate/sdf/CustomSDF.t3每个算子的 C# 入口定义在对应的.cs文件中。你完全不需要手写完整 shader 就能开始使用打开Variations变体窗口任选一个预设并调节参数即可。每个算子都带有一组共享参数 ——Offset、A、B、C、D、GainAndBias 和 Gradient—— shader 片段可以直接读取它们。优秀的预设会在代码顶部用注释说明每个参数的含义例如// A: Falloff B: Size方便他人复用。工作原理模板 代码拼接每个算子都拥有一个模板templateshader 文件由TemplateFile参数指定 —— 打开该参数即可看到完整地包裹你代码的 shader 源码。以 CustomPixelShader 为例它的TemplateFile默认值为Lib:shaders/img/use/CustomImageShader-template.hlsl实际文件位于 Operators/Lib/Assets/shaders/img/use/CustomImageShader-template.hlsl。模板负责声明常量缓冲、纹理与辅助函数然后把你的ShaderCode粘贴进其主函数的函数体中// ...template sets up uv, c, p, v etc. ... { //- METHOD ------------------------------------- /*{method}*/ // ← your ShaderCode lands here //---------------------------------------------- } // ...template writes the expected variables back...你的片段操作的是已准备好的局部变量并且需要设置或修改指定的输出变量。除此之外的一切 —— 线程分发、缓冲读写 —— 都由模板处理。AdditionalCode/AdditionalDefines参数会被插入到主函数之上的全局作用域模板中对应/*{defines}*/标记的位置用于放置你自己的辅助函数、常量或声明额外的资源。从源码可以确认这套拼接机制并非魔法在 CustomPixelShader.t3 内部它用ReadFile节点读取模板、用两个SearchAndReplace节点分别把/*{defines}*/替换为AdditionalCode、把/*{method}*/替换为ShaderCode再交给PixelShaderFromSource节点入口点psMain编译。而 CustomImageShader-template.hlsl 中可以看到实际的注册绑定ImageA/ImageB/Gradient分别绑定t0/t1/t2三个采样器Sampler/ClampedSampler/CustomSampler分别绑定s0/s1/s2Offset/A/B/C/D/GainAndBias位于b0常量缓冲目标尺寸在b1并定义了Biased与SampleGradient辅助函数。各算子的输入输出契约下表是六个算子的完整契约 —— 你能拿到什么需要设置什么OperatorRuns per...Prepared variablesYou set / modify[CustomPixelShader]pixelfloat2 uv,int2 PixelCoord,int2 TargetSizefloat4 c— 输出颜色默认为白色[CustomPointShader]pointPoint p,uint idx别名i,float f idx 归一化到 0…1p— 写入结果缓冲[CustomForce]particleParticle p只读,float3 vel,float3 pos,float4 col,float age,float2 uvvel,col,pos— 按Amount混合回去[CustomVertexShader]vertexPbrVertex v,uint vertexIndexv— 写入结果网格[CustomFaceShader]trianglePbrVertex v1, v2, v3,int3 faceIndices,uint faceIndex,float3 pos1, pos2, pos3v1,v2,v3— 作为非共享三角形写入[CustomSDF]field samplefloat3 p,float3 Offset,float A, B, Creturn在p处的有符号距离上述结构体定义struct Point struct Particle struct PbrVertex { { { float3 Position; float3 Position; float3 Position; float FX1; float Radius; float3 Normal; float4 Rotation; // quat float4 Rotation; // quat float3 Tangent; float4 Color; float4 Color; float3 Bitangent; float3 Scale; float3 Velocity; float2 TexCoord; float FX2; float BirthTime; float2 TexCoord2; }; }; float Selected; float3 ColorRGB; };这些结构体在模板的 include 头中定义如 shared/point.hlsl 等。CustomPixelShader逐像素图像处理该算子对目标纹理运行像素着色器。输入ImageA和ImageB绑定为Texture2Dfloat4并带有别名Image和Image2Gradient作为一张 1 像素高的查找纹理。有三个采样器可用Samplerwrap 环绕、ClampedSamplerclamp 钳制和CustomSampler来自CustomSampler输入。除了ShaderCode、AdditionalCode、TemplateFile与共享参数外它的 C# 入口 CustomPixelShader.cs 还声明了Resolution渲染分辨率、TextureFormat输出格式默认R16G16B16A16_Float、GenerateMips、Clear、多输入的ShaderResources额外 SRV、ConstantBuffers额外常量缓冲与CustomSampler自定义采样器并输出TextureOutput与编译后的ShaderCode_。默认代码是一个简单的暗角vignettefloat d 1 - length(uv - 0.5 - Offset * float2(1,-1)); d ApplyGainAndBias(d, GainAndBias); c ImageA.Sample(Sampler, uv); c.rgb * SampleGradient(d).rgb;用一张图位移另一张图displacement// Connect two images and use the Offset parameter float4 cb ImageB.Sample(Sampler, uv); float d Biased(cb.r); c ImageA.Sample(Sampler, uv - d * Offset * float2(1,-1));扩展输入用 [FloatsToBuffer] / [IntsToBuffer] 提供额外常量缓冲用 [SrvFromTexture2d] 提供更多纹理用 [SamplerState] 提供自定义采样器。每个都要在AdditionalCode中声明例如Texture2Dfloat4 Image3 : register(t3);寄存器号从模板已占用之后继续编号。CustomPointShader逐点计算着色器这是一个对连接缓冲的每个点运行一次的计算着色器。p是源点的拷贝你在它里面留下的任何内容都会写入输出。f是点在缓冲中的归一化位置0…1非常适合沿曲线分布点。Time保存按TimeScale缩放的播放时间TotalCount是缓冲大小。默认代码让点沿自身旋转方向移动并用渐变着色float t Biased( frac(f * (B1) A) ); float3 pForward qRotateVec3(float3(0,0,1), p.Rotation); p.Position pForward * (t - 0.5); p.Position.y sin(t * 2 * PI); p.Color SampleGradient(t); p.Scale t;Wave预设 —— 形成波浪的网格点阵int gs sqrt(TotalCount); float2 gpos float2(idx % gs, idx / gs) / gs - 0.5; p.Position float3(gpos.x, 0, gpos.y); float h length(sin(gpos * 8 Offset.xz) * 0.1); p.Position.y h; p.Color SampleGradient(h * 8);程序化生成点同样可行设置Count并让Points输入留空p会从原点处的默认点开始。CustomForce粒子力场它对粒子系统的每个粒子运行一次。你修改局部拷贝vel速度、col颜色和pos位置代码执行后它们按Amount参数混合回粒子。尽量避免直接写pos当你能把变化表达成速度时就表达成速度 —— 位置绕过模拟的速度处理从 CustomForce-Template.hlsl 源码可以看到pos的注释警告它不会应用SpeedFactor。age保存粒子的寿命秒uv是它当前的屏幕空间位置适合把Image输入当作屏幕对齐贴图采样。注意这里的采样器名称是ClampedSampler和WrappedSampler。把粒子从连接的 SDF 场中推出去float d GetDistance(pos); float3 n GetNormal(pos); if (d 0) vel n / (d 1);模板中提供了完整的相机与物体变换矩阵WorldToClipSpace、ObjectToWorld等位于b3常量缓冲可做高级效果内置的PositionToScreenSpaceUv就是利用WorldToClipSpace把世界坐标转成屏幕 uv 的。CustomVertexShader逐顶点网格变形对连接网格的每个顶点运行一次。修改PbrVertex v—— 通常是v.Position、v.Normal或v.ColorRGB。SimpleNoise预设 —— 沿法线随机位移float4 noise hash41u(vertexIndex); v.Position v.Normal * (noise.xyz - 0.5) * Offset * A;按连接的 distance field 着色// A: Falloff B: Size float d GetField(float4(v.Position, 0)).w; float t Biased(smoothstep(1, 0, (d - A) / B)); v.ColorRGB SampleGradient(t).rgb;CustomFaceShader逐三角形分解它对每个三角形运行一次并把三个顶点非共享unshared写回 —— 每个面拥有自己的顶点。这让共享顶点不可能实现的 faceting 效果成为可能整体缩小、旋转或平移整个三角形。pos1–pos3保留原始位置同时你修改v1–v3。按平均高度给面着色float3 avgPos (v1.Position v2.Position v3.Position) / 3; float4 color SampleGradient((avgPos.y Offset.y) * A B); v1.ColorRGB color.rgb; v2.ColorRGB color.rgb; v3.ColorRGB color.rgb;用逐面噪声炸开三角形v1.Position (hash41u(faceIndices.x).xyz - 0.5) * C; v2.Position (hash41u(faceIndices.y).xyz - 0.5) * C; v3.Position (hash41u(faceIndices.z).xyz - 0.5) * C;CustomSDF距离场节点与上面的算子不同[CustomSDF]不作为一个独立 shader 运行—— 它在 TiXL 的shader graph中定义一个节点。你编写一个距离函数的函数体field 管线把它组装进任何采样该场的 shader 中例如 [RaymarchField]或其他 Custom 算子的 Field 输入float dCustom(float3 p, float3 Offset, float A, float B, float C) { // ← your DistanceFunction code; must return the signed distance at p }默认是一个简单球体return length(p - Offset) - A;SinBlobs预设 —— 有机的团块float scale A; float thickness B; float bias C; p * scale; return (abs(dot(sin(p*.5 Offset), cos(p.zxy * 1.23)) - bias) / scale - thickness) * 0.55;一个 GLSL 风格的mod(x, y)宏已预定义这让把 Shadertoy 或 jbaker.graphics 的分形单行代码移植进来变得直接 —— 许多内置预设BoxFold、SpiderCave、PipeMaze 等都来自那里。把辅助函数放进AdditionalDefines。这里没有 Gradient 或 Image—— 距离函数只返回几何用消费它的 field 算子来着色。用 [VisualizeFieldDistance] 可视化结果用 [RaymarchField] 渲染它并用 [BendField]、[TransformField]、[PolarRepeat] 等修改它。在仓库中对应算子位于field命名空间如 CustomSDF.t3更多说明可参考 field 算子文档。在其它算子中使用 Field[CustomPointShader]、[CustomForce]、[CustomVertexShader] 和 [CustomFaceShader] 都有Field输入接受 field 算子 —— 任何来自field命名空间的东西包括你自己的 [CustomSDF]。模板通过以下函数暴露它们FunctionDescriptionGetField(float4 p)采样p.xyz处的连接场返回 rgb 颜色w 距离GetDistance(float3 p)距离值的简写GetFieldNormal(float3 p)归一化的场梯度在 [CustomForce] 中叫GetNormal这让你可以轻松地对任何你在图中构建的 SDF 进行着色、位移或碰撞。以 CustomForce-Template.hlsl 为证GetField函数体里是/*{FIELD_CALL}*/占位符GetDistance取GetField(...).w而GetNormal用 4 个偏移采样点做中心差分求梯度。内置辅助函数以下函数在所有模板类算子中可用[CustomSDF] 除外 —— 它只能看到其 shader-graph 上下文和AdditionalDefines提供的东西NameDescriptionBiased(float f)对 f 应用GainAndBias参数重映射SampleGradient(float f)在 f0…1处采样Gradient参数ApplyGainAndBias(f, gainBias)类似Biased但使用显式的 gain/biasfloat2hash11(f)…hash44(v)快速哈希函数数字 输出/输入分量数例如hash41u(uint)用 uint 种子返回float4在模板源码中可以找到它们的实际实现例如 CustomImageShader-template.hlsl 中Biased就是调用ApplyGainAndBias(f, GainAndBias)SampleGradient用Gradient.SampleLevel(ClampedSampler, float2(f, 0.5), 0)采样hash*系列位于 shared/hash-functions.hlslgain/bias 位于 shared/bias-functions.hlsl。噪声函数cnoise、snoise、curlNoise等包含在 [CustomVertexShader] 和 [CustomFaceShader] 中。对于其它算子可以通过AdditionalCode引入。四元数工具点的旋转以四元数存储。以下辅助函数在所有算子[CustomPixelShader] 除外中可用NameDescriptionParametersqMul两个四元数的标准 Hamilton 乘积float4 q1,float4 q2qRotateVec3用优化公式将 3D 向量按四元数旋转float3 v,float4 qqConjugate返回四元数的共轭取反虚部float4 qqInverse计算四元数的逆float4 qqFromAngleAxis创建绕axis旋转angle的四元数float angle,float3 axisqFromVectors创建从v1到v2的旋转四元数float3 v1,float3 v2qLookAt创建指向forward、以指定up为上的朝向四元数float3 forward,float3 upqSlerp两个四元数之间的球面线性插值float4 a,float4 b,float tqFromEuler将欧拉角yaw, pitch, roll转换为四元数float yaw,float pitch,float rollqToMatrix将四元数转换为 4×4 旋转矩阵float4 quatqFromMatrix3从 3×3 矩阵简化的四元数转换float3x3 mqFromMatrix3Precise从 3×3 矩阵稳健的四元数转换处理所有情况float3x3 m这些函数定义在 shared/quat-functions.hlsl被各模板 include例如 CustomForce-Template.hlsl 第 3 行。示例 —— 让点沿生成的曲线定向来自Knot预设Generator函数定义在AdditionalDefines中p.Position Generator(f); float3 up float3(0,-1,0); float3 fwd normalize(Generator(f - .01) - Generator(f .01)); p.Rotation qLookAt(fwd, up);实战建议打开模板。TemplateFile参数指向完整的 shader 源码 —— 它是关于什么包围着你的代码、哪些寄存器被绑定的权威参考。模板文件与各算子的对应关系可在 Operators/Lib/Assets/shaders 目录中查看如img/use/CustomImageShader-template.hlsl、particles/CustomForce-Template.hlsl、3d/mesh/modify/CustomVertexShader-template.hlsl、3d/mesh/modify/CustomFaceShader-template.hlsl。把预设作为起点。它们就是普通的参数快照保存你自己的预设会连同所有参数一起捕获 shader 代码。给参数写注释。在片段顶部写一行类似// A: Falloff的注释能让预设对其他人更可复用。编译错误会显示在算子上 —— 点击它读取 HLSL 编译器消息行号指向组装后的 shader所以请对照模板查看上下文。进一步阅读Writing code operators —— 当 shader 片段不够用时编写代码算子Shader development example —— 在完整 shader 文件上配合热重载开发相关算子源码入口CustomPixelShader.cs、CustomPixelShader.t3、CustomForce.t3、CustomSDF.t3【免费下载链接】t3TiXL is an open source software to create realtime motion graphics.项目地址: https://gitcode.com/GitHub_Trending/t3/t3创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考