自由學習記錄(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.pswp.cn/diannao/79712.shtml
繁體地址,請注明出處:http://hk.pswp.cn/diannao/79712.shtml
英文地址,請注明出處:http://en.pswp.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…