2013-03-25 6 views
9

Czytałem wiele artykułów na temat śledzenia promieni i cieniowania, ale mój prześwietlany obraz nie wygląda zbyt dobrze. Mówię o bardzo jasnym zielonym obszarze w pobliżu najciekawszych punktów. Tutaj wygląda na to, że zielony kolor jest tu maksymalny. Jak dostosować kolory i/lub obliczenia cieniowania, aby wyglądał prawidłowo?Raytracing - jak połączyć barwę dyfuzyjną i lustrzaną?

(Nieważne, głupi kod, po prostu staram się najpierw poprawić zasady).

Oto jak to wygląda:

enter image description here

Oto tylko rozproszony komponent:

enter image description here

Oto komponent lustrzane tylko:

enter image description here

EDYCJA: Zmiana dyfuzji na Kolor rozproszony Kolor = Kolor (0,0f, 0,6f, 0,0f); Wtedy obraz wygląda tak:

enter image description here

Point lightPosition = PointMake(-100.0f, 100.0f, -100.0f); 
Color diffuseColor = ColorMake(0.0f, 1.0f, 0.0f); 
Color specularColor = ColorMake(1.0f, 1.0f, 1.0f); 
Color pixelColor = ColorMake(0.0f, 0.0f, 0.0f); 

// Trace... 

      // Diffuse 
      Point intersectionPosition = PointMake(x, y, z); 
      Vector intersectionNormal = VectorMake((x - xs)/rs, (y - ys)/rs, (z - zs)/rs); 
      Vector intersectionNormalN = VectorNormalize(intersectionNormal); 
      Vector lightVector   = VectorSubtract(lightPosition, intersectionPosition); 
      VectorlightVectorN   = VectorNormalize(lightVector); 
      float  cosTheta  = VectorDotProduct(intersectionNormalN, lightVectorN); 
      if (cosTheta < 0.0f) 
      { 
       cosTheta = 0.0f; 
      } 

      pixelColor = ColorMultScalar(diffuseColor, cosTheta); 

      // Specular 
      Vector incomVector = VectorSubtract(intersectionPosition, lightPosition); 
      Vector incomVectorN = VectorNormalize(incomVector); 

      float myDot = - VectorDotProduct(incomVectorN, intersectionNormalN); 
      float myLen = 2.0f * myDot; 

      Vector tempNormal  = VectorMultScalar(intersectionNormalN, myLen); 
      Vector reflectVector = VectorAdd(tempNormal, incomVectorN); 
      Vector reflectVectorN = VectorNormalize(reflectVector); 

      float mySpec = MAX(-VectorDotProduct(reflectVectorN, incomVectorN), 0); 
      mySpec  = powf(mySpec, 5); 

      specularColor = ColorMultScalar(specularColor, mySpec); 
      pixelColor = ColorAdd(pixelColor, specularColor); 
      pixelColor = ColorClamp(pixelColor); 

      [self putPixelatX:i andY:j andR:pixelColor.r andG:pixelColor.g andB:pixelColor.b]; 

Odpowiedz

6

Problem jest, gdy obliczenia rozproszone kolor kuli masz już niewielki obszar pikseli, które są 1 lub bardzo bliski 1 (w zielony kanał). Dodanie do tego składnika "phong" (który ma wartość zbliżoną do jednego we wszystkich kanałach), daje obszar pikseli, które są> = 1. Gdy następnie zacieśnisz wartość koloru na 1, ten obszar> = 1 stoi na zewnątrz.

Można to przetestować za pomocą programu do edycji obrazu i wykonać nakładkę "dodawania" dwóch warstw (warstwa phong nad rozproszoną). Daje to rezultat, który widzisz - i czego można się spodziewać.

Można uniknąć tego problemu przez kilka sposobów:

  1. Można Dim źródło światła trochę, to pomnożyć rozproszone wytrzymałości ty obliczona forma cosinus jasnością - powiedzmy 0.8 lub 0.7 .
  2. Można ograniczyć nasycenie kolorów (kolor zielony) kuli i sprawić, że będzie mniej greeen;)
  3. Użyj operatora mapowania tonów, aby znormalizować wartości kolorów pikseli w zakresie [0..1] - ten temat jest jednak ogromny - wikipedia może dać dobre wprowadzenie. Nie musisz nawet z nimi pracować, ponieważ dla renderowania nie opartego na fizyce prostsze operatory odwzorowania tonów mogą wystarczyć i przynieść rezultaty przyjemne dla oka.

Moje eksperymenty z raytracing datują się na kilka lat, ale możesz wypróbować te rzeczy.


Aktualizacja 1:

Jedną rzeczą, jaką zauważyłem, kiedy gamma poprawić swój obraz wyjściowy - efekt jest mniej widoczny;) - OK, to jest trochę nierówne.

Ostatecznym rozwiązaniem jest wykonanie poprawnej phsically lub użycie innego modelu cieniowania: Wikipedia on Specular highlight.


Aktualizacja 2:

jeden rzeczywisty rozwiązaniem byłoby obliczyć wkład Phong do ostatecznego koloru piksela (czyli zmienna mySpec). Chodzi o to, aby użyć tylko części komponentu rozproszonego, w którym lustro nie jest w rzeczywistości 0, to znaczy, jeśli masz jakiś komponent lustrzany, tak naprawdę nie widzisz komponentu rozproszonego tak bardzo (lub w ogóle), aby mógł być skorygowany o:

float diffuseContrib = 1.f - mySpec; 

to powinno wyglądać dobrze, ale nie jestem pewien, jak poprawne faktycznie jest :).

Uwaga jednak; zakłada to, że twoje komponenty lustrzane i rozproszone są w zakresie [0..1].

Mój wynik wygląda w ten sposób:

diffuse contribution calculated using the specular contribution

4

to od dawna problem z "specular + + otoczenia" rozproszonego modelu oświetlenia. Mianowicie jest to hak i dlatego nie ma gwarancji poprawności.

Jeśli tak bardzo chcesz najpierw scementować swoje podstawy, spójrz na wspaniałą książkę "Physically Based Ray Tracing" autorstwa Matta Pharra i Grega Humphreysa.

+0

To nieprawda, o to chodzi. Nie może istnieć "gwarancja poprawności";) - tak naprawdę jest to tylko sposób na kolorowanie pikseli za pomocą przydatnych funkcji matematycznych (np. Pow phong i pewna arbitralna wartość dla ambientu). Przynajmniej tak to widzę. Najważniejsze; PBRT FTW !! 1 –

+0

Podczas gdy twój punkt jest w 100% ważny, wielu ludzi, którzy wskakują do raytracingu, nie zdaje sobie sprawy z tego faktu - są oni zwykle zachwyceni ładnymi obrazami, nie wiedząc, że istnieje cała garść potrzebnych ulepszeń :) –

0

Powinieneś przeczytać na stronie Blinn/Phong model. Oto przykładowy kod fragmentu shadera. Zasadniczo przeskalujesz pojedyncze komponenty (ambient, diffuse, specular) za pomocą odpowiednich kątów i dodasz je.

varying vec3 N; 
varying vec3 v;  
void main (void) 
{ 
    vec3 L = normalize(gl_LightSource[0].position.xyz - v); 
    vec3 E = normalize(-v); // we are in Eye Coordinates, so EyePos is (0,0,0) 
    vec3 R = normalize(-reflect(L,N)); 

    //calculate Ambient Term: 
    vec4 Iamb = gl_FrontLightProduct[0].ambient;  

    //calculate Diffuse Term: 
    vec4 Idiff = gl_FrontLightProduct[0].diffuse * max(dot(N,L), 0.0); 
    Idiff = clamp(Idiff, 0.0, 1.0);  

    // calculate Specular Term: 
    vec4 Ispec = gl_FrontLightProduct[0].specular 
       * pow(max(dot(R,E),0.0),0.3*gl_FrontMaterial.shininess); 
    Ispec = clamp(Ispec, 0.0, 1.0); 
    // write Total Color: 
    gl_FragColor = gl_FrontLightModelProduct.sceneColor + Iamb + Idiff + Ispec;  
} 

zaczerpnięte z: http://www.opengl.org/sdk/docs/tutorials/ClockworkCoders/lighting.php

0

Dlaczego nie zrobić (światło + otoczenia) * rozproszone + zwierciadlanego? tj. dodanie składnika lustrzanego po pomnożeniu oświetlenia i cieni za pomocą rozproszonego? To da wyraźną uwagę.