SAMSUNG_032023 Advertisement SAMSUNG_032023 Advertisement SAMSUNG_032023 Advertisement

Python: PyGLSL v2.1 / 32. časť

0

V tejto časti seriálu o programovaní v jazyku Python sa poslednýkrát vrátime k aplikácii PyGLSL. Počas prípravy jej druhej verzie, v rámci ktorej sme na vykreslenie jednoduchej 3D scény využili funkcionalitu API Vulkan, sme sa zmienili, že definíciu vrcholov a farieb dvojice trojuholníkov, ktoré sú obsahom našej scény, sme zahrnuli do kódu shaderov. Navyše v spomínanej verzii aplikácie sme na pokrytie trojuholníkov použili jednoduché farby bez aplikácie textúrovania. Externú definíciu vrcholov a textúrovanie síce možno implementovať relatívne drobnými úpravami kódu, spomínaná funkcionalita je však neodmysliteľnou súčasťou moderných 3D aplikácií, a preto ju nesmieme opomenúť.

SAMSUNG_032023_M Advertisement

Definícia atribútov vrcholov

Objekty počítačovo generovaných 3D scén sú zväčša zložené z trojuholníkov, ktoré sú definované tromi vrcholmi. Každý z uvedených vrcholov môže mať viacero atribútov (vlastností), medzi ktoré okrem iných patrí najmä poloha, farba a textúrovacie súradnice. Poloha sa zväčša uvádza ako trojica údajov X, Y, Z, farba ako trojica údajov R, G, B a textúrovacie súradnice ako dvojica údajov U, W. Význam konkrétnych atribútov vrcholov sme v našich seriáloch o programovaní počítačovej grafiky predstavili už mnohokrát. V každom prípade pri tvorbe 3D objektov definujeme zväčša vrcholy trojuholníkov, ktorých atribúty musíme zadať buď ručne, alebo prostredníctvom nejakého automatizovaného procesu. V prípade aplikácie PyGLSL v2.1 sme definíciu atribútov vrcholov umiestnili do funkcie prepare3Dobjects(), ktorú voláme pred volaním funkcie initVulkan() a spustením hlavného programového cyklu funkciou mainLoop().

Na to, aby sme spomínané atribúty vrcholov dokázali použiť v rámci API Vulkan, musíme ich uložiť do tzv. zásobníka vrcholov (vertexBuffer, pozn.: spomeňme si na tzv. Vertex Buffer Object – VBO, ktorý sme používali v minulosti), ktorý následne pripojíme k príslušnému commandBuffer prostredníctvom funkcie vkCmdBindVertexBuffers().

Okrem už opísaných krokov musíme príslušný Vertex Shader informovať o spôsobe prepojenia jeho lokálnych premenných s externými atribútmi vrcholov. Na to sme pripravili triedu s názvom Vertex, v rámci ktorej sme definovali funkcie getVertexBindingDescription() a getVertexAttributeDescriptions(). Tie sú volané pri vytváraní GraphicsPipeline v rámci funkcie vkCreateGraphicsPipelines(), konkrétne jej štruktúry VkGraphicsPipelineCreateInfo() a atribútu pVertexInputState=PipelineVertexInputStateCreateInfo.

Obr. 1 Transformácia údajov (atribútov) vrcholov

 

Textúrovanie

V prípade implementácie textúrovania je situácia jemne zložitejšia. Okrem definície textúrovacích súradníc, ktoré sme zahrnuli medzi atribúty vrcholov, musíme v prvom rade vykonať všetky kroky súvisiace s nahratím obrázka textúry a následne s definíciou tzv. DescriptorSet. Oba kroky riešime v rámci funkcie initVulkan() hneď po tom, ako vytvoríme commandPool. Časť nahratia textúry spočíva vo vytvorení príslušného zásobníka (createBuffer), vytvorení obrazu (createImage), skopírovaní obsahu zásobníka do obrazu (copyBufferToImage), vytvorení ImageView (createImageView) a vytvorení príslušného Samplera (createSampler). Po vykonaní predošlých krokov získame ImageViewSampler, ktorý je vstupom pre DescriptorSet.

DescriptorSet

Prostredníctvom DescriptorSet prepojíme ImageViewSampler s príslušným Fragment Shaderom. Množina funkcií súvisiaca s DescriptorSet je nasledujúca:

vkCreateDescriptorSetLayout()

Pripojenie Uniform Buffer Object (UBO)SamplerFragment Shaderu:

Binding=0 – UBO (nepoužité v rámci aplikácie)

Binding=1 – Sampler

 

V rámci Fragment Shadera:

layout(binding = 1) uniform sampler2D texSampler;

 

Výstup je použitý pri vytváraní GraphicsPipeline v rámci funkcie vkCreatePipelineLayout(), konkrétne jej štruktúry VkPipelineLayoutCreateInfo() a atribútu pSetLayouts= DescriptorSetLayoutInfo.

 

Navyše je výstup použitý pri vytváraní DescriptorSet v rámci funkcie vkAllocateDescriptorSets(), konkrétne jej štruktúry VkDescriptorSetAllocateInfo() a atribútu pSetLayouts=descriptorSetLayout.

vkCreateDescriptorPool()

Vytvorenie DescriptorPool

 

Výstup je použitý pri vytváraní DescriptorSet v rámci funkcie vkAllocateDescriptorSets(), konkrétne jej štruktúry VkDescriptorSetAllocateInfo() a atribútu descriptorPool= vkCreateDescriptorPool().

vkUpdateDescriptorSets()

Zápis konkrétnych DescriptorSet:

dstBinding=0 – UBO (nepoužité v rámci aplikácie)

dstBinding=1 – Sampler

 

Práve v rámci štruktúry VkDescriptorImageInfo(), ktorá je vstupom pre vkUpdateDescriptorSets(), sú použité

textureImageViewtextureSampler, ktoré sme vytvorili v časti nahrávania a prípravy textúry.

 

Posledné dva kroky, ktoré musíme vykonať na úspešnú aplikáciu textúrovania, sú nasledujúce:

  1. Pripojiť DescriptorSet k príslušnému commandBuffer prostredníctvom funkcie vkCmdBindDescriptorSets().
  2. Upraviť obsah Fragment Shader tak, aby obsahoval lokálnu uniform premennú typu sampler2D a aby sa údaje načítané z textúry použili na výpočet výslednej farby fragmentu. K tomuto výpočtu, samozrejme, musíme ako vstup doplniť príslušné textúrovacie súradnice.


Obr. 2 Grafický výstup aplikácie PyGLSL v2.1

 

Zobrazit Galériu

Marek Sopko

Všetky autorove články

Pridať komentár

Mohlo by vás zaujímať

Mohlo by vás zaujímať