Unity Shader开发:非等比缩放下的法线变换原理与实战避坑指南
1. 项目概述一个被忽视的“经典”陷阱如果你在Unity里做过稍微复杂一点的Shader特别是涉及到自定义光照模型或者顶点/片元着色器那么“法线扭曲”这个问题你大概率遇到过或者即将遇到。表面上看模型在非等比缩放比如Scale是(2, 1, 1)时光照变得诡异高光位置错乱模型表面像是被“拧”过一样。新手的第一反应往往是去检查法线贴图、检查光照计算折腾半天最后发现根源在一个看似人畜无害的矩阵上unity_ObjectToWorld。这个问题之所以“经典”是因为它几乎每个Shader开发者都会踩坑但又因为Unity内置的UnityObjectToWorldNormal等函数帮我们处理了大部分情况导致很多开发者知其然而不知其所以然。一旦你需要自己操作模型空间到世界空间的变换比如处理顶点动画后重新计算法线、或者在某些定制化渲染管线中这个坑就会突然出现让你调试到怀疑人生。今天我们就来彻底拆解这个陷阱不仅告诉你“怎么做”更要讲清楚“为什么”让你下次遇到时能一眼看穿本质。2. 核心原理为什么非等比缩放会让法线“跑偏”要理解这个陷阱我们必须先抛开代码从图形学最基础的数学原理说起。这能帮你建立牢固的直觉以后遇到类似问题都能举一反三。2.1 法线的本质垂直于切平面的向量首先我们明确一点法线Normal不是一个普通的“位置”或“方向”向量。它定义了一个表面的朝向具体来说是垂直于该点处曲面的切平面的向量。在模型导入Unity时每个顶点除了位置Position信息都附带了一个法线向量这个向量是在模型空间Object Space中定义的。当我们说“将物体从模型空间变换到世界空间”时对于顶点的位置Point我们使用的是仿射变换这通常由一个4x4矩阵即unity_ObjectToWorld完成它包含了旋转Rotation、缩放Scale和平移Translation。平移很好理解就是直接加一个偏移量。但对于法线事情就变得微妙了。2.2 缩放变换的“破坏性”为何不能直接乘矩阵想象一个简单的二维例子一个正方形其表面法线朝上向量(0, 1)。现在我们仅沿X轴放大2倍正方形变成了长方形。对于顶点位置直接乘以一个缩放矩阵[2, 0; 0, 1]是正确的。但是对于那个朝上的法线(0, 1)呢如果我们也天真地乘以同一个缩放矩阵会得到(0, 1) —— 看起来没变这是因为我们的例子太特殊了。考虑一个倾斜的平面其模型空间法线为(1, 1)经过同样的非等比缩放矩阵变换后会变成(2, 1)。这个新的向量还垂直于被拉伸后的表面吗通过点积计算就会发现它不再垂直于表面切线了。核心结论直接使用变换顶点位置的矩阵即unity_ObjectToWorld来变换法线在存在非等比缩放Non-uniform Scale的情况下会破坏法线与表面的垂直关系。这是因为缩放变换不是保角的Angle-preserving。2.3 正确的数学工具逆转置矩阵Inverse Transpose那么如何找到一个矩阵M使得变换后的法线n仍然垂直于变换后的表面这需要从切向量的变换推导。设表面在某点处的切线向量为t法线为n满足n·t 0点积为零表示垂直。设变换顶点位置的矩阵为M。变换后的切线t M * t。我们需要找到一个矩阵G来变换法线使得n · t 0其中n G * n。将t和n代入(G * n) · (M * t) 0根据点积与矩阵乘法的关系可以推导出(G * n)^T * (M * t) n^T * G^T * M * t 0。 因为对于原始的垂直关系有n^T * t 0所以要使得上式对任意符合条件的n和t都成立就需要G^T * M I单位矩阵即G (M^{-1})^T。这就是黄金法则用于变换法线的正确矩阵是变换顶点位置矩阵的逆矩阵的转置矩阵Inverse Transpose。在只有旋转和等比缩放的情况下矩阵M是一个正交矩阵旋转乘以一个标量等比缩放此时其逆的转置等于其自身再除以缩放系数的平方。但一旦缩放是非等比的M就不是正交矩阵了(M^{-1})^T与M就截然不同。这就是陷阱的数学根源。3. Unity中的实践与陷阱拆解理解了原理我们再看Unity的具体实现。Unity的Shader内置了很多变量和函数其中就藏着解决方案和陷阱。3.1unity_ObjectToWorld的“三列”本质在Unity Shader中unity_ObjectToWorld是一个float4x4矩阵。它直接将模型空间坐标变换到世界空间。我们可以将其理解为三列基向量和一个平移向量前三列分别代表了模型空间X轴、Y轴、Z轴在世界空间下的指向和缩放长度。第四列代表了模型原点在世界空间中的位置平移。当你写worldPos mul(unity_ObjectToWorld, float4(posOS, 1.0));时正是在进行这个标准的仿射变换。陷阱1直接用于法线变换最直接的坑就是worldNormal mul((float3x3)unity_ObjectToWorld, normalOS);。正如原理部分所述这在非等比缩放下会导致错误。你会得到一个长度和方向都可能出错的世界空间法线。3.2 Unity提供的“安全网”UnityObjectToWorldNormalUnity在UnityCG.cginc等头文件中提供了辅助函数来避免这个坑。最常用的就是UnityObjectToWorldNormal。我们来看一下它的典型实现不同版本可能略有差异但思想一致// 简化后的核心思想 float3 UnityObjectToWorldNormal(float3 normalOS) { // 使用 unity_WorldToObject 矩阵的逆转置部分即3x3子矩阵来变换法线 return normalize(mul(normalOS, (float3x3)unity_WorldToObject)); }注意这里的mul参数顺序是mul(normalOS, matrix)这意味着我们是将法线作为行向量与矩阵相乘这等价于将法线作为列向量与矩阵的转置相乘。而unity_WorldToObject是unity_ObjectToWorld的逆矩阵。所以(float3x3)unity_WorldToObject的转置正好就是(float3x3)unity_ObjectToWorld的逆。这完美符合了我们之前推导的(M^{-1})^T公式。关键点这个函数内部已经帮你处理了逆转置操作并且进行了归一化normalize。归一化很重要因为即使方向正确了缩放也可能改变法线的长度而光照计算通常需要单位向量。3.3 隐藏陷阱何时安全网会失效既然有UnityObjectToWorldNormal为什么我们还会掉坑里因为安全网有覆盖不到的地方。陷阱2自定义顶点变形后的法线这是最常见的实战踩坑场景。比如你在顶点着色器中写了一段波浪动画v.vertex.xyz waveOffset; // 在模型空间修改了顶点位置此时顶点位置已经不再是原始模型位置了。如果你简单地使用UnityObjectToWorldNormal(v.normal)它只会基于原始的、未变形的模型形状和原始的unity_ObjectToWorld矩阵来计算法线变换。但对于变形后的新表面其切平面已经改变因此法线也需要重新计算。正确的做法是在模型空间内根据变形后的新顶点位置重新计算或近似计算新的模型空间法线然后再用UnityObjectToWorldNormal转换到世界空间。对于简单的波形可以通过对波形函数求导来得到新的切线/法线对于复杂变形可能需要传递切线/副切线并重新构造TBN矩阵。陷阱3直接使用unity_WorldToObject的3x3部分有些教程或代码中你会看到这样的写法mul((float3x3)unity_WorldToObject, normalOS)。注意这和UnityObjectToWorldNormal的内部实现mul(normalOS, (float3x3)unity_WorldToObject)是不同的前者是法线作为列向量乘以unity_WorldToObject的3x3部分这实际上是错误的方向。它相当于用M^{-1}而不是(M^{-1})^T去乘法线。只有在等比缩放且无旋转的极端情况下两者结果才偶然相同。陷阱4忽略归一化Normalize即使你用了正确的逆转置矩阵变换得到的法线向量可能也不是单位长度。在非等比缩放下各个轴缩放系数不同变换后的法线长度会发生变化。而像dot(N, L)这样的光照计算要求向量是单位向量否则会导致光照强度错误。因此在片段着色器中使用变换后的世界法线前务必确保其是归一化的。UnityObjectToWorldNormal内置了归一化但如果你是自己构造矩阵变换千万别忘了这一步。陷阱5在Surface Shader中误操作Unity的Surface Shader帮你封装了很多细节。其输入结构Input中的worldNormal字段如果你使用了INTERNAL_DATA宏它会在背后正确计算。但如果你在surf函数之外或通过其他方式手动干预了顶点数据却没有同步更新相关的内部数据如worldNormal或worldTangent也可能导致法线错误。通常在Surface Shader中除非必要应尽量使用其内置的数据流。4. 实战解决方案与代码剖析理论说再多不如一行代码。下面我们针对不同场景给出具体的解决方案和代码片段。4.1 标准情况使用内置函数对于绝大多数不需要顶点变形的标准着色器最佳实践就是无条件使用Unity提供的内置函数。在顶点着色器中计算并传递struct appdata { float4 vertex : POSITION; float3 normal : NORMAL; }; struct v2f { float4 pos : SV_POSITION; float3 worldNormal : TEXCOORD0; }; v2f vert (appdata v) { v2f o; o.pos UnityObjectToClipPos(v.vertex); // 变换顶点到裁剪空间 // 正确且安全的法线变换 o.worldNormal UnityObjectToWorldNormal(v.normal); return o; } fixed4 frag (v2f i) : SV_Target { // 确保在片段着色器中使用单位向量虽然顶点着色器已归一化但插值后长度可能不为1 float3 N normalize(i.worldNormal); // ... 后续光照计算 }这是最省心、最不容易出错的方式。4.2 自定义顶点变形后的法线重计算假设我们在模型空间Y轴方向做了一个正弦波变形v2f vert (appdata v) { v2f o; // 1. 顶点变形模型空间 float wave sin(_Time.y * _WaveSpeed v.vertex.x * _WaveFrequency) * _WaveAmplitude; float4 modifiedVertex v.vertex; modifiedVertex.y wave; // 2. 变换变形后的顶点到裁剪空间 o.pos UnityObjectToClipPos(modifiedVertex); // 3. 重新计算模型空间法线近似 // 对波形函数求导得到Y方向变化相对于X的斜率即切线向量的变化 // dy/dx cos(_Time.y * _WaveSpeed v.vertex.x * _WaveFrequency) * _WaveFrequency * _WaveAmplitude float slope cos(_Time.y * _WaveSpeed v.vertex.x * _WaveFrequency) * _WaveFrequency * _WaveAmplitude; // 原始法线假设为 (0,1,0)。变形后表面在X方向有倾斜所以新法线需要反映这个倾斜。 // 一个简化的近似新法线在X方向的分量与斜率相反并重新归一化。 float3 modifiedNormalOS normalize(float3(-slope, 1.0, 0.0)); // 注意这是一个极度简化的模型仅适用于特定方向的波形。更通用的方法需要切线/副切线。 // 4. 将重新计算的法线变换到世界空间 o.worldNormal UnityObjectToWorldNormal(modifiedNormalOS); return o; }对于更复杂的变形你需要使用顶点着色器中可用的切线TANGENT和副切线通过叉积计算来重新构造模型空间的TBN矩阵然后变换法线。这涉及到更复杂的微积分或数值方法通常用于水面、布料等复杂模拟。4.3 手动构造逆转置矩阵在某些极少数情况下你可能需要自己构造变换矩阵例如使用自定义的变换矩阵而非unity_ObjectToWorld。这时你必须手动处理逆转置。// 假设我们有一个自定义的模型到世界矩阵 myObjectToWorld float4x4 myObjectToWorld ...; // 可能包含非等比缩放 // 手动计算用于法线变换的3x3逆转置矩阵 float3x3 myObjectToWorldNormal transpose((float3x3)inverse(myObjectToWorld)); // 注意在Shader中直接计算inverse(4x4)性能开销较大应尽量避免。 // 更高效的做法是如果myObjectToWorld是从脚本传递的最好在CPU端计算好逆转置矩阵再以uniform传入。 // 变换法线 float3 worldNormal normalize(mul(myObjectToWorldNormal, normalOS));重要提示在Shader中实时计算inverse和transpose对于4x4矩阵是非常昂贵的操作绝对不推荐在每顶点或每片段中执行。正确的做法是在C#脚本中计算好这个逆转置的3x3矩阵然后通过Material.SetMatrix或Shader.SetGlobalMatrix传递给Shader。// C# 脚本端 Matrix4x4 objectToWorld transform.localToWorldMatrix; Matrix4x4 worldToObject transform.worldToLocalMatrix; // 用于法线变换的矩阵是 worldToObject 的转置 (3x3部分) Matrix4x4 normalMatrix worldToObject.transpose; // 或者直接计算逆转置: (objectToWorld.inverse).transpose // 传递给Shader material.SetMatrix(_NormalMatrix, normalMatrix);然后在Shader中使用float3 worldNormal normalize(mul((float3x3)_NormalMatrix, normalOS)); // 或者等价的行向量乘法 // float3 worldNormal normalize(mul(normalOS, (float3x3)_WorldToObject));5. 诊断、调试与常见问题排查当你怀疑法线出了问题可以按照以下步骤进行诊断和调试。5.1 视觉化调试法线最直接的调试方法是将世界空间法线作为颜色输出。因为法线分量范围在[-1, 1]而颜色范围在[0, 1]需要映射fixed4 frag (v2f i) : SV_Target { float3 N normalize(i.worldNormal); // 将法线从[-1,1]映射到[0,1]以便显示 fixed3 color N * 0.5 0.5; return fixed4(color, 1.0); }正常情况一个均匀的球体法线颜色应该从中心到边缘平滑渐变。非等比缩放问题如果一个立方体在X轴缩放2倍你会发现法线颜色在拉伸的面上不均匀或者不同面的交界处颜色不连续这直接表明了法线方向错误。5.2 常见问题速查表问题现象可能原因排查步骤与解决方案光照随视角旋转而“滑动”或闪烁法线未归一化在片段着色器中在片段着色器中添加normalize(i.worldNormal)。注意在顶点着色器归一化后经过线性插值在片段着色器中长度不一定为1。非等比缩放物体光照完全错误高光错位使用了错误的矩阵变换法线如直接用unity_ObjectToWorld检查法线变换代码确保使用了UnityObjectToWorldNormal或等效的逆转置矩阵乘法。自定义顶点动画后光照错误动画后未重新计算法线在模型空间根据变形后的几何体重新计算法线方向然后再进行世界空间变换。使用法线贴图后效果怪异切线空间basisTBN矩阵构建错误或未考虑非等比缩放确保在变换切线Tangent和副切线Bitangent时也使用了正确的逆转置矩阵或使用UnityObjectToWorldDir并与法线保持正交化。通常使用UnityObjectToWorldDir变换切线和副切线并用世界法线叉积重新计算副切线以保证正交。Surface Shader中手动计算的光照与标准光照模型不符可能覆盖或错误设置了SurfaceOutput中的法线在Surface Shader中尽量让Unity自动处理法线。如需自定义请仔细查阅文档确保正确赋值o.Normal。5.3 性能考量与最佳实践归一化的位置在顶点着色器中进行法线变换和归一化然后在片段着色器中再次归一化这是标准做法。顶点着色器归一化减少插值误差片段着色器归一化保证精确性。虽然有些性能开销但对于高质量渲染是必要的。避免动态逆矩阵计算绝对不要在Shader中为每个顶点或片段计算inverse(matrix)。所有逆矩阵、逆转置矩阵都应在CPU端预先计算好。善用内置变量和函数UNITY_MATRIX_IT_MV是模型视图矩阵Model-View的逆转置矩阵常用于将法线变换到观察空间Eye Space。在需要观察空间法线时直接使用它比你自己计算更高效、更安全。对于静态批处理物体静态批处理会合并多个物体的顶点数据其unity_ObjectToWorld矩阵可能不再是单个物体的变换矩阵。但Unity会处理好这一点UnityObjectToWorldNormal等函数在静态批处理下仍然有效。如果你自己手动处理矩阵则需要额外小心。6. 延伸思考切线Tangent与副切线Bitangent的变换法线不是唯一需要特殊对待的向量。当使用法线贴图时我们需要构建一个从切线空间到世界空间的变换矩阵TBN矩阵。这个矩阵由世界空间的切线T、副切线B和法线N组成。切线Tangent它本质上是沿着纹理U方向的方向向量。和法线不同切线是一个方向向量但它的变换规则与法线相同吗不完全是。严格来说切线与表面上的一个方向场相关它的变换应该使用与法线相同的逆转置矩阵以确保它与法线在变换后保持正确的正交关系用于构建正确的切空间。在Unity中我们通常使用UnityObjectToWorldDir(v.tangent.xyz)来变换切线这个函数内部处理了方向向量的变换去除了平移但保留了缩放和旋转的影响。对于非等比缩放为了与正确变换的法线构建正交基有时需要重新正交化。副切线Bitangent通常不直接从模型数据传入而是在Shader中通过法线和切线的叉积计算得出bitangent cross(normal, tangent) * v.tangent.w。这里的v.tangent.w是用于决定副切线方向即纹理V方向的符号。关键点在变换到世界空间后更稳健的做法是使用变换后的世界法线N和世界切线T重新计算世界副切线Bfloat3 worldBitangent cross(worldNormal, worldTangent) * tangent.w;。这能确保在世界空间中TBN矩阵仍然是正交的即使原来的变换包含了非等比缩放。因此一个健壮的、支持非等比缩放的法线贴图TBN矩阵构建代码片段如下v2f vert (appdata_tan v) { // 使用包含切线的appdata结构 v2f o; o.pos UnityObjectToClipPos(v.vertex); o.worldNormal UnityObjectToWorldNormal(v.normal); o.worldTangent UnityObjectToWorldDir(v.tangent.xyz); // 变换切线 o.tangentSign v.tangent.w; // 存储副切线方向符号 return o; } fixed4 frag (v2f i) : SV_Target { float3 N normalize(i.worldNormal); float3 T normalize(i.worldTangent); // 重新计算副切线确保与法线、切线正交 float3 B cross(N, T) * i.tangentSign; // 构建从切线空间到世界空间的3x3矩阵 float3x3 TBN float3x3(T, B, N); // 从法线贴图中采样切线空间法线 float3 normalTS UnpackNormal(tex2D(_BumpMap, i.uv)); // 转换到世界空间 float3 worldNormalFromMap mul(TBN, normalTS); // 使用 worldNormalFromMap 进行光照计算 }这个陷阱的解决标志着你从Shader的“使用者”向“理解者”迈进了一步。它背后是线性代数与图形学基本概念的紧密结合。下次当你看到模型在拉伸下光照怪异时你会立刻意识到哦是法线变换矩阵没用好。这种透过现象看本质的能力正是资深图形程序员与初学者的分水岭。在实际项目中我个人的习惯是只要涉及自定义的空间变换就会立刻条件反射般地思考这个变换矩阵是否保角我的法线、切线应该用什么矩阵来变养成这个思维习惯能帮你避开渲染中一大类难以察觉的视觉错误。

相关新闻

C#转Java高效迁移:easy-query工具实战解析

C#转Java高效迁移:easy-query工具实战解析

1. 为什么需要从C#迁移到Java的技术栈转换工具?在软件开发领域,技术栈迁移是常见需求。我见过不少团队从C#转向Java,原因多种多样:可能是客户要求使用Java技术栈,也可能是为了利用Java生态的某些特定优势。但无论原因如…

2026/10/13 16:19:12 阅读更多 →
CAN总线函数解析

CAN总线函数解析

一、初始化与配置 函数原型功能说明void CAN_DeInit(CAN_TypeDef* CANx)将指定的 CAN 外设(CAN1 或 CAN2)恢复为默认复位状态,禁用时钟并重置所有寄存器。uint8_t CAN_Init(CAN_TypeDef* CANx, CAN_InitTypeDef* CAN_InitStruct)根据 CAN_In…

2026/10/13 16:18:44 阅读更多 →
react navite权限处理:相机、定位、相册、推送权限

react navite权限处理:相机、定位、相册、推送权限

React Native 做相机、定位、相册、推送权限管理,推荐不要自己封装 Native 权限,而是统一使用: react-native-permissions 它统一封装 iOS / Android 权限申请、检查、跳转设置等流程。(NPM) 整体流程: 用户操作↓ 业务功能触…

2026/10/5 15:15:21 阅读更多 →

最新新闻

Python金融科技实战:量化回测、风控模型与工程化落地

Python金融科技实战:量化回测、风控模型与工程化落地

先说个背景。我前两年参与过一个从零搭建的量化信号系统的项目,技术栈里最核心的就是 Python。那段时间接触了不少金融科技方向的案例和团队,越来越感觉 Python 在 FinTech 里几乎是无处不在的。无论是量化交易、风险模型、信贷风控,还是财报…

2026/10/13 16:20:34 阅读更多 →
WooCommerce 3.5.2 安装包获取与环境搭建完整指南

WooCommerce 3.5.2 安装包获取与环境搭建完整指南

简介:Woocommerce 3.5.2 安装包面向使用 WordPress 搭建在线商店的开发者与店主,提供创建和管理电商站点所需的完整插件文件,适合具备一定 WordPress 基础、希望自行部署或研究插件结构的用户。压缩包共 1099 个文件,约 3.73MB&am…

2026/10/13 16:20:34 阅读更多 →
Python在金融科技中的实战应用:数据处理、量化回测与风控建模

Python在金融科技中的实战应用:数据处理、量化回测与风控建模

Python这几年在金融圈的热度,不用我多说。如果你去翻各大券商、基金公司、银行金融科技岗的招聘要求,Python基本是标配技能。我身边不少做量化、风控、数据分析的朋友,日常工作的主力工具就是Python,从拉数据、清洗、建模到生成报…

2026/10/13 16:20:34 阅读更多 →
t3code 跨平台 CLI 工具拆解:Electron 与 CLI 双形态架构及安装配置指南

t3code 跨平台 CLI 工具拆解:Electron 与 CLI 双形态架构及安装配置指南

1. 从 t3code 这个标题说起:一个跨平台 CLI 工具的真实拆解第一次看到 t3code 这个名字,我下意识把它和一堆 CLI 工具联想到了一起。原因很简单,最近一两年围绕终端体验的工具爆发式增长,从 codex cli 到 openspec cli&#xff0c…

2026/10/13 16:20:34 阅读更多 →
PS5辅助工具AnyPS5:游戏库管理、存档备份与远程下载实践

PS5辅助工具AnyPS5:游戏库管理、存档备份与远程下载实践

最近整理我那台 PS5 的时候,发现一个挺尴尬的现实:机器里已经装了几十款数字版和实体版游戏,但每次想找某个老游戏,要么在首页翻半天,要么得先开机再进内容库按字母一个个找。主机自带的界面其实已经做得不错&#xff…

2026/10/13 16:20:34 阅读更多 →
从直连到聚合:大模型API对接的架构演进与实战避坑指南

从直连到聚合:大模型API对接的架构演进与实战避坑指南

1. 从直连到聚合:API对接思路的转变2026年开年到现在,我陆续参与了三个不同规模的AI应用项目,从智能客服到内容生成工具,再到一个内部知识库问答系统。这三个项目有一个共同点:都需要对接大模型API。而在这三个项目的推…

2026/10/13 16:19:32 阅读更多 →

日新闻

物联网系统集成避坑指南:从选型到验收的关键要点

物联网系统集成避坑指南:从选型到验收的关键要点

做了这么多年物联网系统集成的项目,我最大的感受是,大部分坑不是出在技术前沿,而是出在一些看起来很平常的地方。设备选了便宜的、协议没问清楚、现场没摸透、验收标准写得含糊——这些细枝末节,最后都会变成延期、超支和扯皮的大…

2026/10/13 0:00:57 阅读更多 →
ESP32舵机控制全攻略:从PWM原理到高级玩法与常见故障排查

ESP32舵机控制全攻略:从PWM原理到高级玩法与常见故障排查

如果你玩ESP32有一阵子了,很难不碰到舵机控制这道坎。做智能小车要转方向,做机械臂要抬关节,做云台要偏航俯仰,背后都是同一个东西在干活:舵机。而我见过太多人卡在“代码能编译、舵机就是不听话”这个阶段&#xff0c…

2026/10/13 0:00:57 阅读更多 →
CAN总线原理与STM32实战:抗干扰、仲裁、错误处理全解析

CAN总线原理与STM32实战:抗干扰、仲裁、错误处理全解析

1. 为什么CAN总线至今仍是工业现场的“硬通货”?——从汽车底盘到智能温室的真实需求你有没有拆过一辆老款燃油车的中控台?或者调试过某高校实验室里那台跑着Modbus协议却频频丢帧的PLC控制柜?又或者,在某个农业物联网项目里&…

2026/10/13 0:00:57 阅读更多 →

周新闻

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

简介:基于 ARIMA、LSTM、Transformer 等模型的流感时间序列预测 Python 源码,面向计算机相关专业课程设计与期末大作业学生,以及项目实战学习者。内容覆盖预处理、平稳性检验、定阶、残差分析、多模型对比预测的完整时序建模流程,…

2026/10/13 2:54:56 阅读更多 →
影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别 做影刀RPA自动化,十个新手有八个栽在"往输入框里填东西"这件事上:要么填不进去,要么填了一半,要么直接把原来内容追加在后面。这背后的根因&…

2026/10/12 0:16:38 阅读更多 →
影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容 1. 认识影刀:什么场景该用RPA采小说数据 起点中文网的页面结构相对稳定——分类榜单、书籍详情、章节内容三块独立页面,跳转链路清晰。这种场景非常适合影刀自动化&#x…

2026/10/13 1:58:08 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/12 21:05:09 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/13 14:57:39 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/12 18:11:17 阅读更多 →