自由学习记录(56)

从贴图空间(texture space)将值还原到切线空间(tangent space)向量

tangentNormal.xy = (packedNormal.xy * 2 - 1) * _BumpScale;

背后的知识点:法线贴图中的 RGB 是在 0~1 范围内编码的向量

所以贴图法线是怎么“压缩”和“解压”的?

💾 存储时:

  • 法线向量 float3(n.x, n.y, n.z) ∈ [-1, 1]

  • 存入贴图时要转为 0~1 范围:

读取后要“反解码”回来:

fixed3 packedNormal = tex2D(_BumpMap, i.normalUv);读到的是范围是 [0,1]

所以:tangentNormal.xy = packedNormal.xy * 2 - 1;

  • 这一步将 0~1 解码为 -1~1

  • _BumpScale 是调节法线扰动强度的乘子(可以人为增强凹凸感)

法线贴图中,我们通常只显式存储了 xy 分量(映射到 R 和 G 通道),而 z 是通过单位向量长度约束反推的。

RGB 贴图中 xyz 的意义是什么?

通道存储的是什么映射回 tangent space 的含义
R(x)切线方向上的扰动(沿 tangent 轴)normal 在 tangent 方向上的偏移量
G(y)副切线方向上的扰动(沿 bitangent 轴)normal 在 bitangent 方向上的偏移量
B(z)法线方向(沿 normal 轴)通常通过反推计算,表示“凸出/凹陷”程度

这些值共同构成了贴图中每个点的扰动法线向量(在 tangent space 中)。

法线贴图并不改变顶点的 normal,而是在片元级别提供比顶点插值更精细的扰动方向

  • 顶点 normal 是由模型网格决定的(每个顶点一个方向)

  • 法线贴图在片元级别提供 “在当前表面方向上的微扰”

  • Shader 会把贴图中的 (x,y,z) 作为一个 Tangent Space 中的扰动法线

  • 然后用 TBN 把这个扰动变换到世界空间,再用于光照计算

z 分量作用 保证法线是单位向量,体现凹凸“凸起”的程度

Unity UnpackNormal(tex2D(...)) is used to decode the normal

Normal map is saved as an RGB texture with values in 0–1.

_BumpMap ("Normal Map", 2D) = "bump" {}
Unity 会自动:

把这个属性在材质面板中以 “Normal Map 类型”显示

在材质面板中选择贴图时,Unity 会验证它是否是 正常格式的法线贴图

有些内置函数(如 UnpackNormal)也会默认适配

这是一种 语义提示 + 编辑器行为绑定机制。

含义解释
"white"默认使用 Unity 的纯白纹理(全通、全亮),通常用于颜色贴图、控制图等
"black"默认使用纯黑纹理
"gray"使用灰色纹理,常用于金属度、AO、Roughness 等
"bump"✅ 使用 Unity 内置的法线贴图格式(编码好的 normal map),不会当成颜色贴图
"red", "green", "blue"分别用纯红、绿、蓝纹理测试

预处理判断语句 并不是为了“再计算值”,而是为了根据光源类型(点光、方向光、多光源)不同,决定如何使用这个值

#ifndef USING_LIGHT_MULTI_COMPILE

如果你没有启用多光源(不是 forward 渲染 path)

return objSpaceLightPos - v.xyz * _WorldSpaceLightPos0.w;
这段非常关键,它根据 _WorldSpaceLightPos0.w 来判断当前是:

_WorldSpaceLightPos0.w光源类型表达形式
1点光源L = lightPos - vertexPos
0方向光L = -lightDir

#ifndef USING_DIRECTIONAL_LIGHT
    return objSpaceLightPos.xyz - v.xyz;

表示点光源:
方向 = 光源位置 - 当前顶点位置

#else
    return objSpaceLightPos.xyz;

表示方向光:
方向 = 光线方向(由 _WorldSpaceLightPos0 直接编码)

tex2D方法传入的Sample2D和uv类型,这里的uv是经过了TRANSFORM_TEX的变换的,所以对应关系没有出现问题

tex2D() 返回的是 RGBA 值,对应纹理的 4 个通道:

分量意义(默认)
x / .rRed 通道 → 通常表示 normal.x
y / .gGreen 通道 → 通常表示 normal.y
z / .bBlue 通道 → 通常表示 normal.z(或重构)
w / .aAlpha 通道 → 通常无意义,默认值为 1,除非你主动使用它

“返回的是四维矩阵?w 是什么?”

  • ❌ 它不是矩阵,是一个四维向量:float4

  • .w 是采样纹理像素的 Alpha 通道

  • ✅ 在法线贴图中,w/alpha 一般 没有特别作用,除非你专门用它存东西

📌 例外情况:

有时你可能会看到设计得比较高级的 Packed Texture,用 RGBA 四个通道存多个信息,比如:

通道内容(例)
R法线 x 分量
G法线 y 分量
BAO or 金属度
A透明度 or 粗糙度

在这种情况下,.w(或 .a)是你主动使用的额外通道。

常见的指令说明:

指令含义
#if defined(MACRO)如果宏 MACRO 被定义,执行下面的代码块
#elif defined(...)否则如果另一个宏被定义,执行这一块
#else如果以上都不满足,则执行这一块
#endif结束 #if 条件块
#define MACRO定义一个宏(一般由 Unity 自动定义)
#undef MACRO取消一个宏定义

法线贴图需要::编码/解码

贴图压缩技术::DXT5nm、BC5、ASTC 等压缩格式对 normal map 做特定方式编码

(解码).x *= .w 在 RGorAG 模式中,w(即 alpha 通道)保存了缩放系数,乘上修正 x

宏分支控制,,,让同一 Shader 能适配不同贴图格式和硬件压缩能力

从数学上讲,xy 变大,z 的确必须变小,否则法线向量就不再是单位长度了。我们来精确、严谨地拆解这一点,并澄清“为什么我们不能随意直接乘 z”。

tangentNormal.xy *= _BumpScale;
tangentNormal.z = sqrt(1.0 - saturate(dot(tangentNormal.xy, tangentNormal.xy)));

  • xy 扰动越大 → z 越低 → 表示“偏离表面方向更多”

  • xy 越小 → z 越接近 1 → 趋近于原始平面法线(表面更平)

packedNormal.x *= packedNormal.w;

✅ 这是 Unity 在处理 DXT5nm 格式(或 RG/AG 编码)法线贴图时
为了还原正确的 X 分量方向所做的“签名恢复”操作(sign restoration)。

这句代码的意义就是:

恢复 DXT5nm 格式贴图中被拆开的 X 分量的符号信息。

使用情况是否需要 x *= w
RGB 正常法线贴图❌ 不需要,RGB 已存完整 xyz
DXT5nm (RGorAG) 格式✅ 需要,从 R+A 通道还原 x
ASTC RG 格式✅ 一样道理,可能用 .g *= .a

tangentNormal.xy *= _BumpScale 是在 z 已经被 sqrt() 计算之后进行的,那这时法线向量还是单位长度吗?还合理吗?”

❗这样写是不严谨的结果法线向量将不再是单位向量,可能会影响光照准确性,
但实际在某些低精度光照模型中可能“看起来”没太大问题,所以有时会被这么写。

正确的写法应该是:先 scale,再重建 z

但也可以tangentNormal = normalize(tangentNormal);这虽然也能修复向量长度,但会引入不必要的性能消耗,并且对于低精度法线会有误差积累。

如果这里没设置成Normal map,是default,那就按注释的那一块来 

如果在 Unity 中导入贴图时 没有把它设置为 “Normal map” 类型,而是保留为 Default,那就不能直接用 UnpackNormal(),而要自己手动解码贴图数据(如 *2 - 1 等)——对不对?

✔ 是的,这个判断逻辑是完全正确的。

所以注意::cross(N, T ) * w ✅ 是 Unity 推荐的构造 binormal 方法

由于 HLSL 是“列向量 × 行矩阵”的表达顺序 —— 不能直接这么写!

也就是你写的这个形式:

float3 worldNormal = float3(
    dot(i.TtiW0.xyz, tangentNormal),
    dot(i.TtiW1.xyz, tangentNormal),
    dot(i.TtiW2.xyz, tangentNormal)
);

为什么不需要逆矩阵?

这是一个关键误区 —— 很多书说“方向向量要乘以逆转置矩阵”,那是对 非正交矩阵非单位正交基 的情况。

但是在这里:

  • T, B, N 都是单位向量

  • 三者彼此正交

  • 所以 TBN 是正交矩阵

对于正交矩阵:

tex2D(_RampTex, fixed2(halfLambert, halfLambert))

如果你贴的是一张黑 → 白的横向渐变图,那它就像是:

  • 漫反射强 → 用白

  • 光线垂直 → 用灰

  • 背面 → 用黑(因为 dot = 0)

Half-Lambert 是为了让漫反射“更柔和、避免背光发黑”而人为做的函数变换;而 Blinn-Phong 的 Half Vector 是光和视线之间的“几何中间方向”,是完全不同的概念。

渲染操作是否进行说明
深度测试✅ 默认开启,所有物体都可以参与无论透明还是不透明,片元都可能接受深度测试
深度写入⛔ 透明物体通常默认关闭因为深度写入会导致后绘制的透明物体被挡住

为什么有这些不同混合因子

艺术风格与公式的“对应性”

很多时候,所谓“自然的过渡”、“漂亮的发光”,其实是:

  • 物理叠加模拟真实世界光照(如 Linear Add)

  • 用 Cutoff + Lambert 模拟日光与背光

  • 用 Soft Add 表现氛围感光晕扩散

这些都是人类在长期调试中找到的:

✅ “某些数学形式 → 在显示器上经过 gamma → 在人眼中感觉刚刚好”

自然感 = 光 + 人眼 + 数学的共同结果

你看到的那种:

“怎么一个冷冰冰的 Blend One OneMinusSrcAlpha,出来就能让玻璃有那种淡淡的透光感?”

那是因为它刚好:

  • 用透明度控制了透光量(alpha)

  • 保留了背景(OneMinusSrcAlpha)

  • 而你屏幕发光、你眼睛接收,刚好构成了感知的闭环

当你在片元着色器(frag())里写了 discard;
GPU 会把这个 当前正准备写入屏幕的像素彻底丢弃,不再处理它

举个实际例子:一张带 alpha 的叶子贴图

比如:

  • 树叶是绿色,alpha = 1

  • 叶子空隙是透明,alpha = 0

if (texColor.a < 0.5) discard;
那结果就是:

✅ 树叶的绿色区域 → 保留渲染

❌ 空隙区域 → 这个片元直接 被丢弃,什么都不写,像没来过一样

图形管线视角下的“丢”

整个流程简化如下(以一个像素为例):

  1. 顶点着色器执行完 → 光栅化 → 生成这个片元

  2. 进入片元着色器执行 → 执行到你写的 discard;

  3. GPU 立刻中止这个片元的写入流程

  4. 不写入颜色缓冲区,不写入深度,不触发混合,不投影阴影

  5. 后面的像素该怎么画还怎么画,就像这个像素从没存在过

return 的颜色,还要经过 后处理通道

在 Unity 的标准 Shader 中,开启 Blend 通常会

🔹默认搭配 ZWrite Off,否则效果可能异常(如透明遮挡错误)。

Tags { "Queue" = "Transparent" } ✅ Unity 内置 Shader 会自动设为 ZWrite Off

  • To define Pass tags, place the Tags block inside a Pass block.
  • To define SubShader tags, place the Tags block inside a SubShader block but outside a Pass block.

Common built-in RenderType values Unity recognizes:

What does “replaced” mean in RenderType?

In this context, “replaced” refers to a feature called:

🎯 Camera.SetReplacementShader(...)

It means Unity can:

👉 Replace the shaders of everything in the scene at runtime,
BUT only for objects with a certain RenderType.

This is what RenderType is actually used for in this case.

AspectDefined in Shader Language?Used internally by Unity systems?Example
"Transparent"❌ No✅ YesReplacement shaders, depth prepass
"Opaque"❌ No✅ YesG-buffer, deferred passes
"TransparentCutout"❌ No✅ YesCutout lighting, shadows
"MyCustomType"❌ No❌ Only if you use itCustom pipeline or editor tools

使用多个 Pass 的确是为了让 一个 Shader 能够对同一个材质进行多次渲染处理

👉 每一个 Pass 相当于 GPU 要渲染这个物体一次。
所以多个 Pass 就是 同一个物体重复渲染多遍(不代表重复 draw call,但有性能代价)。

Pass {
    ZWrite On
    ColorMask 0
}
的作用是:

✅ 提前写入深度值,但不渲染任何颜色,
这样后续的透明 Pass 就可以正确地进行基于深度的遮挡排序,避免穿模。

为什么透明物体会错位?

原因是:

  • 透明物体一般不开 ZWrite(ZWrite Off)

  • Unity 渲染透明物体时默认按 背面→前面的顺序(靠排序,不靠深度)

  • 如果模型像“绳结”那样自相交(自己遮挡自己),
    👉 你就无法靠“渲染顺序”判断哪个面该挡住谁了
    👉 导致“后面的反而盖住了前面”

ZWrite 的深度信息只要写入,就会保留在深度缓冲区中,直到下一帧/下一次清除
✅ 所以:只要材质没有 ZWrite Off,无论是否最终画出来,只要通过深度测试,它就确实会写入深度

三种法线外拓的shader写法

法线向量不能被平移 法线必须保持和切平面垂直(几何关系) 非均匀缩放会破坏这种垂直性

法线向量是一个协变向量(co-vector)
变换它需要使用原始变换矩阵的逆的转置(inverse transpose)

左乘和右乘有明确、统一、严谨的数学定义
它们的本质是取决于你采用的是**“列向量”还是“行向量”表示法”**。

一旦你选定了其中一种方式 —— 所有矩阵乘法的方向、变换链的顺序、转置等操作都有一致的逻辑。

常见约定:列向量形式是计算机图形学中最常用的表示

使用方式表示法矩阵乘法顺序向量在右边 or 左边
列向量约定v∈Rnv \in \mathbb{R}^nv∈Rn 是列MvMvMv向量在右边(标准)
⛔ 行向量约定(不常用)v⊤v^\topv⊤ 是行向量v⊤Mv^\top Mv⊤M向量在左边

图形学、Unity、OpenGL、HLSL 统一采用列向量规范:

✅ 你常写的这些:

float4 worldPos = mul ( unity_ObjectToWorld  ,  v.vertex );

本质就是:

向量是列向量,矩阵在左边,左乘矩阵,右乘向量

「左乘矩阵、右乘向量」这类说法,确实是在强调“向量在右边”的这种形式。
它告诉你的是向量和矩阵在表达式中的排列关系,是列/行向量系统的一部分语义

🎯 换句话说:

“左乘矩阵”,是说矩阵写在左边,向量在右边
→ 即:Mv(向量被左边的矩阵变换)
→ 默认你在使用 列向量系统---------------Unity巴拉巴拉

“右乘矩阵”,是说向量写在左边,矩阵在右边
→ 即:vM(向量右乘矩阵)
→ 默认你在使用 行向量系统

所以,是不是「只有这两种说法」?

是的,从向量和矩阵相乘的定义角度来说,就这两种约定,没有第三种本质上不同的方式。

表示方式写法适配场景
列向量Mv✅ 图形学、Unity、OpenGL、HLSL、GLSL
行向量vM⛔ 一些数学教材、少部分线性代数风格(但不常用于图形变换)

---------

可是我写成的形式只是fixed3(x,y,z),,实际上存储数据的是不关注行列的,,,那么是不是意味着这里的tanspose同样是只是逻辑上的提示,并不代表里面实际的数据处理方式真的有转置?

🎯 简要回答你:

✅ 是的,你是对的 ——
实际上 fixed3(x, y, z)float3 本质上只是 一组线性数据,GPU 或 CPU 并不会自动知道它是“行向量”还是“列向量”,这是数学意义上的区别,不是内存物理结构。

而像你提到的 transpose,更多是对数学逻辑的一种语义提示或约定,并不意味着内存中数据真的被 rearrange(重新排布)了。

Pass{Name "Outline"Cull FrontCGPROGRAM#pragma vertex vert#pragma fragment frag#include "UnityCG.cginc"float _Outline;fixed4 _OutlineColor;struct v2f{float4 vertex :SV_POSITION;};v2f vert (appdata_base v){v2f o;//物体空间法线外拓//v.vertex.xyz += v.normal * _Outline;//o.vertex = UnityObjectToClipPos(v.vertex);//视角空间法线外拓//float4 pos = mul(UNITY_MATRIX_V, mul(unity_ObjectToWorld, v.vertex));//float3 normal = normalize(mul((float3x3)UNITY_MATRIX_IT_MV,v.normal));//pos = pos + float4(normal,0) * _Outline;//o.vertex =  mul(UNITY_MATRIX_P, pos);//裁剪空间法线外拓o.vertex = UnityObjectToClipPos(v.vertex);float3 normal = normalize(mul((float3x3)UNITY_MATRIX_IT_MV,v.normal));float2 viewNoraml = TransformViewToProjection(normal.xy);o.vertex.xy += viewNoraml * _Outline;return o;}float4 frag(v2f i):SV_Target{return _OutlineColor;}ENDCG}

UNITY_MATRIX_IT_MV 转成 3x3 ((float3x3)UNITY_MATRIX_IT_MV) 是合理的,因为我们处理的是法线方向向量,不需要考虑位移分量

  • 对于方向向量如 v.normal,这段 3x3 就足够完成旋转和缩放变换。

  • 如果你传入的是位置 v.vertex,那才需要用 float4x4,因为要考虑位移部分。

为什么只用 normal.xy

1. 目标是对 o.vertex.xy 做偏移

  • o.vertex 是裁剪空间(clip space)下的坐标,作用于屏幕上的 2D 位置。

  • 所以我们只需要在 X 和 Y 平面内偏移这个像素点,制造出轮廓线的“外拓”效果。

  • z 分量在这里并不会影响你看到的轮廓(不会显著影响屏幕上的位置,只影响深度)

TransformViewToProjection() 是做什么的?

  • 这个函数将 观察空间(View Space) 中的向量转换为 投影空间(Projection Space)

  • 它用于将法线的方向也带入透视变形中,避免轮廓线在不同视角下厚度不一致。

  • 但它的输入是 float2,意味着只能转换 2D 屏幕平面上的分量

o.vertex.xy += viewNormal * _Outline;
明明 vertex 是 clip space 的 xyzw,
只改 xy 会不会出问题?

不会出问题,反而这是合理做法,因为这里我们就是要在屏幕空间做一个 2D 偏移效果,而不破坏 zw

o.vertex = UnityObjectToClipPos(v.vertex);
它是 Clip Space(裁剪空间)坐标,四维向量 (x, y, z, w)。

后续会自动进入 NDC(x/w, y/w, z/w),再映射到屏幕。

o.vertex.xy += viewNormal * _Outline;
因为:

你只想让模型边缘沿屏幕方向“鼓出来”,产生描边效果。

所以只改 xy,让它在画面中“挤出一点”。

改 z 会造成深度变化,可能导致遮挡错误。

改 w 会影响投影缩放关系,造成透视失真。

是否破坏了 clip space 的投影?

不会。

  • Clip space 是一个过渡空间,最终 GPU 会做 o.vertex.xyz / o.vertex.w 投影。

  • xy 改变后,在屏幕上会位移。

  • zw 不变,意味着你不会影响遮挡关系或投影缩放。

假设你有一张纸(屏幕),你把一个点轻轻沿着横纵方向推开一点,但不把它抬起来(不改 z),也不改变它离你的“距离比例”(w)。那么它的视觉位置偏移了,但它的深度和透视仍然是对的。

smoothstep() 是一个在图形编程中非常常用的函数,用于生成**平滑过渡(soft transition)**效果

smoothstep(edge0, edge1, x)
其作用是:

当 x 在 edge0 和 edge1 之间时,输出一个从 0 到 1 的平滑插值值。
当 x <= edge0,返回 0;
当 x >= edge1,返回 1;
中间用一个平滑三次曲线过渡。

float t = saturate((x - edge0) / (edge1 - edge0));
return t * t * (3 - 2 * t);
这个公式创造了一个 S型曲线,即缓入缓出(ease in/out)的效果。

difLight = smoothstep(0, 1, difLight);
这一步是:

对 dot(worldLightDir, i.worldNormal) * 0.5 + 0.5 这个光照强度进行 平滑映射;

避免原始 dot 值带来的硬切换或强烈对比;

实际上就是给卡通风格加一点“柔化的边缘过渡”。

Shader 中前面那一堆 ShaderLab 语言(也就是 Pass 里的非 HLSL 部分),它们是用来控制渲染行为的,并不是计算颜色或坐标,而是告诉 GPU 在“怎么渲染”这段片元

Pass
{
    Name "XRay"
    Tags { "ForceNoShadowCasting" = "true" }
    Blend SrcAlpha One
    ZWrite Off
    ZTest Greater

Name "XRay"

  • 给这个 Pass 起个名字,方便调试或多通道控制时引用。

  • 不影响渲染行为。

Tags { "ForceNoShadowCasting" = "true" }

  • 让这个 Pass 不参与阴影投射

  • 对于半透明或特殊渲染(如 X-Ray)是有意义的:不需要参与阴影。

ZWrite Off

  • 关闭深度写入,也就是说这个 Pass 不会写入 Z 缓冲区。

  • 原因是:XRay 要“穿透”,你不希望它挡住别的物体。

ZTest Greater

  • 表示只有在片元比当前深度更远(Z更大)时才绘制

  • 非常关键!这让这个 XRay Pass 只在物体背面被遮挡时才显示

    • 也就是:只有当它“在其他物体后面”才会出现,模拟透视内部结构。

  • 相比常用的 ZTest LEqualZTest Always,这是一种隐藏条件渲染

fixed4 frag(v2f i) : SV_Target
{
    float3 normal = normalize(i.normal);
    float3 viewDir = normalize(i.viewDir);
    float rim = 1 - dot(normal, viewDir);
    return _XRayColor * pow(rim, 1 / _XRayPower);
}
Shader 计算了一个 Rim(边缘高光)值 来模拟透视轮廓。

和前面的 ZTest Greater 联合使用后,只有被挡住的背面边缘才出现 XRay 效果,很自然地做出内透或透视显示。

  • 同一个模型的不同三角面片之间,只要一个片元比另一个更靠前,就会记录它的深度。

  • 所以模型自己也会遮挡自己。

  • 这就是为什么你可以做 XRay 效果:它会在“模型自己后面的像素”上画出边缘线或高光

切线空间(Tangent Space)转世界空间(World Space)

fixed3 worldNormal = normalize(float3(
    dot(i.TtoW0.xyz, tangentNormal),
    dot(i.TtoW1.xyz, tangentNormal),
    dot(i.TtoW2.xyz, tangentNormal)
));

TBN矩阵 = [Tangent, Binormal, Normal]  (每一列是一个向量)

由于你无法直接在 Unity 的 fragment shader 中使用 mul(float3x3, float3)(尤其是当 TBN 来自顶点插值的时候),Unity 中很多时候会“展开”这个乘法写成:

顶点插值不支持结构体或矩阵传递

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/diannao/79712.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【mysql】mysql疑难问题:实际场景解释什么是排它锁 当前读 快照读

注&#xff1a; 理解本文 前置需要掌握的基础知识&#xff1a;事务隔离、锁的概念、并发知识&#xff1b; 事务隔离 尤其是事务延伸问题 是个重难点&#xff0c;绝非八股文那几句话就能说完的&#xff0c;在实际场景中&#xff0c;分析起来有一定难度 author: csdn博主 孟秋与你…

Python:使用web框架Flask搭建网站

Date: 2025.04.19 20:30:43 author: lijianzhan Flask 是一个轻量级的 Python Web 开发框架&#xff0c;以简洁灵活著称&#xff0c;适合快速构建中小型 Web 应用或 API 服务。以下是 Flask 的核心概念、使用方法和实践指南 Flask 的核心特点&#xff1a; 轻量级 核心代码仅约…

层次式架构核心:中间层的功能、优势与技术选型全解析

层次式架构中的中间层是整个架构的核心枢纽&#xff0c;承担着多种重要职责&#xff0c;在功能实现、优势体现以及技术选型等方面都有丰富的内容&#xff0c;以下为你详细介绍&#xff1a; 一、功能 1.业务逻辑处理 复杂规则运算&#xff1a;在许多企业级应用中&#xff0c;…

网络--应用层自定义协议与序列化

目录 4-1 应用层 4-2 重新理解 read、write、recv、send 和 tcp 为什么支持全双工 4-3 开始实现 4-1 应用层 我们程序员写的一个个解决我们实际问题 , 满足我们日常需求的网络程序 , 都是在应用 层 . 再谈 " 协议 " 协议是一种 " 约定 ". socke…

fastlio用mid360录制的bag包离线建图,提示消息类型错误

我用mid360录制的bag包&#xff0c;激光雷达的数据类型是sensor_msgs::PointCloud2&#xff0c;但是运行fast_lio中的mid360 launch文件&#xff0c;会报错&#xff08;没截图&#xff09;&#xff0c;显示无法从livox_ros_driver2::CustomMsg转换到sensor_msgs::PointCloud2。…

C# WinForm窗口TextBox控件只能输入数字(包括小数)并且恢复Ctrl+C复制和Ctrl+V粘贴功能

1. 前言 最近在写定GPS定位时&#xff0c;经纬度是用的double类型&#xff0c;并且经纬度的要求是小数点后最少6位&#xff0c;多了能达到17位&#xff0c;又遇到了常用的TextBox控件只能输入数字、小数的功能&#xff0c;因为有一年多没有写程序&#xff0c;现在再来写这些感…

【MySQL数据库】数据类型

目录 1&#xff0c;数据类型分类 2&#xff0c;bit类型 3&#xff0c;小数类型 3-1&#xff0c;float/double类型 3-2&#xff0c;decimal类型 4&#xff0c;字符串类型 4-1&#xff0c;char 4-2&#xff0c;varchar 5&#xff0c;日期和时间类型 6&#xff0c;enum和…

Spark-SQL核心编程2

路径问题 相对路径与绝对路径&#xff1a;建议使用绝对路径&#xff0c;避免复制粘贴导致的错误&#xff0c;必要时将斜杠改为双反斜杠。 数据处理与展示 SQL 风格语法&#xff1a;创建临时视图并使用 SQL 风格语法查询数据。 DSL 风格语法&#xff1a;使用 DSL 风格语法查询…

pandas库详解

CONTENT 基本数据结构SeriesDataFrame 数据读取与写入读取 CSV 文件写入 CSV 文件 数据清洗处理缺失值数据类型转换 数据操作索引与切片数据合并数据分组与聚合 数据可视化 基本数据结构 Series Series 属于一维标记数组&#xff0c;由一组数据和对应的索引构成。 import pa…

黑马商城(五)微服务保护和分布式事务

一、雪崩问题 二、雪崩-解决方案&#xff08;服务保护方案&#xff09; 请求限流&#xff1a; 线程隔离&#xff1a; 服务熔断&#xff1a; 服务保护组件&#xff1a; 三、Sentinel 引入依赖&#xff1a; <!--sentinel--> <dependency><groupId>com.aliba…

洛谷P1312 [NOIP 2011 提高组] Mayan 游戏

题目 #算法/进阶搜索 思路: 根据题意,我们可以知道,这题只能枚举,剪枝,因此,我们考虑如何枚举,剪枝. 首先,我们要定义下降函数down(),使得小木块右移时,能够下降到最低处,其次,我们还需要写出判断函数,判断矩阵内是否有小木块没被消除.另外,我们还需要消除函数,将矩阵内三个相连…

基于Redis的3种分布式ID生成策略

在分布式系统设计中&#xff0c;全局唯一ID是一个基础而关键的组件。随着业务规模扩大和系统架构向微服务演进&#xff0c;传统的单机自增ID已无法满足需求。高并发、高可用的分布式ID生成方案成为构建可靠分布式系统的必要条件。 Redis具备高性能、原子操作及简单易用的特性&…

Spotlight on Mysql详细介绍

1. 版本............................................................................................................................................1 2. 使用介绍...............................................................................................…

背包 DP 详解

文章目录 背包DP01 背包完全背包多重背包二进制优化单调队列优化 小结 背包DP 背包 DP&#xff0c;说白了就是往一个背包里扔东西&#xff0c;求最后的最大价值是多少&#xff0c;一般分为了三种&#xff1a;01 背包、完全背包和多重背包。而 01 背包则是一切的基础。 01 背包…

二级评论列表-Java实现

二级评论列表是很常见的功能&#xff0c;文章记录了新手用Java实现的具体逻辑。 整体实现逻辑是先用2个sql&#xff0c;分别查出两层数据。然后用java在service中实现数据组装&#xff0c;返给前端。这种实现思路好处是SQL简洁&#xff0c;逻辑分明&#xff0c;便于维护。 一…

快速入手-基于python和opencv的人脸检测

1、安装库 pip install opencv-python 如果下载比较卡的话&#xff0c;指向国内下载地址&#xff1a; pip3 install opencv-python -i https://pypi.tuna.tsinghua.edu.cn/simple 2、下载源码 https://opencv.org/ windows11对应的版本下载&#xff1a; https://pan.baidu…

GitLab本地安装指南

当前GitLab的最新版是v17.10&#xff0c;安装地址&#xff1a;https://about.gitlab.com/install/。当然国内也可以安装极狐GitLab版本&#xff0c;极狐GitLab 是 GitLab 中国发行版&#xff08;JH&#xff09;。极狐GitLab支持龙蜥&#xff0c;欧拉等国内的操作系统平台。安装…

OpenCv高阶(六)——图像的透视变换

目录 一、透视变换的定义与作用 二、透视变换的过程 三、OpenCV 中的透视变换函数 1. cv2.getPerspectiveTransform(src, dst) 2. cv2.warpPerspective(src, H, dsize, dstNone, flagscv2.INTER_LINEAR, borderModecv2.BORDER_CONSTANT, borderValue0) 四、文档扫描校正&a…

资源-又在网上淘到金了

前言&#xff1a; 本期再分享网上冲浪发现的特效/动画/视频资源网站。 一、基本介绍&#xff1a; mantissa.xyz&#xff0c;about作者介绍为&#xff1a;Midge “Mantissa” Sinnaeve &#xff08;米奇辛纳夫&#xff09;是一位屡获殊荣的艺术家和导演&#xff0c;提供动画、…

Linux疑难杂惑 | 云服务器重装系统后vscode无法远程连接的问题

报错原因&#xff1a;本地的known_hosts文件记录服务器信息与现服务器的信息冲突了&#xff0c;导致连接失败。 解决方法&#xff1a;找到本地的known_hosts文件&#xff0c;把里面的所有东西删除后保存就好了。 该文件的路径可以在报错中寻找&#xff1a;比如我的路径就是&a…