Ciao a tutti, oggi mi sono un pò divertito a chiedere a chatGPT di scrivermi un codice di HSR software, gestito dalla cpu. In buona sostanza, gli ho chiesto una cosa semplice, ovvero che la cpu, durante la fase di trasform, clipping and lighting, determini quali siano i triangoli visibili e quali quelli nascosti, tenendo presente che alcuni di essi possano essere trasparenti. Inoltre, per non creare troppa attesa alla scheda video (altrimenti solo al termine di tutti i test avrebbe inviato i soli triangoli visibili alla scheda), gli ho detto che ogni qualvolta un triangolo risulta visibile dal test di profondità lo deve anche immediatamente inviare alla scheda video, mentre solo quelli sicuramente nascosti li dovrà scartare. Chiaramente è un metodo semplice che non azzera l'overdraw, ma penso possa venire incontro alle cpu meno potenti, e inoltre, se non ricordo male, i giochi venivano programmati con delle tecniche front to back, ovvero iniziare l'elaborazione geometrica dai triangoli più prossimi al soggetto: così si avrebbero alte probabilità di inviare alla scheda video i soli triangoli realmente visibili...
Si tratta pertanto di una tecnica di HSR applicata ai triangoli, senza andare a lavorare sui singoli pixel. Tradotto: soltanto i triangoli completamente nascosti vengono scartati, mentre se anche un solo pixel di un triangolo sarà visibile, l'intero triangolo sarà elaborato.
In ogni caso, ecco il risultato! Qualcuno che abbia voglia di ragionarci su???
#include <iostream>
#include <vector>
struct Triangle {
float x1, y1, z1; // Coordinate del primo vertice
float x2, y2, z2; // Coordinate del secondo vertice
float x3, y3, z3; // Coordinate del terzo vertice
float transparency; // Trasparenza del triangolo (0.0 - 1.0)
};
// Dimensioni del frame buffer
const int framebufferWidth = 800;
const int framebufferHeight = 600;
// Buffer di profondità
float depthBuffer[framebufferWidth][framebufferHeight];
// Funzione per il calcolo dell'area di un triangolo
float CalculateTriangleArea(float x1, float y1, float x2, float y2, float x3, float y3) {
return std::abs((x1*(y2-y3) + x2*(y3-y1) + x3*(y1-y2)) / 2);
}
// Funzione per determinare la visibilità di un triangolo e inviarlo immediatamente alla scheda video se visibile
bool CheckAndRenderTriangle(const Triangle& triangle) {
// Calcolo dell'area del triangolo
float area = CalculateTriangleArea(triangle.x1, triangle.y1, triangle.x2, triangle.y2, triangle.x3, triangle.y3);
// Iterazione sui pixel all'interno del bounding box del triangolo
int minX = std::min({triangle.x1, triangle.x2, triangle.x3});
int maxX = std::max({triangle.x1, triangle.x2, triangle.x3});
int minY = std::min({triangle.y1, triangle.y2, triangle.y3});
int maxY = std::max({triangle.y1, triangle.y2, triangle.y3});
bool visibleTriangleFound = false; // Flag per indicare se è stato trovato un triangolo visibile
for (int y = minY; y <= maxY; y++) {
for (int x = minX; x <= maxX; x++) {
// Calcolo delle coordinate baricentriche del punto
float alpha = CalculateTriangleArea(x, y, triangle.x2, triangle.y2, triangle.x3, triangle.y3) / area;
float beta = CalculateTriangleArea(triangle.x1, triangle.y1, x, y, triangle.x3, triangle.y3) / area;
float gamma = CalculateTriangleArea(triangle.x1, triangle.y1, triangle.x2, triangle.y2, x, y) / area;
// Verifica se il punto è all'interno del triangolo
if (alpha >= 0 && beta >= 0 && gamma >= 0) {
// Calcolo del valore Z interpolato
float interpolatedZ = alpha * triangle.z1 + beta * triangle.z2 + gamma * triangle.z3;
// Verifica la visibilità del punto tramite il buffer di profondità
if (interpolatedZ < depthBuffer
// Invio del triangolo alla scheda video per il rendering
// ...
visibleTriangleFound = true; // Indica che è stato trovato un triangolo visibile
// Esci dalla funzione, inviando solo il primo triangolo visibile
return true;
}
}
}
}
return visibleTriangleFound; // Restituisce true se è stato trovato almeno un triangolo visibile
}
int main() {
// Inizializzazione del buffer di profondità
for (int y = 0; y < framebufferHeight; y++) {
for (int x = 0; x < framebufferWidth; x++) {
depthBuffer
}
// Esempio di utilizzo
std::vector<Triangle> triangles; // Vettore dei triangoli della scena
// Aggiungi i triangoli della scena al vettore 'triangles'
// ...
// Itera sui triangoli e invia i triangoli visibili alla scheda video
for (const Triangle& triangle : triangles) {
if (CheckAndRenderTriangle(triangle)) {
// Se è stato trovato un triangolo visibile, passa al triangolo successivo
continue;
}
// Se nessun triangolo visibile è stato trovato, determina i restanti triangoli
// ...
}
return 0;
}
Si tratta pertanto di una tecnica di HSR applicata ai triangoli, senza andare a lavorare sui singoli pixel. Tradotto: soltanto i triangoli completamente nascosti vengono scartati, mentre se anche un solo pixel di un triangolo sarà visibile, l'intero triangolo sarà elaborato.
In ogni caso, ecco il risultato! Qualcuno che abbia voglia di ragionarci su???

#include <iostream>
#include <vector>
struct Triangle {
float x1, y1, z1; // Coordinate del primo vertice
float x2, y2, z2; // Coordinate del secondo vertice
float x3, y3, z3; // Coordinate del terzo vertice
float transparency; // Trasparenza del triangolo (0.0 - 1.0)
};
// Dimensioni del frame buffer
const int framebufferWidth = 800;
const int framebufferHeight = 600;
// Buffer di profondità
float depthBuffer[framebufferWidth][framebufferHeight];
// Funzione per il calcolo dell'area di un triangolo
float CalculateTriangleArea(float x1, float y1, float x2, float y2, float x3, float y3) {
return std::abs((x1*(y2-y3) + x2*(y3-y1) + x3*(y1-y2)) / 2);
}
// Funzione per determinare la visibilità di un triangolo e inviarlo immediatamente alla scheda video se visibile
bool CheckAndRenderTriangle(const Triangle& triangle) {
// Calcolo dell'area del triangolo
float area = CalculateTriangleArea(triangle.x1, triangle.y1, triangle.x2, triangle.y2, triangle.x3, triangle.y3);
// Iterazione sui pixel all'interno del bounding box del triangolo
int minX = std::min({triangle.x1, triangle.x2, triangle.x3});
int maxX = std::max({triangle.x1, triangle.x2, triangle.x3});
int minY = std::min({triangle.y1, triangle.y2, triangle.y3});
int maxY = std::max({triangle.y1, triangle.y2, triangle.y3});
bool visibleTriangleFound = false; // Flag per indicare se è stato trovato un triangolo visibile
for (int y = minY; y <= maxY; y++) {
for (int x = minX; x <= maxX; x++) {
// Calcolo delle coordinate baricentriche del punto
float alpha = CalculateTriangleArea(x, y, triangle.x2, triangle.y2, triangle.x3, triangle.y3) / area;
float beta = CalculateTriangleArea(triangle.x1, triangle.y1, x, y, triangle.x3, triangle.y3) / area;
float gamma = CalculateTriangleArea(triangle.x1, triangle.y1, triangle.x2, triangle.y2, x, y) / area;
// Verifica se il punto è all'interno del triangolo
if (alpha >= 0 && beta >= 0 && gamma >= 0) {
// Calcolo del valore Z interpolato
float interpolatedZ = alpha * triangle.z1 + beta * triangle.z2 + gamma * triangle.z3;
// Verifica la visibilità del punto tramite il buffer di profondità
if (interpolatedZ < depthBuffer
- [y]) {
- [y] = interpolatedZ;
// Invio del triangolo alla scheda video per il rendering
// ...
visibleTriangleFound = true; // Indica che è stato trovato un triangolo visibile
// Esci dalla funzione, inviando solo il primo triangolo visibile
return true;
}
}
}
}
return visibleTriangleFound; // Restituisce true se è stato trovato almeno un triangolo visibile
}
int main() {
// Inizializzazione del buffer di profondità
for (int y = 0; y < framebufferHeight; y++) {
for (int x = 0; x < framebufferWidth; x++) {
depthBuffer
- [y] = std::numeric_limits<float>::max(); // Valore iniziale massimo
}
// Esempio di utilizzo
std::vector<Triangle> triangles; // Vettore dei triangoli della scena
// Aggiungi i triangoli della scena al vettore 'triangles'
// ...
// Itera sui triangoli e invia i triangoli visibili alla scheda video
for (const Triangle& triangle : triangles) {
if (CheckAndRenderTriangle(triangle)) {
// Se è stato trovato un triangolo visibile, passa al triangolo successivo
continue;
}
// Se nessun triangolo visibile è stato trovato, determina i restanti triangoli
// ...
}
return 0;
}