[C#] Oświetlenie 2D 26114 74

O temacie

Autor Sauron

Zaczęty 27.01.2015 roku

Wyświetleń 26114

Odpowiedzi 74

Sauron

Sauron

Użytkownicy
posty267
Propsy5
Profesjabrak
  • Użytkownicy
Witam. Problem dotyczy oświetlenia płaskiej powierzchni. Udało mi się uwzględnić światło rozproszone, niestety mam problem z odbitym. Próbowałem robić coś takiego:

Vector3 light_direction = new Vector3(500, 500, 500);
Vector3 normal = new Vector3(0, 0, 1);
Vector3 eye = new Vector3(500, 500, 1);
for(int i =0;i<=b.Width - 1;i++)
{
    for(int i2 = 0;i2<=b.Height - 1;i2++)
    {
        Vector3 pos = (i, i2, 0);
        Vector3 lightToSurface = pos - light_direction;
        Vector3 reflection = lightToSurface - 2 * Dot(lightToSurface, normal) * normal;
        float specularAngle = Dot(reflection.Normalize(), eye.Normalize());
        float specular = (float)Math.Pow(specularAngle, 5);
    }
}

Potem do specular dodaję diffuse i mnożę razy kolor. Efekt nie wygląda zbyt dobrze. Światło odbite to tylko 1 oświetlony piksel w centrum obrazu. Jak "powiększyć" ten obszar?

Dodam, że obraz ma rozmiary 1000x1000 i leży na płaszczyźnie X (tzn. Z jest zawsze równe 0).

A i jeszcze jedno: jaki związek ma intensywność światła rozproszonego od odległości jego źródła?
 
Ash nazg durbatulûk, ash nazg gimbatul,
ash nazg thrakatulûk agh burzum-ishi krimpatul.

mgr Fartuess

mgr Fartuess

Użytkownicy
Kiedyś to były czasy!
posty1485
Propsy890
ProfesjaProgramista
  • Użytkownicy
  • Kiedyś to były czasy!
 Intensywność światła rozproszonego od odległości jest zależna przy świetle punktowym, która jak widzę tutaj wyliczasz. Co do błędów to nawet mi trudno wychwycić... rozumiem, że testowałeś różne wartości potęgi pod specularAngle.
 
Popisuje się ciągle menda jedna...

Sauron

Sauron

Użytkownicy
posty267
Propsy5
Profesjabrak
  • Użytkownicy

Sauron

[C#] Oświetlenie 2D
#2 2015-01-28, 17:15(Ostatnia zmiana: 2015-01-28, 18:58)
Wiem, że jest zależna, ale jak? Ja uwzględniam tylko kąt, ale gdyby postawić dwie płaszczyzny obok siebie, jedna dalej światła, inna bliżej i każda z nich byłaby oświetlana osobnym źródłem, to więcej światła dotrze do punktu bliższego. Chyba nikt nie zaprzeczy?

EDIT:
Nie odjąłem punktu zaczepu wektora, powinno być tak:
Dot(reflection.Normalize(), (eye - pos).Normalize());
Niby teraz powinno być dobrze, ale chyba jednak nie  :hmmm: Jeżeli wykładnik potęgi ustawie na 2, to specular (sam, bez diffuse) wygląda tak (przypomnę, że "kamera" jest na środku, tak jak źródło światła):

http://ifotos.pl/z/wxhqpss

EDIT2: Udało się. Zmieniłem odległość kamery od powierzchni (wcześniej było 1, teraz 500). Zapomniałem, że nie mogę wpisać sobie byle czego, tak jak w normalnej  :lol: Jak powinienem liczyć kolor końcowy?
 
Ash nazg durbatulûk, ash nazg gimbatul,
ash nazg thrakatulûk agh burzum-ishi krimpatul.

mgr Fartuess

mgr Fartuess

Użytkownicy
Kiedyś to były czasy!
posty1485
Propsy890
ProfesjaProgramista
  • Użytkownicy
  • Kiedyś to były czasy!
Podejścia do koloru końcowego są różne. Ogólnie sumuje się wynik z diffuse'a z wynikiem ze speculara. Diffuse przemnaża się przez teksturę koloru diffuse a specular przez kolor tekstury speculara lub pozostawia się nieprzemnożony dla dielektryków lub przemnożony mniej więcej przez diffuse dla metali.

Co do wygaszania:

albo jeśli chcesz customowy factor wygaszania:
 
Popisuje się ciągle menda jedna...

Sauron

Sauron

Użytkownicy
posty267
Propsy5
Profesjabrak
  • Użytkownicy
Cytuj
Podejścia do koloru końcowego są różne. Ogólnie sumuje się wynik z diffuse'a z wynikiem ze speculara. Diffuse przemnaża się przez teksturę koloru diffuse a specular przez kolor tekstury speculara lub pozostawia się nieprzemnożony dla dielektryków lub przemnożony mniej więcej przez diffuse dla metali.
A ambient? Słyszałem też o emit, ale nie mam pojęcia co to jest. A jak to jest z innymi typami światła, np. "spot light"?
 
Ash nazg durbatulûk, ash nazg gimbatul,
ash nazg thrakatulûk agh burzum-ishi krimpatul.

mgr Fartuess

mgr Fartuess

Użytkownicy
Kiedyś to były czasy!
posty1485
Propsy890
ProfesjaProgramista
  • Użytkownicy
  • Kiedyś to były czasy!
Ambient po prostu dodajesz do każdego piksela ambient * textureColor. Chodzi o to, żeby tam gdzie nie dociera bezpośrednio światło nie było totalnie czarno. Emit idzie z nowej tekstury i dodajesz go bez przemnażania przez wartości oświetlenia.

Co do innych typów świateł. Directional light jest dość prosty - od razu podajesz wektor kierunkowy i oświetlasz bez wygaszania z odległością. Spot Light z kolei jest podobny do światła punktowego tylko dodatkowym elementem wygaszającym jest odległość kątowa od kierunku spota.

 
Popisuje się ciągle menda jedna...

Sauron

Sauron

Użytkownicy
posty267
Propsy5
Profesjabrak
  • Użytkownicy
Cytuj
Diffuse przemnaża się przez teksturę koloru diffuse a specular przez kolor tekstury speculara lub pozostawia się nieprzemnożony dla dielektryków lub przemnożony mniej więcej przez diffuse dla metali.

Wydaję mi się, że nadużywasz słowa "tekstura"... Kolor tekstury to jak rozumiem kolor światła? Ale chyba nie w obu przypadkach (diffuse i specular)? Inaczej. Ma to wyglądać tak: (ambient + diffuse) * texture + specular * lightColor, czy tak: ambient * texture + diffuse * lightColor + specular * specularLightColor?

Chyba powinienem powiedzieć, że nie piszę tego w OpenGL, tylko korzystam ze struktur, które sam napisałem. Kolor traktuje tutaj jako 3 składowe typu byte, czyli klasycznie (może i błędnie - wektor byłby chyba lepszy), a teksturą ('texture', 2 zdania wcześniej) jest bitmapa, więc no... A składowe liczę osobno tj. wyżej.

Ponadto: dla dielektryków nieprzemnożony... czyli tak jakby diffuse * (coś tam) + specular, ale to mi się wydaję być bez sensu... Może głupi jestem. Metale jeszcze lepiej: diffuse * (coś tam) + specular * diffuse. Takie coś  wnioskuje z twojej wypowiedzi.

Jeszcze to:
Cytuj
Emit idzie z nowej tekstury i dodajesz go bez przemnażania przez wartości oświetlenia.

Nowej tekstury?? Sprecyzuj, jeśli możesz.
 
Ash nazg durbatulûk, ash nazg gimbatul,
ash nazg thrakatulûk agh burzum-ishi krimpatul.

mgr Fartuess

mgr Fartuess

Użytkownicy
Kiedyś to były czasy!
posty1485
Propsy890
ProfesjaProgramista
  • Użytkownicy
  • Kiedyś to były czasy!
Wydaję mi się, że nadużywasz słowa "tekstura"... Kolor tekstury to jak rozumiem kolor światła? Ale chyba nie w obu przypadkach (diffuse i specular)? Inaczej. Ma to wyglądać tak: (ambient + diffuse) * texture + specular * lightColor, czy tak: ambient * texture + diffuse * lightColor + specular * specularLightColor?
Nie. Tekstura to jest to co nakładasz na płaszczyznę. A wzorek będzie wyglądał mniej więcej tak:

color = ((ambient + diffuse) * diffuseTexture) + specular * specularTexture) * lightColor;
Często w materiałach dotyczących oświetlenia phonga wzór jest uproszczony i pomija się przemnożenie przez specularTexture.

Chyba powinienem powiedzieć, że nie piszę tego w OpenGL, tylko korzystam ze struktur, które sam napisałem. Kolor traktuje tutaj jako 3 składowe typu byte, czyli klasycznie (może i błędnie - wektor byłby chyba lepszy), a teksturą ('texture', 2 zdania wcześniej) jest bitmapa, więc no... A składowe liczę osobno tj. wyżej.
W OpenGLu (współczesnym) i tak piszesz struktury samemu po stronie C++ a typy dobierasz jak ci pasują po stronie shadera. Kolor możesz zrobić jako złożenie 3 byte. W grafice używa się do tego floatów, bo operacje na GPU są znacznie szybsze na floatach. Tu możesz zostawić jak masz, tylko wtedy we wzorze gdzie mnożysz coś przez kolory to musisz to znormalizować do przedziału [0;1] w wygodny dla ciebie sposób (np ostatecznie podzielić to co otrzymałeś przez 256)

Ponadto: dla dielektryków nieprzemnożony... czyli tak jakby diffuse * (coś tam) + specular, ale to mi się wydaję być bez sensu... Może głupi jestem. Metale jeszcze lepiej: diffuse * (coś tam) + specular * diffuse. Takie coś  wnioskuje z twojej wypowiedzi.
Chodzi o to, że dielektryki (plastik, drewno, farba...) mają biały połysk podczas gdy metale mają połysk kolorowy.
Różnie się to załatwia w różnych modelach oświetlenia, ale w phongu robi się to tak, że przygotowuje się dodatkową teksturę mówiącą jaki kolor i intensywność będzie miał rozbłysk w danym pikselu. W przypadku metali na teksturze speculara będziemy mieli tą samą (może nieco rozjaśnioną) barwę co na diffuse, podczas gdy dla dielektryków będziemy mieli barwę przeciwną (w photoshopie przekształcasz barwę/hue o 180 stopni) i nieco rozjaśnioną często. W przypadku dielektryka chodzi o to, że jak zsumujemy barwę przeciwną z wstępną po kanałach to w sumie wyjdzie nam biały rozbłysk.

Jeszcze to:
Cytuj
Emit idzie z nowej tekstury i dodajesz go bez przemnażania przez wartości oświetlenia.

Nowej tekstury?? Sprecyzuj, jeśli możesz.

Emit to jest światło emitowane przez powierzchnię. Nie oświetla ono obiektów naokoło ale dzięki niemu można zrobić np świecące na czerwono oczy robota, które widać w ciemności. W tym celu należy sobie przygotować teksturkę na której namalujesz które piksele mają jak mocno świecić i z jakim kolorem.

Wzór po dodaniu emita będzie wyglądał tak:
color = ((ambient + diffuse) * diffuseTexture) + specular * specularTexture) * lightColor + emitTexture;
 
Popisuje się ciągle menda jedna...

Sauron

Sauron

Użytkownicy
posty267
Propsy5
Profesjabrak
  • Użytkownicy
Ok, wszystko elegancko, ale teraz jest problem z wygaszaniem (wynikającym z odległości). U mnie odległość światła (500px od płaszczyzny) od skrajnego punktu (ok. 707px od środka obrazu) to liczba rzędu 800, więc ten współczynnik to dopiero jest cudo... (odwrotność kwadratu). jak mniemam problemem są piksele. O ile dobrze się orientuję to OpenGL'u używa się float'ów, tj. 1.0, czy 0.5. Wtedy wychodzą ogarnięte liczby. Tak więc, jak przeliczyć piksele na float'a?
 
Ash nazg durbatulûk, ash nazg gimbatul,
ash nazg thrakatulûk agh burzum-ishi krimpatul.

Adanos

Adanos

Administrator
Szara eminencja
posty5204
Propsy3870
ProfesjaProgramista
  • Administrator
  • Szara eminencja
Po prostu przeskaluj z przedziału [0, 800] (czy jaki tam masz) na [0, 1]. Chociaż nie wiem, czy to ci jest naprawdę potrzebne...

Sauron

Sauron

Użytkownicy
posty267
Propsy5
Profesjabrak
  • Użytkownicy

Sauron

[C#] Oświetlenie 2D
#10 2015-02-16, 19:13(Ostatnia zmiana: 2015-02-16, 19:34)
Jeżeli nie jest to potrzebne, to jak zrobić inaczej?

Przedział jest (tak jakby) nieskończony. To znaczy, mam bitmapę o rozmiarze 1000x1000, ale światło może być gdziekolwiek. Nie wiem, czy skalować względem powierzchni, czy świtała (jeśli te pierwsze to światło będzie miało współrzędne większe niż 1 - może się tak zdarzyć) i czy to coś znacznie zmieni. Poza tym, chyba powinno (nie wiem, czy nie musi) być tak, że punkt (0, 0, 0) to środek płaszczyzny.

EDIT: A jak jest z wygaszaniem przy specular? Bierze się tą samą wartość, czy np. o połowę mniejszą (światło pokonuje 2x dłuższą drogę)?
 
Ash nazg durbatulûk, ash nazg gimbatul,
ash nazg thrakatulûk agh burzum-ishi krimpatul.

mgr Fartuess

mgr Fartuess

Użytkownicy
Kiedyś to były czasy!
posty1485
Propsy890
ProfesjaProgramista
  • Użytkownicy
  • Kiedyś to były czasy!
Ja u siebie skaluje sobie zakres wygaszania do promienia światła jaki sobie ustawiłem.
 
Popisuje się ciągle menda jedna...

Sauron

Sauron

Użytkownicy
posty267
Propsy5
Profesjabrak
  • Użytkownicy
Małe odświeżenie.
Cytuj
Ja u siebie skaluje sobie zakres wygaszania do promienia światła jaki sobie ustawiłem.
 Wyjaśnij jeśli możesz :D

Jeszcze co do spotlight. Gdzieś znalazłem coś dot. tego rodzaju światła i tam jest to podzielone na 'inner cone' i 'outer cone'. Jak ma się to do tego co pisałeś wcześniej? BTW: Z tego opisu mało zrozumiałem, np. co to jest X1 :P 

Kolejna sprawa (wiem że dużo wymagam) - 'area light'. Jak to się robi?
 
Ash nazg durbatulûk, ash nazg gimbatul,
ash nazg thrakatulûk agh burzum-ishi krimpatul.

mgr Fartuess

mgr Fartuess

Użytkownicy
Kiedyś to były czasy!
posty1485
Propsy890
ProfesjaProgramista
  • Użytkownicy
  • Kiedyś to były czasy!
Chodzi o to, że normalnie ustawiasz sobie jak światło ma się wyagszać i jaką ma mieć siłę. Nie panujesz nad tym gdzie się ono skończy a wraz ze zmianą wartości attenuation to miejsce bardzo drastycznie się zmienia. Ja po prostu jakimiś wzorami które sobie sam wyprowadziłem zrobiłem tak, że w odległości 0 światło jest w pełni jasne a w odległości >= radius jest jasość zerowa. Pomiędzy są wartości pośrednie. Dzięki temu attenuation nie wpływa na promień światła, tylko na "ostrość krawędzi". Tak to jest zrobione na Unreal Engine na przykład.


Co do spot lighta. To co znajduje się poza outer cone nie jest oświetlane wcale. To co znajduje się w inner cone nie jest wygaszane ze względu na kąt względem kąta spot lighta (tj wygaszane jest tylko przez attenuation jak z point lighta). To co znajduje się w outer cone, ale nie w inner cone ma wartości pośrednie zależne od kąta (przypomnienie; dla wektorów długości 1 dot product, czyli iloczyn skalarny daje nam wartości kąta między tymi dwoma wektorami)

Co to X1 nie powiem ci teraz, bo piszę to o 3ciej w nocy, a czuję, że musiałbym to przysiedzieć, żeby zrozumieć. Ja w swoim silniku nie skończyłem implementacji spota, bo mi się już nie chciało :P

Area light tylko nieco kojarzę co to jest. Nie znam implementacji. Duże silniki do gier 3D zazwyczaj tego nie implementują. Area light zazwyczaj nie liczy się w realtimie, a jeśli się liczy to pewnie skomplikowanymi trikami. W 2D te triki mogą być łatwiejsze.
 
Popisuje się ciągle menda jedna...

Sauron

Sauron

Użytkownicy
posty267
Propsy5
Profesjabrak
  • Użytkownicy
Wstępnie pozwoliłem sobie pominąć radius i beamWidthAngle. Liczę kąt między normalną, a światłem, czyli wszystko jak w diffuse. Tyle że sprawdzam jeszcze warunek, czy dot product jest mniejszy niż cosinus kąta spotAngle (spreadAngle w modelu wyżej), jeżeli nie jest tak to punkt jest czarny. Potem jeszcze to potęguje i... i właśnie. Krawędź nie jest zbyt "gładka" mimo że wykładnik potęgi to 8. Dołączam zdjęcie (ambient: 0, specular: 0, diffuse(jako spot): 0.9, wygaszanie proporcjonalne do kwadratu odległości)
 
Ash nazg durbatulûk, ash nazg gimbatul,
ash nazg thrakatulûk agh burzum-ishi krimpatul.

mgr Fartuess

mgr Fartuess

Użytkownicy
Kiedyś to były czasy!
posty1485
Propsy890
ProfesjaProgramista
  • Użytkownicy
  • Kiedyś to były czasy!
Możesz wkleić kod który to liczy? Będzie mi łatwiej. Nie skodziłem spota do końca, więc nie wszystko Ci mogę powiedzieć z marszu.
 
Popisuje się ciągle menda jedna...

Sauron

Sauron

Użytkownicy
posty267
Propsy5
Profesjabrak
  • Użytkownicy
light_position = new Vector3(0, 0, 1);
normal = new Vector3(0, 0, 1);
Vector3 eye = new Vector3(0, 0, 1);

int specularExponent = 3;

float ambient = 0f;
float kSpecular = 0f;
float kDiffuse = 0.90f;

Vector3 lightColor = ColorToVec3(Color.White); //funkcja pomocnicza

float halfX = b.Width / 2f; //b to bitmapa
float halfY = b.Height / 2f;

float spotAngle = 1f; // jakiś tam kąt w radianach

for (int i = 0; i <= b.Width - 1; i++)
{
      for (int i2 = 0; i2 <= b.Height - 1; i2++)
      {
            Vector3 pos = new Vector3((i - halfX) / halfX, (i2 - halfY) / halfY, 0);// skalowanie od -1 do 1
            Vector3 temp = pos - light_position;

            float distance = temp.Lenght();
            float specularDist = distance + eye.Lenght();
            distance = distance * distance; //można zoptymalizować - wiem
            specularDist = specularDist * specularDist;// j.w

            Vector3 lightToSurface = temp / distance;

            Vector3 reflection = lightToSurface - ((2 * Dot(lightToSurface, normal)) * normal);
            float specularAngle = Dot(reflection, (eye - pos).Normalize());
            float specular = Math.Max((float)(Math.Pow(specularAngle, specularExponent) * kSpecular / specularDist), 0);
            float angle = Dot(normal, -lightToSurface);
            float spotLight = 0;
            if (Math.Cos(spotAngle) < angle)
                  spotLight = (float)Math.Pow(angle, 2) * kDiffuse / distance;

            Vector4 texture = ColorToVec4(b.GetPixel(i, i2));
            Color final = Vec4ToColor(new Vector4(((ambient + spotLight) * texture.XYZ() + specular * new Vector3(1f, 1f, 1f)) * lightColor, texture.I));// ten Vector3(1, 1 ,1) to specularMapa

            b.SetPixel(i, i2, final);
      }
}
 
Ash nazg durbatulûk, ash nazg gimbatul,
ash nazg thrakatulûk agh burzum-ishi krimpatul.

mgr Fartuess

mgr Fartuess

Użytkownicy
Kiedyś to były czasy!
posty1485
Propsy890
ProfesjaProgramista
  • Użytkownicy
  • Kiedyś to były czasy!
wykomentuj ifa i speculara i zobacz co ci się będzie działo.

Ogólnie wydaje mi się możliwe, że problem jest tutaj:
spotLight = (float)Math.Pow(angle, 2) * kDiffuse / distance;
może nie powinno być potęgi? I dlaczego jest tutaj liniowe wygaszaie w zależności od odległości? Dunno sprawdź jeszcze co się stanie jak tak zrobisz.
spotLight = angle * kDiffuse;
 
Popisuje się ciągle menda jedna...

Sauron

Sauron

Użytkownicy
posty267
Propsy5
Profesjabrak
  • Użytkownicy
Jak usunę if'a to efekt jest taki jak przy zwykłym diffuse, tyle że "obszar" światła jest mniejszy:


Usunięcie speculara nic nie daje, bo już wcześniej ustawiłem go na 0. Wygaszenie wcale nie jest liniowe. Gdzieś jest tam linijka:
distance = distance * distance
Wydaję mi się, że potęga jest potrzebna. Kilka postów temu, wysłałeś obrazki z Unreal'a i tam jest "FalloffExponent". Trochę mi się skojarzyło i zrobiłem potęgę. Jak jej nie ma to efekt jest taki jak na zdj. wyżej, tyle że jeszcze bardziej przypomina diffuse (wolniejsze zaciemnienie).

Efekt jest ciekawszy, gdy usunę wygaszanie:
spotLight = angle * kDiffuse;


Kąt spota to w dalszym ciągu 30 st. (wiem że w kodzie było inaczej, ale screen był z właśnie tej wartości)
 
Ash nazg durbatulûk, ash nazg gimbatul,
ash nazg thrakatulûk agh burzum-ishi krimpatul.

mgr Fartuess

mgr Fartuess

Użytkownicy
Kiedyś to były czasy!
posty1485
Propsy890
ProfesjaProgramista
  • Użytkownicy
  • Kiedyś to były czasy!

mgr Fartuess

[C#] Oświetlenie 2D
#19 2015-03-22, 15:31(Ostatnia zmiana: 2015-03-22, 15:43)
Fallof exponent jest od attenuation. Nie jestem pewien czy ma wpływ na rzeczy związane z inner/outer angle.

po usunięciu wygaszania masz pokazane jaki wpływ ma outer angle ze spota - nie za duży :P.

Jesteś pewien że wygaszanie zależne od kąta padania normalizujesz do outer angle (tak żeby przy outer angle było wygaszone do 0)
 
Popisuje się ciągle menda jedna...


0 użytkowników i 1 Gość przegląda ten wątek.
0 użytkowników
Do góry