ich versuche gerade einfaches View Frustum Culling zu realisieren. Irgendeine Kleinigkeit scheine ich aber zu übersehen.
Die Idee hinter meinem Ansatz ist, dass jedes Objekt eine Kugel zugewiesen bekommt, dessen Zentrum der Mittelwert der Vertexpositionen (lokal zum Objekt Mittelpunkt) des Objektes ist und dessen Radius, der Abstand zum am weitesten entfernten Vertex ist.
Das sieht bei mir dann so aus:
Code: Alles auswählen
void sgObject::initCullSphere()
{
sgVector3 center;
float radius = 0;
float temp;
sgVector3 diff;
for(int m = 0; m < meshs.size(); m++)
{
//Calculate the center
for(int i = 0; i < meshs[m]->vertexnum; i++)
{
center += meshs[m]->vertices[i].position;
}
center /= meshs[m]->vertexnum;
//Find the radius
radius = 0;
for(int i = 0; i < meshs[m]->vertexnum; i++)
{
diff = meshs[m]->vertices[i].position-center;
temp = diff.length();
if(radius < temp)
radius = temp;
}
meshs[m]->cullsphere = sgVector4(center.x, center.y, center.z, radius);
}
}
Die nächste Transformation bringt den Kugelmittelpunkt in den Raum der Kamera und anschließend multiplitziere ich noch mit meiner Projektionsmatrix. Nach meinem Verständnis, ist der Mittelpunkt der Kugel nun immer dann sichtbar, wenn w positiv (und < clipfar) ist und x und y zwischen -1 und 1 sind. Soweit scheint auch alles zu klappen. Nun muss aber natürlich auch der Radius noch mit einfließen und dazu muss ich auch diesen noch irgendwie projizieren, so dass ich die 1 - -1 Grenzen um diesen erweitern kann. Dazu habe ich mir überlegt, dass ich zwei Positionen aus dem radius relativ zur Kamera konstruiere, die ich dann projiziere. Diese sind (radius|0|mittelpunkt.w|1) und (0|radius|mittelpunkt.w|1). Hier pflücke ich mir dann x, bzw y heraus und erweitere meine Grenzen damit. Das Ergebniss ist dann aber dass alles was den Rand schneidet geculled wird, wenn ich den Einfluss vom Radius bei den Punkten invertiere passt es dann besser, was ich aber auch irgendwie komisch finde.
Im Code sieht dies derzeit so aus:
Code: Alles auswählen
void sgRenderer::culling(sgCamera *cam)
{
sgMatrix4x4 projview = cam->matproj*cam->matview;
sgMatrix4x4 projviewmodel;
sgVector4 pos;
sgVector4 temp;
sgVector2 radius;
for(sgObject *obj = first_solid->next; obj != NULL; obj = obj->next)
{
obj->culled = false;
for(int i = 0; i < obj->meshs.size(); i++)
{
//Transformation and projection
pos = obj->meshs[i]->cullsphere;
projviewmodel = projview*obj->matmodel;
pos.w = 1.0;
pos = projviewmodel*pos;
pos.x /= pos.w;
pos.y /= pos.w;
//Projection of the radius
temp = sgVector4(-obj->meshs[i]->cullsphere.w, 0.0, pos.w, 1.0);
temp = cam->matproj*temp;
radius.x = temp.x/temp.w;
temp = sgVector4(0.0, -obj->meshs[i]->cullsphere.w, pos.w, 1.0);
temp = cam->matproj*temp;
radius.y = temp.y/temp.w;
//Check for visibility
if((pos.x < 1.0+radius.x && pos.x > -1.0-radius.x && pos.y < 1.0+radius.y && pos.y > -1.0-radius.y && pos.w > 0) || (abs(pos.w) <= obj->meshs[i]->cullsphere.w))
obj->meshs[i]->culled = false;
else
obj->meshs[i]->culled = true;
}
}
}
Meine Projektionsmatrix sieht übrigens so aus:
Code: Alles auswählen
void sgMatrix4x4::makeProjectionPersp(float arc, float aspect, float clipnear, float clipfar)
{
memset(mat, 0, sizeof(float)*16);
float xFac, yFac;
yFac = tanf(arc * 3.14f/360);
xFac = yFac*aspect;
mat[0] = 1/xFac;
mat[5] = 1/yFac;
mat[10] = -(clipfar+clipnear)/(clipfar-clipnear);
mat[11] = -1;
mat[14] = -(2*clipfar*clipnear)/(clipfar-clipnear);
}
Nils