Ich arbeite an einem Raytracer mit C++ und konnte bisher ein Beleuchtungsmodell basierend auf diffusen, spiegelnden und ambienten Komponenten berechnen. Mein Problem erschien, als ich versuchte Schatten meiner Szenen hinzuzufügen: die Szenen wirklich erhalten verkorkste:Unerwartetes Ergebnis beim Berechnen von Schatten in einem Raytracer
Mein Code wie folgt unterteilt:
- Ich habe eine Basisklasse „Szenenobjekt“ , die eine virtuelle Methode intersect() hat, die einen Strahl (definiert durch Ursprung und Richtung) nimmt und einen booleschen Wert sowie Rückgabeargumente für den berechneten t-Wert, einen Trefferpunkt und die Normale des Objekts ausgibt.
- Die Klasse "Material" enthält eine spiegelnde und diffuse Farbe (Vektoren) sowie einen Wert für einen Phong-Exponenten (int).
- Ich habe 3 abgeleitete Klassen aus dem obigen SceneObject: Ebenen-, Dreieck- und Kugelklassen, jede mit ihrer eigenen Version des in der Basisklasse definierten Schnittpunkts.
- Ich habe eine Funktion, die Ausgabefarbe für ein bestimmtes Pixel unter Verwendung der Normalen des Objekts, des Hitpoints, einer Lichtquelle und des Objektmaterials berechnet.
- Alle meine Objekte zu rendern sind in einem Vektor gespeichert.
Hier ist eine meiner abgeleiteten Klassen, Dreieck:
class Triangle: public SceneObject{
public:
Triangle (vec3 a, vec3 b, vec3 c, Material mat){
name = "Triangle";
p0 = a;
p1 = b;
p2 = c;
objectMaterial = mat;
normal = normalize(cross(p0-p1, p0-p2));
}
//Möller-Trumbore algorithm
bool intersect(Ray aRay, float &t, vec3 &hitPoint, vec3 &n){//we will use ray-plane intersection and barycentric coords:
bool returnValue = false;
//first we need to get a t of intersection between the passed ray and the triangle
vec3 v0v1 = p1-p0;
vec3 v0v2 = p2-p0;
vec3 pvec = cross(aRay.getDirection(), v0v2);
float det = dot(v0v1, pvec);
if (det >= 1e-6){ // Only draw if not backfacing
float invDet = 1/det;
float u = dot(-p0, pvec) * invDet;
// No intersection if u < 0 or u > 1
if (u >=0 && u <= 1) {
vec3 qvec = cross(-p0, v0v1);
float v = dot(aRay.getDirection(), qvec) * invDet;
// No intersection if v < 0 or u + v > 1
if (v >=0 && (u + v) <= 1){
t = dot(v0v2, qvec) * invDet;
returnValue = true;
hitPoint = aRay.getOrigin() + (t*aRay.getDirection());
n = normal;
//calculated_Out_Colour = calculateOutputColour(normal, aRay, lightSource, objectMaterial, t, hitPoint);
}
}
}
return returnValue;
}
private:
vec3 p0;
vec3 p1;
vec3 p2;
vec3 normal;
};
Und das ist meine Hauptschleife, wo ich meine Strahlen alle für jedes Pixel von meinem Fenster erzeugen, und die Farbe zu bestimmen und wenn die aktuellen Position im Schatten befindet oder nicht:
for(int i=0;i<imageBuffer.Height();i++){
for(int j=0;j<imageBuffer.Width();j++){
float currentX = ((float)i-256);
float currentY = ((float)j-256);
//cout << currentX << ", " << currentY << ", " << currentZ << endl;
//make a ray for this pixel (i,j)
glm::vec3 rayDirection = glm::normalize(glm::vec3(currentX, currentY, -d));
//make a ray for this pixel (i,j)
Ray currentRay(vec3(0,0,0), rayDirection);
vec3 hitPoint;
vec3 normalAtHit;
float tnear = 999; // closest intersection, set to INFINITY to start with
SceneObject* object = NULL;
for (int k = 0; k < objects.size(); k++) {
float t; // intersection to the current object if any
if (objects[k]->intersect(currentRay, t, hitPoint, normalAtHit) && t < tnear) {
object = objects[k].get();
tnear = t;
vec3 shadowRayDirection = normalize(light1.getLightOrigin()-hitPoint);
Ray shadowRay(hitPoint+vec3(0.03, 0.03,0.03), shadowRayDirection);
float shadowT;
vec3 shadowHitPoint;
vec3 shadowN;
for (int m = 0; m < objects.size(); ++m) {
if (objects[m]->intersect(shadowRay, shadowT, shadowHitPoint, shadowN)) {
imageBuffer.SetPixel(i, j, ambientColour*ambientIntensity);
break;
} else {
imageBuffer.SetPixel(i, j, calculateOutputColour(normalAtHit, currentRay, light1, objects[k]->getMaterial(), hitPoint));
}
}
}
}
}
}
ich bin ehrlich mit Verlust hier, und ich habe keine Ahnung, warum dies geschieht. Ich habe versucht, mit dem Algorithmus beschrieben here, aber es erzeugt das gleiche Ergebnis im Bild gezeigt. Als Referenz, wenn ich die Schleife nehmen und prüfen, ob Schatten, sieht meine Szene wie folgt aus:
schätzen ich Hilfe bei dem Versuch, diese Sache zu debuggen. Vielen Dank.
Für Ihren Schattenstrahl sollten Sie 'hitPoint + 0.03 * shadowRayDirection' oder' hitPoint + 0.03 * normalAtHit' für den Ursprung des Strahls verwenden (jeder kann arbeiten; Argumente können in beide Richtungen erstellt werden). – Cornstalks
korrigiert zu float shadowOffset = 0.05; Ray shadowRay (hitPoint + shadowOffset * shadowRayDirection, shadowRayDirection); aber es erzeugt das gleiche Ergebnis :-( – jjcastil
Die Art, wie Sie 't' berechnen, könnte falsch sein (aber es könnte richtig sein; ich bin mir nicht sicher.) Ich mache es anders in meinem Raytracer:' vec3 n = cross (v0v1, v0v2); float num = Punkt (n, p0 - aRay.getOrigin()); float den = Punkt (n, aRay.getDirection()); t = num/den; '(aber überprüfe, dass' den! = 0 "vor dem Dividieren. Vielleicht möchten Sie das. Eine Sache, die Sie tun können, um zu testen, ob Ihr t-Wert stimmt, ist ein Tiefenbild, damit Sie sehen können, ob Ihre berechneten Schnittpunkte mit dem übereinstimmen, was Sie sind erwartet. – Cornstalks