Metal 學習筆記二:3D模型

是什么讓一個好游戲更好玩?漂亮的圖像!就像《神界:原罪2》,《暗黑破壞神3》以及《巫師3》等大作一樣,需要一個強大的程序團隊以及3D美術團隊強強合作。你在屏幕中看到正是3D模型使用自定義渲染繪制的結果。就像上一章你繪制的紅色球體那樣,只是效果更為豐富和先進而已。

在本節,我們會熟悉3D模型,我們會學習如何創建它們,它們是由什么組成,以及如何用不同的顏色和風格來渲染它們。

什么是3D模型?

3D模型是由頂點組成的。每個頂點都是3D空間的一個點,由 x, y, z 值組成。

就像你在前一章看到的,你會發送這些頂點數據到GPU來渲染它們。

打開本章的starter的playground。這個playground包含兩頁,Render and Export 3D Model 以及 Import Train。它也包含了USDZ格式的train模型,如果你看不到這些東西的話,你可能需要使用右上角圖標來顯示項目導航。

要顯示文件擴展名,請打開 Xcode 設置,然后在 General 選項卡上,選擇 File Extensions: Show All。

從項目導航那里,選擇Render and Export 3D Model。它包含了第一章的代碼,"Hello Metal!" 檢查它在playground實時視圖中顯示的球體。當前球體是顯示為一個平坦的實心紅色實體。

要查看每個三角形的邊,您可以使用線框渲染模型。

為了使用線框渲染,在renderEncoder.setVertexBuffer(...)后添加如下代碼:

renderEncoder.setTriangleFillMode(.lines)

此代碼指示 GPU 渲染線條而不是實心三角形。

運行playground:

這里有點視覺錯覺。它可能看起來不像,但 GPU 正在渲染直線。球體邊緣看起來彎曲的原因是 GPU 渲染的三角形數量。如果渲染的三角形較少,則曲線模型往往看起來有些“塊狀”。
你現在可以真正看到球體的 3D 性質。模型的三角形在水平方向上均勻分布,但由于您在二維屏幕上查看,因此它們在球體邊緣的位置比中間的三角形小。

在 Blender 或 Maya 等 3D 應用程序中,您通常會作點、線條和面。點是頂點;線(也稱為邊)是頂點之間的線;而面是三角形平面區域。

頂點通常按三角形排列,因為 GPU 硬件專門用于處理它們。GPU 的核心指令希望看到一個三角形。在所有可能的形狀中,為什么是三角形?
? 三角形是二維中可繪制的任何多邊形中頂點最少的。
? 無論以何種方式移動三角形的點,這三個點將始終位于同一平面上。
? 從任何頂點開始分割三角形時,它總是變成兩個三角形。
在 3D 應用程序中建模時,通常使用四邊形(四點多邊形)。四邊形與細分或平滑算法配合得很好。當您使用 Model I/O 框架導入模型時,Model I/O 會將這些四邊形轉換為三角形。

用Blender創建模型

為了創建3D模型,你需要一個好用的3D建模程序。市面上有很多建模軟件,從免費的到昂貴的。對于免費中最好用的3D建模軟件是Blender(作者使用的版本是 v.3.6)。也有很多建模專家使用Blender,如果你了解Cheetah3D、Maya或Houdini等其他軟件的話,你會發現Blender用起來也差不多。

下載并安裝Blender,通過 https://www.blender.org 網址。運行Blender,點擊空白區域關閉啟動tips界面,然后你會看到一個操作界面,如下圖:

如果你的界面看起來不一樣的話,可以點擊Edit Menu -> Preferences. 點擊左下角的漢堡菜單,選擇Load Factory Settings,并且點擊Load Factory Preferences。點擊Save Preferences保存設置。

如果你希望創建你自己的模型,最好的開始是參照Blender說的教程,在地址。

這個教程會教你怎么做一個蘑菇,你可以后續在你的playerground中把這個蘑菇給渲染出來,本章后面的挑戰中,有這個題目。

3D文件格式

.obj: 由Wavefront科技公司開發,流行過一段時間;基本上所有3D建模程序都支持導入和導出.obj文件,你可以使用和obj同文件的.mtl文件來指定材質(包括紋理以及表面屬性等),不過這個文件不支持動畫。

.glTF:由Khronos開發出來--就是那個管理Vulkan和OpenGL的機構--這個格式相對比較新,并且仍然在開發中。因為它的靈活性,所以它有強大的社區支持,它也支持動畫模型。

.blend:是Blender建模軟件用的格式。

.fbx:Autodesk私有格式,由于Autodesk公司有多個強大建模軟件的原因,這個格式使用很廣泛,并且支持動畫,但是缺點是, 它是私有的,并且沒有單一標準。

.usd:Universal Scene Description是一個由Pixar開發的開源格式,完整文檔在https://openusd.org。USD 文件可以引用許多模型和文件,因此團隊中的每個人都可以處理場景的單獨部分。USD 文件可以具有多個不同的擴展名。.usd 可以是 ASCII 或二進制。.usda 是人類可讀的 ASCII。.usdz 是一個 USD 存檔文件,其中包含模型或場景所需的一切。Apple 將 USDZ 格式用于其 AR 模型。

OBJ 文件僅包含單個模型,而 glTF 和 USD 文件是整個場景的容器,包括模型、動畫、相機和燈光。
在本書中,您將主要使用 USD 格式。

您可以使用 Apple 的 Reality Converter 將 3D 文件轉換為 USDZ。Apple 還提供了用于驗證和檢查 USDZ 文件 (https:// apple.co/3gykNcI) 的工具,以及示例 USDZ 文件庫 (https://apple.co/ 3iJzMBW)。

導出到Blender

現在你已經安裝好Blender了,是時候導出你在playground中創建的模型到Blender中了。

仍然在Render and Export 3D Model頁,到playground的靠前的代碼,你創建模型的地方,修改如下代碼:

let mdlMesh = MDLMesh(shereWithExtent: [0.75, 0.75, 0.75],segments:[100, 100],inwardNormals: false,geomeryType: .triangles,allocator: allocator)// 修改為如下代碼,即改為創建圓錐體,而不是球體
let mdlMesh = MDLMesh(coneWithExtent: [1, 1, 1],segments:[10, 10],inwardNormals: false,cap: true,geomeryType: .triangles,allocator: allocator)

這將會創建圓錐體,而不是球體。運行playground,你將會看到線框的圓錐體。

這個將會是你通過Model I/O 來導出的模型。

在Finder中,在Documents目錄,創建一個新的文件夾,命名為Shared Playground Data。這個是你保存playgrounds的文件的地方,確保你命名準確。

注意:全局常量playgroundSharedDataDirectory會持有這個文件夾的名字。

為了導出這個圓錐體,增加如下代碼,在創建mesh的后面:

// begin export code// 在Model I/O 的場景的最上層是一個MDLAsset,
// 你可以增加子對象,比如Mesh,相機,燈光等
// 到asset并且構建一個完整場景層次
let asset = MDLAsset()
asset.add(mdlMesh)// 檢測Model I/O 是否能導出一個 .usda文件格式
// 你可以選擇.usd或.usdz,但是選擇ASCII文本可以方便檢查文件內容
let fileExtension = "usda"
guard MDLAsset.canExportFileExtension(fileExtension) else {fatalError("Can't export a .\(fileExtension) format")
}// 導出圓錐體到Shared Playground Data的文件夾中
do {let url = playgroundSharedDataDirectory.appendingPathComponent("primitive.\(fileExtension)")try asset.export(to: url)
} catch {fatalError("Error \(error.localizedDescription)")
}
// end export code

運行playground即可導出圓錐體對象了。

usd文件格式

在Finder,導航到Documents -> Shared Playground Data. 我們看到playground已經導出這個文件:primitive.usda。

使用一個文本編輯器,打開primitive.usda。

以下是描述具有四個角頂點的平面基元的示例 USD 文件。圓錐體 USD 文件看起來相似,只是它具有更多的頂點數據。

#usda 1.0
(defaultPrim = "plane"endTimeCode = 0startTimeCode = 0timeCodesPerSecond = 60upAxis = "Y" )
def Mesh "plane"
{uniform bool doubleSided = 0float3[] extent = [(0, -0.5, -0.5), (0, 0.5, 0.5)]int[] faceVertexCounts = [3, 3]int[] faceVertexIndices = [3, 2, 1, 3, 1, 0]normal3f[] normals = [(-1, 0, 0), (-1, 0, 0), (-1, 0, 0),
(-1, 0, 0)]point3f[] points = [(0, 0.5, 0.5), (0, -0.5, 0.5), (-0,
-0.5, -0.5), (0, 0.5, -0.5)]float2[] primvars:Texture_uv = [(1, 1), (0, 1), (0, 0), (1,
0)] (interpolation = "vertex")
}

該文件首先描述大體功能,例如動畫計時和向上的方向。然后,該文件將描述網格。
以下是平面 USD 的詳細解釋:
? extent:網格的大小。創建圓錐體時,在 coneWithExtent 中,您在所有軸上都指定了 1。最小頂點位置值為 -0.5,最大值為 0.5。
? faceVertexCounts:此平面由兩個三角形組成,每個三角形有三個頂點。您的圓錐體將有許多三角形。
? faceVertexIndices:此平面有四個頂點,每個角一個。索引順序是這些頂點的渲染順序。要組成兩個三角形,您需要渲染六個頂點。
? normals:表面法線。法線是與平面正交、指向外面的向量。稍后將閱讀有關法線的更多信息。
? points:每個頂點的位置。該平面有四個頂點。您的圓錐體將具有許多頂點。
? Texture_uv:UV 坐標確定頂點在 2D 紋理上的位置。紋理上的坐標稱為 uv 坐標,而不是 xy 坐標,但它們的工作原理相同。您的圓錐體不使用這些 UV 坐標,因為您尚未對其應用任何自定義紋理。

導入圓錐

現在準備導入圓錐體到Blender中,按如下步驟:

1,打開Blender

2,選擇File -> New -> General

3,選中初始的立方體

4,按X鍵刪除那個立方體,并確認

現在你的Blender已經清空好了。

選擇 File -> Import -> Universal Scene Description (.usd*),并在Documents/Shared Playground Data的文件夾中選中primitive.usda文件。

這樣圓錐體就導入到Blender中了:

左鍵點擊這個圓錐體以選中它,并按Tab鍵,讓Blender切換到編輯模式,讓你能看到組成圓錐體的頂點和三角形。

在編輯模式中,你可以移動頂點位置,以及添加新頂點來創造更復雜的3D模型。

使用playground,我們已經可以創建,渲染和導出3D模型了。在本章的后面,我們將渲染一個更為復雜的模型,它有多個材質組。

材質

材質描述 3D 渲染器應如何為頂點著色。例如,頂點應該光滑有光澤嗎?粉紅色?反射?

材料特性可以包括:
? diffuse:表面的基本顏色。
? metallic:描述表面是否為金屬。
? roughness:描述表面的粗糙程度。如果表面的粗糙度為 0,則它是完全平坦且有光澤的。

材質組

在Blender中,打開train.blend。它就在本章的資源目錄下。它是tran.usdz的源編輯文件。左鍵點擊這個模型來選中它,然后按Tab鍵進入編輯模式。

不同于普通的灰色圓錐,火車模型有幾種顏色。這些顏色被定義在材料組中 - 每種顏色一組。在 Blender 屏幕的右側,您將看到屬性面板,其中材料上下文已選定(這是垂直圖標列表底部的圖標),該模型中的材料列表在頂部。

選中Body,然后點擊下面的“Select”,分配到Body紋理組的頂點都會高亮起來:

注意如何將頂點分為不同的組或材料。這種分離使選擇Blender中的各個部分變得更加容易,并使您能夠分配不同的顏色。

回到Xcode中,在項目導航那里,打開Import Train的playground頁面。

在playground的資源文件夾,我們可以看到train.usdz文件。在窗口上拖動,以便將視圖攝像頭繞著模型移動。

在Import Train中,移除你創建圓錐體的代碼:

let mdlMesh = MDLMesh(coneWithExtent: [1, 1, 1],segments:[10, 10],inwardNormals: false,cap: true,geomeryType: .triangles,allocator: allocator)

不用擔心,你的代碼暫時編譯不過,直到你完本節。我們現在要加載train模型,使用如下代碼:

guard let assetURL = Bundle.main.url(forResource: "train",withExtension: "usdz") else {fatalError()
}

這會設置好USD文件的URL地址。

頂點描述

Metal創建對象時,都會使用一個描述來填充信息。你在上一章看到創建管線狀態對象時也使用過描述。在加載模型之前,我們需要通過創建一個頂點描述,以便告訴Metal如何安排頂點和其他數據。

接下來的圖表描述模型頂點數據的輸入緩沖,它共有兩個頂點,每個頂點包含了位置,法線以及紋理坐標屬性。頂點描述讓Metal知道怎么解析頂點數據。

在剛才設置模型URL代碼后,添加如下代碼:

// 創建一個頂點描述,用來配置所有頂點屬性。
// 一般頂點屬性會包含位置,法線,和紋理坐標等數據。
// 不過這里只需要位置。每個頂點最多可以包含31種屬性。
let vertexDescriptor = MTLVertexDescriptor()// 屬性0:位置,它是一個由3個float組成的數據
vertexDescriptor.attributes[0].format = .float3// 屬性0在緩存中的偏移為0,是第一個屬性
vertexDescriptor.attributes[0].offset = 0// 當你發送頂點數據到GPU時,你通過一個MTLBuffer發送它,
// 并且會用一個索引來標識這個緩沖。有31個有效緩沖,
// Metal會用一個緩沖參數表來記錄它們。使用0號緩沖,
// 以便頂點著色器可以匹配輸入到緩沖0的頂點數據
vertexDescriptor.attributes[0].bufferIndex = 0

緊接著是如下代碼:

// 指定buffer0的頂點數據步幅值。步幅值是每個頂點占用字節個數。
// 這里我們每個頂點只有位置信息,所以占用了3個float3的尺寸,float3等同于swift中的SIMD3<Float>。
// 使用緩沖區布局索引和步幅格式,您可以設置引用具有不同布局的多個 MTLBuffer 的復雜頂點描述符。您可以選擇交錯位置、法線和紋理坐標;或者,您可以先布置包含所有位置數據的緩沖區,然后再包含其他數據。
vertexDescriptor.layouts[0].stride = MemoryLayout<SIMD3<Float>>.stride// 通過metal的頂點描述,創建一個Model I/O專用的頂點描述
// Model I/O 需要的格式略有不同的頂點描述符,因此您可以從 Metal 頂點描述符創建新的Model I/O 描述符。如果您有Model I/O 描述符并且需要一個 Metal 描述符,MTKMetalVertexDescriptorFromModelIO() 提供了一個解決方案
let meshDescriptor =MTKModelIOVertexDescriptorFromMetal(vertexDescriptor)// 把字符串名“position”分配給屬性0,這讓Model I/O 知道這個屬性代表位置信息。
// 法線和紋理坐標數據也可用,但使用此頂點描述符,您告訴 Model I/O 您對加載這些屬性不感興趣。
(meshDescriptor.attributes[0] as! MDLVertexAttribute).name =
MDLVertexAttributePosition

接下來是如下代碼:

// 通過URL,頂點描述,以及內存分配器讀取到資源。
let asset = MDLAsset(url: assetURL,vertexDescriptor: meshDescriptor,bufferAllocator: allocator)
// 先只取得第一個子mesh
let mdlMesh = asset.childObjects(of: MDLMesh.self).first as! MDLMesh

此代碼使用 URL、頂點描述符和內存分配器讀取asset。然后,您讀入asset中的第一個 Model I/O 網格緩沖區。一些更復雜的對象將具有多個網格,但您稍后會處理這個問題。
現在您已經加載了模型頂點信息,代碼的其余部分將相同,您的 Playground 將從新的 mdlMesh 變量加載網格。

運行Playground查看線框渲染的train:

耶!真酷,不過它們好像有點太高了,我們想辦法把它拉低一些,接近地面。

Metal坐標系統

所有模型都有一個原點。原點是mesh放在3D場景的定位點,火車的原點是[0, 0, 0],在模型的中下方。我們在Blender編輯這個模型時,這個點在場景的正中間。

Metal的NDC(歸一化設備坐標)系是一個2個單元寬,2個單元高,1個單元深的盒子,其中X是右/左,Y是上/下,Z是 進/出 屏幕。

歸一化,意味著調整到標準數值范圍。在屏幕中,比如你的窗口像素坐標是0到375,但是Metal的NDC坐標系不關心屏幕的實際尺寸,它的X的坐標總是從-1.0到1.0。在第四章,“3D變換”,我們會學習在不同坐標系之間的變換。因為火車的原點[0, 0, 0]在它的中下部,所以,它的中下部位于在NDC屏幕的中間。導致輪胎看起來有點高。

GPU 根據頂點函數的輸出呈現頂點位置。您的playground目前包含一個非常簡單的頂點函數,該函數返回傳遞給它的頂點位置。

在playground中定位到let shader = """...""",

shader 是一個文本字符串,其中包含 Metal 庫加載和編譯的著色器函數代碼。通過更改此字符串中的 vertex_in.position,您可以更改每個頂點的渲染位置。
在著色器文本字符串中,將返回 vertex_in.position;更改為:

 float4 position = vertex_in.position;
position.y -= 1.0;
return position;

請小心地完全按照所示方式添加此代碼,在每行的末尾添加分號。由于代碼包含在字符串中,因此編譯器無法識別錯誤。
在這里,您從渲染的每個頂點的 y 位置減去 1.0。y 軸上的 NDC -1.0 位于屏幕底部。如果您還不太了解發生了什么,請不要擔心,因為您將在第 4 章 “頂點函數”中重新討論這個主題。

運行playground,輪胎現在已經顯示到了屏幕的底部了。

?

現在車輪已經固定,你準備好解決失蹤火車的情況了!

子網格submesh

到現在,你的模型只顯示了一個紋理組,也就是一個子mesh。下圖中是一個平面,有4個頂點,以及兩個材質組。

當 Model I/O 加載這個平面時,它會把4個頂點放到一個MTLBuffer中,接下來的圖顯示兩個子網格的緩沖是如何索引它的頂點數據的。

第一個子網格緩沖區保存淺色三角形 ACD 的頂點索引。這些索引指向頂點 0、2 和 3。第二個子網格緩沖區保存暗三角形 ADB 的索引。子網格在子網格緩沖區開始的位置也有一個偏移。索引可以保存在 uint16 或 uint32 中。第二個子網格緩沖區的偏移量將是 uint 類型大小的三倍。

環繞順序

頂點順序(也稱為環繞順序)在這里很重要。該平面的頂點順序是逆時針。通過逆時針環繞順序,以逆時針順序定義的三角形正面面向您,而以順時針順序環繞的三角形背對您。在后面的章節,我們將會理解渲染管線,并且會看到GPU是怎么剔除背面的三角形的,以便節省處理時間。

渲染子mesh

目前,我們只渲染了第一個子mesh。我們的火車模型有多個材質組,因此它有多個子mesh,我們需要用一個循環來渲染它們。

在playground代碼靠后位置,修改:

guard let submesh = mesh.submeshes.first else {fatalError()
}
renderEncoder.drawIndexedPrimitives(type: .triangle,indexCount: submesh.indexCount,indexType: submesh.indexType,indexBuffer: submesh.indexBuffer.buffer,indexBufferOffset: 0)

為:

for submesh in mesh.submeshes {renderEncoder.drawIndexedPrimitives(type: .triangle,indexCount: submesh.indexCount,indexType: submesh.indexType,indexBuffer: submesh.indexBuffer.buffer,indexBufferOffset: submesh.indexBuffer.offset)
}

這個循環,會遍歷所有子mesh,并調用draw call。mesh和子mesh都在MTLBuffers中,子mesh持有它使用的網格中頂點的索引清單。

運行playground,然后你的火車就能完全渲染出來了,除了材質顏色,你將會在第7章“紋理映射與材質”中學習如何著色。

祝賀!你已經渲染了3D模型了。暫時不用管你只能渲染它到一個類2D的效果,并且沒有顯示材質顏色。到下一章,你會知道渲染更多的知識,并且再后續章節,你會知道如何把它渲染得更為3D一些。

挑戰

如果你要參加一個有趣的挑戰,請完成 Blender 教程來制作蘑菇 (https://bit.ly/3gwKiel),然后將你在 Blender 中制作的內容導出到 .usdz 文件。如果要跳過建模,可以在本章的 resources 目錄中找到 mushroom.usdz 文件。
? 將 mushroom.usdz 導入 playground 并渲染它。
如果您使用自己建模的蘑菇,您可能會發現蘑菇是側躺的。Blender 使用 Z 軸向上,而你的 Playground 期望 Y 軸向上。在導出為 USD 之前,您應該將模型在 Z 軸上旋轉 180°,在 X 軸上旋轉 270°。然后,您必須在 Blender 中應用所有變換,然后才能使用菜單選項 Object ? Apply ? All Transforms 導出。resources 目錄中的 mushroom.usdz 已經旋轉。

如果你遇到困難,完成的 Playground 位于本章的挑戰目錄中。

參考

https://zhuanlan.zhihu.com/p/384962760

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/web/70735.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/70735.shtml
英文地址,請注明出處:http://en.pswp.cn/web/70735.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

【算法】797. 差分

題目 797. 差分 思路 差分的實質是通過構造數組b減少時間復雜度&#xff0c;數組a為初始數據&#xff0c;構造數組b&#xff0c;數組a是b的前綴和&#xff0c;通過對數組b操作就可以實現數組a每個數加上c&#xff0c;而對數組b的操作在單位時間內即可完成&#xff0c;對數組…

解鎖狀態模式:Java 編程中的行為魔法

系列文章目錄 后續補充~~~ 文章目錄 一、狀態模式&#xff1a;概念與原理二、狀態模式的深度剖析&#xff08;一&#xff09;模式定義與核心思想&#xff08;二&#xff09;模式結構與角色 三、狀態模式的實際應用場景&#xff08;一&#xff09;電商系統中的訂單狀態管理&…

php 獲取head參數

php 獲取head參數 在PHP中&#xff0c;獲取HTTP頭部&#xff08;head&#xff09;參數可以通過不同的方式實現&#xff0c;下面為你詳細介紹幾種常見的方法。 1. 使用$_SERVER超全局變量 $_SERVER 是PHP中的一個超全局變量&#xff0c;它包含了諸如頭信息、路徑、腳本位置等…

數據結構與算法-圖論-最短路-拓展運用

選擇最佳路線 分析&#xff1a; 這是一道圖論中的最短路徑問題&#xff0c;目標是在給定的公交網絡中&#xff0c;找到從琪琪家附近的車站出發&#xff0c;到她朋友家附近車站&#xff08;編號為 s &#xff09;的最短時間。以下是對該問題的詳細分析&#xff1a; 問題關鍵信息…

AI知識架構之神經網絡

神經網絡:這是整個內容的主題,是一種模擬人類大腦神經元結構和功能的計算模型,在人工智能領域廣泛應用。基本概念:介紹神經網絡相關的基礎概念,為后續深入理解神經網絡做鋪墊。定義與起源: 神經網絡是模擬人類大腦神經元結構和功能的計算模型,其起源于對生物神經系統的研…

【江科協-STM32】5. 輸出比較

1. 輸出比較簡介 OC(Output Compare)輸出比較。 輸出比較可以通過CNT&#xff08;CNT計數器&#xff09;與CCR寄存器值的關系&#xff0c;來對輸出電平進行置1、置0或翻轉的操作&#xff0c;用于輸出一定頻率和占空比的PWM波形。 :::tip CNT計數器是正向計數器。它只能正向累…

C++ Primer 再探迭代器

歡迎閱讀我的 【CPrimer】專欄 專欄簡介&#xff1a;本專欄主要面向C初學者&#xff0c;解釋C的一些基本概念和基礎語言特性&#xff0c;涉及C標準庫的用法&#xff0c;面向對象特性&#xff0c;泛型特性高級用法。通過使用標準庫中定義的抽象設施&#xff0c;使你更加適應高級…

排查和解決線程池瓶頸問題案例

在分布式系統中&#xff0c;線程池的使用非常普遍&#xff0c;尤其是在處理異步任務時。然而&#xff0c;線程池的配置不當可能會導致性能瓶頸&#xff0c;進而影響系統的整體性能。本文將分享一個實際案例&#xff0c;介紹如何通過日志分析和線程池優化來解決系統中的性能瓶頸…

影響板材的熱導率有哪些因素?

板材熱導率受多種因素左右&#xff0c;可劃分為內部材料特性與外部環境條件兩大方面 內部材料特性 化學構成&#xff1a;不同化學元素及化合物組合形成的板材&#xff0c;熱導率表現大相徑庭&#xff1b;金屬板材&#xff0c;像銅與鋁&#xff0c;熱導率優異&#xff0c;這是…

給字符串加密解密

加密規則&#xff1a;輸入1a2b3c 輸出 abbccc 解密&#xff1a;輸入abbccc 輸出 1a2b3c 代碼&#xff1a; using System;namespace 加密解密 {class Program{static void Main(string[] args){Encryption("4b2a8p");Decryption("ppppppoovvv");Console.…

人工智能中的特征是什么?

什么是人工智能中的特征&#xff1f; 在人工智能中&#xff0c;特征&#xff08;feature&#xff09;是指從原始數據中提取出的、能夠代表數據關鍵信息并用于模型訓練的屬性或變量。特征通常是對原始數據的抽象或轉換&#xff0c;目的是捕捉數據中的模式、結構或相關性&#x…

20250226-代碼筆記05-class CVRP_Decoder

文章目錄 前言一、class CVRP_Decoder(nn.Module):__init__(self, **model_params)函數功能函數代碼 二、class CVRP_Decoder(nn.Module):set_kv(self, encoded_nodes)函數功能函數代碼 三、class CVRP_Decoder(nn.Module):set_q1(self, encoded_q1)函數功能函數代碼 四、class…

洛谷 P3628/SPOJ 15648 APIO2010 特別行動隊 Commando

題意 你有一支由 n n n 名預備役士兵組成的部隊&#xff0c;士兵從 1 1 1 到 n n n 編號&#xff0c;你要將他們拆分成若干特別行動隊調入戰場。出于默契的考慮&#xff0c;同一支特別行動隊中隊員的編號應該連續&#xff0c;即為形如 i , i 1 , ? , i k i, i 1, \cdo…

PCL源碼分析:曲面法向量采樣

文章目錄 一、簡介二、源碼分析三、實現效果參考資料一、簡介 曲面法向量點云采樣,整個過程如下所述: 1、空間劃分:使用遞歸方法將點云劃分為更小的區域, 每次劃分選擇一個維度(X、Y 或 Z),將點云分為兩部分,直到劃分區域內的點少于我們指定的數量,開始進行區域隨機采…

Go語言--語法基礎2--下載安裝

2、下載安裝 1、下載源碼包&#xff1a; go1.18.4.linux-amd64.tar.gz。 官方地址&#xff1a;https://golang.google.cn/dl/ 云盤地址&#xff1a;鏈接&#xff1a; https://pan.baidu.com/s/1N2jrRHaPibvmmNFep3VYag 提 取碼&#xff1a; zkc3 2、將下載的源碼包解壓…

lowagie(itext)老版本手繪PDF,包含頁碼、水印、圖片、復選框、復雜行列合并等。

入口類&#xff1a;exportPdf ? package xcsy.qms.webapi.service;import com.alibaba.fastjson.JSONArray; import com.alibaba.fastjson.JSONObject; import com.alibaba.nacos.common.utils.StringUtils; import com.ibm.icu.text.RuleBasedNumberFormat; import com.lowa…

3-2 WPS JS宏 工作簿的打開與保存(模板批量另存為工作)學習筆記

************************************************************************************************************** 點擊進入 -我要自學網-國內領先的專業視頻教程學習網站 *******************************************************************************************…

Ubuntu20.04之VNC的安裝使用與常見問題

Ubuntu20.04之VNC的安裝與使用 安裝圖形桌面選擇安裝gnome桌面選擇安裝xface桌面 VNC-Server安裝配置開機自啟 VNC Clientroot用戶無法登入問題臨時方案永久方案 安裝圖形桌面 Ubuntu20.04主流的圖形桌面有gnome和xface兩種&#xff0c;兩種桌面的安裝方式我都會寫&#xff0c…

Day46 反轉字符串

I. 編寫一個函數&#xff0c;其作用是將輸入的字符串反轉過來。輸入字符串以字符數組 s 的形式給出。 不要給另外的數組分配額外的空間&#xff0c;你必須原地修改輸入數組、使用 O(1) 的額外空間解決這一問題。 class Solution {public void reverseString(char[] s) {int i …

用FileZilla Server 1.9.4給Windows Server 2025搭建FTP服務端

FileZilla Server 是一款免費的開源 FTP 和 FTPS 服務器軟件&#xff0c;分為服務器版和客戶端版。服務器版原本只支持Windows操作系統&#xff0c;比如筆者曾長期使用過0.9.60版&#xff0c;那時候就只支持Windows操作系統。當時我們生產環境對FTP穩定性要求較高&#xff0c;比…