Conversation
pobratime
commented
Aug 4, 2026
…ring model loading), Model changes yet to be made, RayTracing pipeline destroyed, BvhTree needs to be fixed
…all good changes (at least i think so)
…source management
…line and Scene, Shader is yet to be made...
…es from files, after that we pass them to ThreadPool
Thread pool
- Updated .gitignore to exclude .zed files - Commented out rendering calls in MainController and Scene to disable rendering temporarily - Renamed and modified methods in RayTracingPipeline for better clarity and functionality - Added position, rotation, and scale methods to RayTracingModel - Changed BlasTree node structure for improved clarity - Introduced TlasTree class for handling top-level acceleration structures
…y (there will be) while writing the shader
|
@spaske00 Imam par pitanja vezanih za osvetlenje. Samo odgovorite na komentar da bi mi stiglo obavestenje kad budete mogli da odgovorite da Vas ne bi remetio. |
|
slobodno pisite, ja cu videti i odgovoriti prvom prilikom |
|
@spaske00 Mislim da Vam nesto oko mejla nijie u redu, pokusao sam vise puta danas da Vam posaljem pitanja ali svaki mejl se vrati, drugi mejlovi prolaze. |
|
Dodacu samo neka zapazanja, Vi slobodno odaberite pristupizmedju A ili B koji Vam se cini najbolji, oba su prihvatljiva. Takodje, dole izneto su samo predlozi i sta mi se cini da bi bilo optimalno u ovom konkretnom slucaju. Takodje, iz iznetih zapazanje ce te uociti da se svaki pristup moze dodatno otpakovati i imati nepokrivenih slucajeva i boljih resenja. Molim Vas, obratite paznju da cilj ovog konkretnog projekta nije da napravio klon Unreal Engine-a koji u svakoj mogucoj situaciji hendla sve moguce slucajeve, vec samo da na konkretnom zadatku provezbate sebe u implementaciji i razumevanju grafike. Shodno tome, ako zelite da implementirate sve ovo, nemam nista protiv, samo napred, ja cu Vam pomoci u svemu; samo imajte na umu i da u nekom trenutku treba ograniciti skup funkcionalnosti i podrzanih slucajeva kako bi se projekat kompletirao. :) Ako sam nesto propustio da odgovorim, slobodno pisite. Pristup ANema potrebe da se proverava emisivna tekstura po trouglu prilikom učitavanja. struct GPUPrimitive {
...
uint32_t materialIndex;
bool emissive;
};ili, još bolje, da se informacije ne bi duplirale: struct GPUMaterial {
...
int emissiveTextureIndex;
glm::vec3 emissiveFactor;
};Zatim: bool isEmissive(GPUMaterial material)
{
return material.emissiveTextureIndex >= 0 &&
dot(texture(u_Textures[material.emissiveTextureIndex], uv).rgb,
vec3(1.0)) > 0.0;
}E sad, tekstura moze da varira unutar jednog trougla. Zbog toga primitiva ne moze uvek jednostavno da se klasifikuje kao emisivna/neemisivna na osnovu svog materijala. Trougao moze imati emisivnu teksturu sa samo malim emisivnim regionom, ali to vec prevazilazi opseg projekta. Slobodno mozete staviti da je svojstvo materijala. struct GPUMaterial glm::vec3 emissiveFactor; Dakle, primitiva koja koristi materijal sa pozitivnom emisijom je emisivna. Pristup BNije bas najsrecnije resenje sa inzinjerske strane, ali moze da radi uz male modifikacije. Korišćenje Blender konvencije imenovanja kao što je: je sasvim ok kao konvencija asset pipeline-a za Vas projekat. Međutim, ja bih tu konvenciju prilikom učitavanja pretvorio u eksplicitne podatke engine-a: if (mesh->mName.C_Str() contains "_emissive")
{
material.emissive = true;
}Nakon učitavanja, renderer više ne bi trebalo da zavisi od konvencije. Još bolje, ako vec imate pristup Blender assetima, slobodno nakacite emisioni materijal u Blenderu omoguciti asimpu da ga ucita da bi se koristila semantika materijala, a ne konvencija. Izvor svetlaNije potrebna posebna struktura za ubrzavanje ako postoji samo nekoliko izvora svetla. Na primer: struct GPULightSource
{
AABB bounds;
glm::vec3 centroid;
};i: std::vector<GPULightSource> lightSources;mogu da se pošalju kao SSBO. Samo bih vodio racuna prilikom koriscenja centroid AABB-a kao stvarnu poziciju izvora svetla. Centroid može biti prilično udaljen od stvarne emisivne površine, naročito kod tankog ili konkavnog izvora svetla. Na primer, kod pravougaonog izvora, centroid AABB ce biti ispravan, ali za neki nepravilni oblik nece. Ako bas zelite do kraja da ga ispeglate, onda bi sacuvao ovako nesto struct GPULightSource
{
AABB bounds;
glm::vec3 position; // reprezentativna tačka
};gde je Opet, bilo bi poželjno da se uzorkuje tačka na površini izvora svetla, umesto da se uvek cilja jedna reprezentativna tačka. Ali za ovaj projekat reprezentativna tačka je sasvim dovoljna. Ako postoji samo nekoliko izvora svetla, algoritam može biti znatno jednostavniji: hit = tracePrimaryRay()
if hit.isEmissive:
return hit.emission
radiance = 0
for each light in lightSources:
lightPoint = sampleLight(light)
shadowRay = createRay(hit.position, lightPoint)
if isVisible(shadowRay, lightPoint):
radiance += calculateDirectLighting(hit, lightPoint)
return radianceTakodje
je malo problematična. AABB samo govori da zrak ulazi u okvirnu zapreminu objekta, ali ne i da zaista dolazi do emisivne geometrije. Na kraju je ipak potrebna provera vidljivosti prema stvarnoj geometriji izvora svetla. Pogodak primitive
Ja bih ovo drugačije formulisao u rendereru. Isti trougao može biti:
Zbog toga je: primitive.isIlluminatedgeneralno pogrešna apstrakcija. Umesto toga, zgodnije bi bilo Pogodak ima:
a zatim shader/path tracer izračunava: radiance_at_hit =
emission
+ direct_lighting
+ reflected_radianceSubmodeliEngine trenutno ignorise podpodele, slobodno dodajte funkcionalnost ako Vam je potrebna :) Teksture u GLSL-uSlobodno mozete: sampler2D textures[16];
sampler2D emissiveTextures[16];Samo napravite eksplicitno indeksiranje struct GPUMaterial
{
int albedoTexture;
int normalTexture;
int roughnessTexture;
int metallicTexture;
int emissiveTexture;
};RTAO vs PBROdabrao bih RTAO za ovaj projekat. |
|
@spaske00 Sto se tice komentara sa kojim ste zapoceli odgovor, u potpunosti ste u pravu, nije tema projekta napraviti klon Unreal Engine-a. Svestan sam toga no elem to vuce ono sto sam jos u prvom mejl pisao, cista nezasitost onim sto napravim. Imao sam 2 forka pre ovoga koja sam u potpunosti obrisao. Jedan je radio ray marching, te sam mogao da prikazem matematicke figure => ne svidja mi se ovo ocu modele, nakon toga napravim modele => fps je nizak, ocu da bude brze => implementiram blas, mogu samo jedan model => ne moze to tako ocu tlas => sad nemam teksture treba mi i to itd. itd. i tako se moze ici u nedogled. Ali potpuno ste u pravu u jednom trenutku treba reci dosta i zaokruziti stvari. Trenutno se unutar Ostali saveti su sve top, primenicu. To sto ste rekli da mogu da odradim ono da bi ispeglao do kraja, odradicu to. Kad sam vec uzeo ovoliko da zagrizem i krenuo da radim sve ovo nije okej da sad pred kraj odustanem :). |
|
Nekako ovako bi izgledalo: CPU / ucitavanje modelaNeki tok podataka bi bio Model
|
Meshes + materijali
|
Identifikovanje emisivnih primitiva
|
Za svaku emissivnu primitivu:
transformisi vertekse u world space
izracunati povrsine trouglova i centroid
AABB
|
GPU LightSource[]struct GPULightSource {
glm::vec3 position;
AABB bounds;
};Ovo saljemo kao SSBO. GLSL GPUShader dobija: struct GPULightSource {
vec3 position;
AABB bounds;
};
layout(std430, binding = ...) buffer LightSources {
GPULightSource lights[];
};
uniform int u_LightCount;Postojeći podaci o primitivima/materijalima odreduju materijal u tacki pogotka zraka, dalje algoritam je:
Na mestu pogotka: Hit hit = traceRay(ray);
if (hit.material.isEmissive)
return evaluateEmission(hit);ako je promasaja ide standardno ostatak algoritma. Neka podela posla bi bila da CPU obavlja ekstrakciju izvora svetlosti, dok GLSL obavlja transport svetlosti/shading. Opet, ovo je sve ugrubo, da Vam da skicu, nije jedini pristup i slobodno prilagodite za potrebe Vaseg projekta. Takodje, ne mora da bude idealno, i ne mora da bude savrseno efikasno. |
@spaske00 Mislim da se opet nismo razumeli, vec Vam previse vremena oduzimam. Sve sto ste opisali je nesto sto nije problem uz malo logike srediti i napraviti kako treba uraditi ovaj pipeline slanja podataka, i u pocetnom pitanju je kod mene isti stvar problem. Model
|
Meshes + materijali
|
Identifikovanje emisivnih primitiva // <- Ovo ovde
|
Za svaku emissivnu primitivu:
transformisi vertekse u world space
izracunati povrsine trouglova i centroid
AABB
|
GPU LightSource[]Problem je identifikacije emisivnih primitiva na C++ strani. Kada model ima teksturu emisiv onda je npr 80% crna i 20% neka druga boja. Kada u sejderu pogodimo zrak to je lako procitati. Ali mi nekakav ovakav podatak moramo i sa C++ strane srediti, da bi izracunali mesto izvora svetla.
Nije problem slanje, kreiranje ili ucitavanje. Problem je pre kreiranja treba izdvojiti primitive koji su emisivni. Kako izdvojiti primitive koji su emisivni? |
Taman posla, sve pet, razjasnicemo, vrv sam i ja nesto pogresno razumeo :)
Aha, na osnovu materijala, zar ne? Mozete uvesti ogranicenje da je primitiva emisivna ako ima prikljucen emisivni materijal. |
|
@spaske00 GLSL
enum class TextureType {
Regular,
Diffuse,
Specular,
Normal,
Height,
Emissive,
Metalness,
DiffuseRoughness,
AmbientOcclusion
};A sve teksture se cuvaju u uniform sampler2D u_Textures[16];Moguce je da mi ne trebaju sve teksture izbacicu ono sto mi ne treba, ali svakako ne smeta funkcionalnosti. vec3 texture_primitive(GPUPrimitive tri, GPUInstance inst) {
int diff_idx = int(tri.t_idx.x);
int spec_idx = int(tri.t_idx.y);
int norm_idx = int(tri.t_idx.z);
int high_idx = int(tri.t_idx.w);
float u = primitive_hit.uv.x;
float v = primitive_hit.uv.y;
float w = 1.0f - u - v;
vec2 interpolated_uv = w * tri.uv0.xy + u * tri.uv1.xy + v * tri.uv2.xy;
vec3 diff_color = (diff_idx != -1) ? textureLod(u_Textures[diff_idx], interpolated_uv, 0.0).rgb : vec3(1.0f);
vec3 norm_color = (norm_idx != -1) ? textureLod(u_Textures[norm_idx], interpolated_uv, 0.0).rgb : vec3(0.5, 0.5, 1.0);
float spec_color = (spec_idx != -1) ? textureLod(u_Textures[spec_idx], interpolated_uv, 0.0).r : 0.2f;
return diff_color;
}
Obrada podataka C++Okej znaci ajde da napravimo neku klasu, strukturu uz par f-ja, bilo kakav pristup da oformimo nesto ovako. Za ovo su nam potrebni sirovi podaci pri ucitavanju. Nikakav problem imamo pristup njima. Uzmemo podatke, umemo da ih obradimo. Primitivi se pokupe, izracuna se centroid svakog, globalni centroid, poveze se sa struct GPUInstance {
glm::mat4 world_to_local; // ZBOG OVOGA
glm::mat4 local_to_world; // ZBOG OVOGA
uint32_t blas_root_index;
uint32_t material_index;// TODO change later <- apsolutni visak treba da se pretvori u pad
uint32_t pad0;
uint32_t pad1;
};world_to_local local_to_world, jer iako je emitvan deo poseban i saljemo nesto zaesbno za njega, on je i dalje deo istog modela i za njega vaze ista pravila kao sto vaze i za ostatak modela, ne zelimo da se moddel razdvoji. A i treba nam da bi mogli da prolazimo kroz tlas i proverimo da li je hitId modela koji je hitovan i id modela kojeg je izvor svetla deo isti. Znaci umemo da naravimo ovo. Ucitavanje i izdvajanje podataka C++Znaci mi nekako moramo umeti da prepoznamo koji delovi modela su emisivni. Ovo moramo raditi pri ucitavanju, jer tada imamo pristup "raw" podacima koji nam trebaju. Ajde da se vratimo na pocetnu pp. da ucitavamo lampu, da se sastoji iz sijalice, tela i glave. Sijalica, telo, glava i dalje dele isi .gltf fajl, dele iste teksture (u smisli da je u istom .jpg fajlu za npr. difuzunivnu teksturu cela lampa, nije odvojeno kao sto je slucaj sa nekim drugim modelima, ali je i dalje lampa sastavljena od sub-modela sub-mesheva). OPCIJA 1:void AssimpSceneProcessor::process_node(const aiNode *node) {
for (uint32_t i = 0; i < node->mNumMeshes; ++i) {
auto mesh = m_scene->mMeshes[node->mMeshes[i]];
process_mesh(mesh);
}
for (uint32_t i = 0; i < node->mNumChildren; ++i) {
process_node(node->mChildren[i]);
}
}Imamo ovu funkciju. Sijalica je poseban deo modela lampe, Okej ajde da odradimo nesto sa, OPCIJA 2:// FIXED sub-mesh loading
void AssimpSceneProcessor::process_mesh(aiMesh *mesh) {
std::vector<Vertex> vertices;
vertices.reserve(mesh->mNumVertices);
for (unsigned int i = 0; i < mesh->mNumVertices; ++i) {
vertices.push_back(extract_vertex(mesh, i));
}
const std::vector<uint32_t> indices = extract_indices(mesh);
const auto material = m_scene->mMaterials[mesh->mMaterialIndex];
std::vector<Texture *> textures = process_materials(material);
if (m_loading_model_rt) {
// ovo promeniti koristiti materialId kao sto je marko preporucio a unutar materialId staviti indekse ovih stvar
glm::vec4 tex_indices_a{-1.0f};
glm::vec4 tex_indices_b{-1.0f};
for (const auto &tex: textures) {
if (!tex) continue;
switch (tex->type()) {
case TextureType::Diffuse: tex_indices_a.x = static_cast<float>(tex->index()); break;
case TextureType::Specular: tex_indices_a.y = static_cast<float>(tex->index()); break;
case TextureType::Normal: tex_indices_a.z = static_cast<float>(tex->index()); break;
case TextureType::Height: tex_indices_a.w = static_cast<float>(tex->index()); break;
case TextureType::Emissive: tex_indices_b.x = static_cast<float>(tex->index()); break;
case TextureType::Metalness: tex_indices_b.y = static_cast<float>(tex->index()); break;
case TextureType::DiffuseRoughness: tex_indices_b.z = static_cast<float>(tex->index()); break;
case TextureType::AmbientOcclusion: tex_indices_b.w = static_cast<float>(tex->index()); break;
default: break;
}
}
const size_t num_triangles = indices.size() / 3;
for (size_t i = 0; i < num_triangles; ++i) {
m_rwg.texture_indexes.push_back(tex_indices_a);
m_rwg.texture_indexes.push_back(tex_indices_b);
}
const auto base_index = static_cast<uint32_t>(m_rwg.vertices.size());
for (const uint32_t idx: indices) {
m_rwg.indices.push_back(base_index + idx);
}
m_rwg.vertices.insert(m_rwg.vertices.end(), vertices.begin(), vertices.end());
} else {
m_meshes.emplace_back(Mesh(vertices, indices, std::move(textures)));
}
}(Ovde treba promeniti ovo sa dva Nadam se da sam se sada lepo izrazio. Pitanje je kako unutar modela koji u sebi ima deo koje je izvor svetla izvuci samo primitive koji su izvor svetla. Nije problem njihovo cuvanje, obrada i slanje, vec kako ih pronaci. Nadam se da sam Vam sad lepse opisao. |
|
Preimenovacu nazive meshova i podmodela u blenderu, smislio sam ideju kako bi moglo da funkcionise 2. pristup ali previse izmena zahteva i trebala bi mi zasebna klasa za procesuiranje ovih stvari. Nije najlepsa praksa kao sto smo rekli da engine zavisi od naziva modela ali valjda mozemo reci da je "okej" za potrebe projekta. |
|
@spaske00 Trebalo bi da je projekat zaokruzen manje vise, to je ta struktura. Dodato je jos par modela i neke izmene su napravljene. Ako zelite da pulujete projekat da pogledate da li sve izgleda okej, mogu vam proslediti link do modela ili ih samo skloniti iz .gitignore. Ako imate neke zamerke, skrenite mi paznju da bi ih ispravio sto pre. Kod mene na laptopu se projekat ne pokrece najlepse, dosta secka i ima 5-15 fpsa, na kompjuteru je dosta stabilnije, da znate samo unapred ako budete hteli da pokrecete. |
|
@pobratime dodajte molim Vas i modele da bih mogao kod mene pokrenuti |
|
@spaske00 Odradjeno. Mozete pogledati. |
|
Top, sve radi! Projekat je fenomenalan, stvarno ste se potrudili! Sve cestitke od mene za trud i rad! Nadam se da Vam je bilo zanimljivo. Na sutrasnjem poslu u industriji iteracija na nekom zadatku Dakle:
Jedino sto bi mozda PR-ovi bili manji, ali sve u svemu ovo je opsta slika. Eto, to je sutra manje vise ono sto Vas ceka na poslu :) Samo prijavite projekat preko stranice, odbranu cemo zakazati pred ispitni rok. |

