Rendering czasu rzeczywistego (PDF)

Post on 11-Jan-2017

253 views 3 download

Transcript of Rendering czasu rzeczywistego (PDF)

Rendering w czasie rzeczywistym

dr inż. Rafał Wcisło

wcislo@agh.edu.pl

Wstęp

2

Rendering w czasie rzeczywistym

Polega na generowaniu obrazów na tyle szybko, aby stworzyć wrażenie płynnej animacji i zagwarantować możliwość interaktywnej współpracy aplikacji z użytkownikiem 24 fps – 60 fps (120 fps dla stereo)

Ważne aspekty: Virtual reality (rzeczywistość wirtualna)

Augmented reality (rzeczywistość rozszerzona)

3

Zastosowania

Gry rozrywka

„Serious games” symulacje

edukacja

terapia

4

Co się zmienia?

Oczekiwania użytkowników

5

Pong

1972

6 "TeleGames-Atari-Pong" by Evan-Amos - Own work. Licensed under CC BY-SA 3.0 via Commons - https://commons.wikimedia.org/wiki/File:TeleGames-Atari-Pong.png#/media/File:TeleGames-Atari-Pong.png

Donkey Kong

1981

7

"Donkey Kong Gameplay" by Source (WP:NFCC#4). Licensed under Fair use via Wikipedia - https://en.wikipedia.org/wiki/File:Donkey_Kong_Gameplay.png#/media/File:Donkey_Kong_Gameplay.png

Combat Zone

1983 https://www.youtube.com/watch?v=SGDvi6ydFHE

8

Doom

1993

9

Unreal

1998

10

Grand Theft Auto V

2013

11

"Grand Theft Auto V combat" by Source. Licensed under Fair use via Wikipedia - https://en.wikipedia.org/wiki/File:Grand_Theft_Auto_V_combat.jpg#/media/File:Grand_Theft_Auto_V_combat.jpg

Wiedźmin III

2015

12

Co się zmienia?

Rozdzielczość CGA (320x200),…,HD 1080 (1920x1080),…

Kolory 8, 16, 24, 32 bit/pixel, HDR (High Dynamic Range)

2D 3D

13

14 "Vector Video Standards2" by Original uploader was XXV at en.wikipedia Later version(s) were uploaded by Jjalocha, Aihtdikh at en.wikipedia. - Transferred from en.wikipedia. Licensed under CC BY-SA 3.0 via Commons - https://commons.wikimedia.org/wiki/File:Vector_Video_Standards2.svg#/media/File:Vector_Video_Standards2.svg

Co się zmienia?

Moc obliczeniowa CPU

GPU

Pamięci (RAM, cache, SSD, itp.)

Przepustowość

15

Biblioteki graficzne

Kilkanaście lat temu grafika czasu rzeczywistego była generowana na CPU, przy pomocy renderera napisanego „od zera” (Wolfenstein, Doom, Quake,…)

Wszystkie współczesne aplikacje tego typu wymagają kart graficznych

Biblioteki graficzne zapewniają dostęp do funkcjonalności kart graficznych różnych producentów, oferując podstawowe procedury renderingu

16

Biblioteki graficzne, c.d.

Biblioteki te skupiają się tylko na jednym algorytmie renderingu – rasteryzacji

Obecnie żaden inny algorytm (np. śledzenie promieni) w czasie rzeczywistym nie jest w stanie stworzyć obrazu o lepszej jakości

17

Biblioteki graficzne, c.d.

Najczęściej stosowane biblioteki to OpenGL i DirectX

Mają one bardzo podobne możliwości i wydajność

18

OpenGL

Biblioteka niezależna od platformy (Windows, Unix, iOS, PS)

Opracowana przez SGI (Mark Segal i Kurt Akeley) w 1991/92

Powszechne stosowanie rozszerzeń przez producentów kart graficznych

Model programowania proceduralny

19

DirectX

Biblioteka Microsoftu

Z OpenGL’em konkuruje jedynie Direct3D (część DirectX)

Opracowana początkowo w 1992 przez Servana Keondjiana (założył firmę RenderMorphics), następnie w 1995 wcielona do DirectX 2.0

Niedostępna na systemach Unix, iOS, PS

Brak mechanizmu rozszerzeń (teoretycznie)

Obiektowy model programowania 20

Próba integracji

W 1997 SGI, Microsoft (i później HP) uruchomiły projekt mający na celu zintegrowanie OpenGL i Direct3D

Projekt został porzucony w 1999 Microsoft – zmiana strategii

SGI – kłopoty finansowe

21

Historia renderingu na kartach graficznych

Karty graficzne nieprogramowalne

OpenGL 1.x, DirectX do wersji 7

Tylko rendering trójkątów z pojedynczą teksturą

Sprzętowa transformacja i oświetlenie wierzchołków

Programowalne przetwarzanie wierzchołków

Rozszerzenia OpenGL 1.x, DirectX 8.x

22

Programowalne przetwarzanie fragmentów OpenGL 2.x, DirectX 9.x

Możliwość pisania coraz bardziej zaawansowanych programów

Nowe formaty tekstur, HDR (High Dynamic Range), rendering do tekstury

23

Historia renderingu na kartach graficznych, c.d.

Programowalne przetwarzanie geometrii OpenGL 3.x, DirectX 10.x

Operacje na prymitywach

Obliczenia na GPU (ogólnego przeznaczenia)

24

Historia renderingu na kartach graficznych, c.d.

Programowalna tesselacja OpenGL 4.x, DirectX 11

Nowe możliwości programów GPU

Zapis i odczyt z tekstury, operacje atomowe

25

Historia renderingu na kartach graficznych, c.d.

Wersje OpenGL

https://www.opengl.org/wiki/History_of_OpenGL

26

Rozszerzenia

GL_ : wszystkie platformy

GLX_ : Linux & Mac

WGL_ : Windows

EXT_ : rozszerzenie ogólne

ARB_ : zaakceptowane przez wszystkich członków OpenGL Architecture Review Board (EXT_ często stają się ARB_ w kolejnych wydaniach)

NV/AMD/INTEL/APPLE 27

Vulkan

https://en.wikipedia.org/wiki/Vulkan_(API)

next generation OpenGL initiative

higher performance and lower CPU usage

prekompilowane shadery

28

Vulkan vs OpenGL

In OpenGL getting something on the screen is by far easier. Even without classic fixed function, just rendering full-screen effects or image-processing takes only few lines of code. Vulkan’s level of verbosity to get to the first pixel on the screen is far higher. As hinted in the previous blog posts on resource bindings or memory management, these additional complexities will require more code to be written. Especially for people new to graphics, it may be better to use OpenGL or rendering middleware that hides this complexity and focus on the actual task.

30

Grafika 3D - przypomnienie

Modele budowane z wierzchołków Pozycja

Normalna

Współrzędne tekstury

I wiele, wiele, wiele innych

Wybrane trójki wierzchołków tworzą trójkąty, stanowiące brzeg modelu

Najnowsze karty obsługują bardziej złożone powierzchnie (sprzętowa teselacja)

31

Wierzchołki są transformowane z przestrzeni obiektu, przez przestrzeń świata i widoku do przestrzeni ekranu przy pomocy macierzy

W przestrzeni ekranu wykonywana jest rasteryzacja trójkątów

Liczone jest oświetlenie i teksturowanie

32

Grafika 3D - przypomnienie, c.d.

Wykonywane jest zasłanianie (z-bufor), wtapianie (blending) itp.

Wymienione powyżej elementy są bardzo podstawowe, obecnie stosuje się o wiele więcej zaawansowanych technik

33

Grafika 3D - przypomnienie, c.d.

OpenGL 3.0 rendering pipeline

34

OpenGL 4.3 rendering pipeline

35

OpenGL 4.5 rendering pipeline

36

Skrócona wersja obrazkowa

37

Pojedyncze podawanie wierzchołków

glBegin(GL_TRIANGLES);

glVertexf(...); glVertexf(...); glVertexf(...); glVertexf(...); glVertexf(...); glVertexf(...); glEnd();

DEPRECATED 38

Stare style programowania OpenGL

Stare style programowania OpenGL, c.d.

Bufory z wierzchołkami

DEPRECATED

39

Stare style programowania OpenGL, c.d.

Display lists

glNewList(index, GL_COMPILE); glBegin(GL_TRIANGLES); glVertex3fv(v0); glVertex3fv(v1); glVertex3fv(v2); glEnd(); glEndList(); glCallList(index);

DEPRECATED

40

A zatem jak?

Shaders

Vertex shader

Tesselation shaders (2x)

Geometry shadrer

Fragment shader

Bufory: VBO, VAO, EBO, textures,...

41

Literatura

42

Online

http://www.learnopengl.com

https://www.opengl.org/sdk/docs/man/html

https://www.opengl.org/registry

https://www.opengl.org/wiki/History_of_OpenGL

http://www.lighthouse3d.com/tutorials/glsl-tutorial

43

44

Książki

45

Książki, c.d.

Zaczynamy

46

Wersje OpenGL i GLSL

https://en.wikipedia.org/wiki/OpenGL_Shading_Language

47

Sprawdzenie wersji

glGetString(...) GL_RENDERER

karta graficzna

GL_VERSION wersja OpenGL

GL_SHADING_LANGUAGE_VERSION wersja GLSL

GL_EXTENSIONS obsługiwane rozszerzenia

48

Przykład OpenGL01

49

NVIDIA was proud to introduce programmable shading with Cg, which supported dozens of different OpenGL and DirectX profile targets. It allowed developers to incorporate interactive effects within 3D applications and share them among other Cg applications, across graphics APIs, and most operating systems (Windows XP, Vista and Windows 7, Mac OS X for Leopard, Snow Leopard & Lion, Linux 32-bit & 64-bit) as well as balance effect complexities with client GPU capabilities.

Going forward, we recommend new development with GLSL, or HLSL for Windows applications, rather than Cg. (2012 Cg DEPRECATED)

„… via Cg compiler”

50

Nie ma lekko…

In Modern OpenGL we are required to define at least a vertex and fragment shader of our own (there are no default vertex/fragment shaders on the GPU). For this reason it is often quite difficult to start learning Modern OpenGL since a great deal of knowledge is required before being able to render your first triangle…

51

Przykład OpenGL02

52

Shaders #version 450

in vec3 position;

in vec3 color;

uniform float zoom;

out vec3 fragColor;

void main()

{

gl_Position = vec4(position, 1.0)*zoom;

fragColor = color;

} 53

Typy zmiennych

Skalary bool, int, float, double, uint

Wektory {b|i||d|u|}vec[2|3|4], np. vec3, uvec2

Macierze {d}mat[2|3|4|2x2|2x3|2x4|3x3|3x3|3x4|4x2|4x3|4x4] (kolumn x wierszy),

np. mat4, dmat2x3

Samplers, Images, Opaque types, Atomic counters

void

54

Dostęp do składowych wektorów i macierzy

vec4 v v[0], v[1], v[2], v[3]

v.xyzw, v.x, v.xy, v.zyx, v.xxx, v.xxxx

v.rgba (kolory)

v.stpq (współrzędne tekstur)

mat4 m m[2][1]

m[3].xyz

55

Typy zmiennych, c.d.

Struktury struct {

} nazwa;

Tablice typ nazwa[rozmiar]

Po szczegóły dotyczące tablic odsyłam do specyfikacji GLSL

56

Przesyłanie danych

57

Vertex Buffer Object (VBO)

Służy do przekazania danych wierzchołków Zwykle: współrzędne, normalna, kolor, współrzędne tekstur

Ale może zawierać praktycznie dowolne dane

Dane przygotowujemy na CPU, a następnie: GLuint VBO;

glGenBuffers(1, &VBO);

glBindBuffer(GL_ARRAY_BUFFER, VBO);

glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);

58

VBO dla wielu obiektów

Lepiej (wydajniej) jest operować na pojedynczym VBO Przełączanie pomiędzy VBO zajmuje czas

Ale są wyjątki np. dla obiektów, dla których liczba wierzchołków znacząco się zmienia, lepiej

przydzielić oddzielne VBO

www.opengl.org/wiki/Vertex_Specification_Best_Practices

59

Aktualizacja fragmentu lub całości VBO

glBufferSubData(GLenum target, GLintptr offset, GLsizeiptr size, const GLvoid *data);

60

Opisanie struktury VBO

Poprzez tzw. atrybuty: GLint attr = glGetAttribLocation(shaderProgram, "position");

glVertexAttribPointer(attr, 3, GL_FLOAT, GL_FALSE, 9*sizeof(GLfloat), 0);

glEnableVertexAttribArray(attr);

61

Vertex Array Object (VAO)

Pozwala zapamiętać VBO i jego atrybuty glGenVertexArrays(1, &VAO);

glBindVertexArray(VAO);

glBindBuffer(GL_ARRAY_BUFFER, VBO);

GLint attr = glGetAttribLocation(shaderProgram, "position");

glVertexAttribPointer(attr, 3, GL_FLOAT, GL_FALSE, 9*sizeof(GLfloat), 0);

glEnableVertexAttribArray(attr);

glBindVertexArray(0); // ???

62

VAO

63

Uruchomienie rysowania VAO (=VBO+attr)

…jest już bardzo proste: glUseProgram(shaderProgram);

glBindVertexArray(VAO);

glDrawArrays(GL_TRIANGLES, offset, count);

64

Przykład OpenGL03

65

Element Buffer Object (EBO)

66

Korzystanie wyłącznie z wierzchołków jest w większości przypadków nieefektywne

Sześcian – ile trójkątów, ile wierzchołków?

67

Sześcian – ile trójkątów, ile wierzchołków? c.d.

Sześcian ma 8 wierzchołków

Ściany zbudować można z 12 trójkątów

Daje to 36 wierzchołków – 4.5 x więcej!

68

Sześcian – ile trójkątów, ile wierzchołków? c.d.

Jeśli jednak dodamy normalne, to jest lepiej, bo: Wierzchołków jest 3x8 = 24

Czyli licząc 36 liczymy tylko 1.5 x więcej

Ale tak jest tylko dlatego, że wszystkie wierzchołki w sześcianie są „niegładkie”

Często jest całkiem inaczej -->

69

EBO

Reasumując: Często ten sam wierzchołek występuje w kilku trójkątach

Jego wielokrotne obliczanie w vertex shaderze jest zbędne!

70

EBO, c.d.

71

EBO, c.d.

Przekazanie EBO do OpenGL jest podobne do VBO: GLuint EBO;

glGenBuffers(1, &EBO);

glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);

glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);

72

EBO, c.d.

EBO może być zawarte w VAO

Rysowanie wg EBO: glUseProgram(shaderProgram);

glBindVertexArray(VAO);

glDrawElements(GL_TRIANGLES, 3, GL_UNSIGNED_INT, 0);

73

Przykład OpenGL04

74

EBO i kilka VBO

75

Przykład OpenGL05

76

Przepływ danych

W wersji bardzo uproszczonej:

77

Zmienne wbudowane

Pełny wykaz i opis w „The OpenGL Shading Language”, rozdział „Built-in Variables” https://www.opengl.org/registry/doc/GLSLangSpec.4.40.pdf

Część zmiennych aktywna jedynie w określonych kontekstach lub po aktywacji glEnable(…) np. glEnable(GL_VERTEX_PROGRAM_POINT_SIZE) i glDrawArrays(GL_POINTS, …)

pozwala ustawiać gl_PointSize

Należy unikać używania własnych zmiennych z nazwą zaczynającą się od „gl_”

78

Interpolacja dla fragment shadera

Zmienne trafiają do fragment shadera interpolowane

Trzy metody interpolacji (dla zmiennych typu float i pochodnych): smooth – liniowa z uwzględnieniem perspektywy (domyślna metoda)

flat – brak interpolacji (brana jest wartość z ostatniego punktu)

noperspective – liniowa

definiuje się na wejściu do fragment shadera (np. in flat vec3 …)

Ograniczenie zmiennych wejściowych fragment shadera: Nie można używać bool i pochodnych

Zmienne typu int, double i pochodne muszą być oznaczone flat

79

smooth vs noperspective

80

Bufory framebuffera

W celu uniknięcia „migotania” i innych artefaktów: Rysowanie odbywa się do bufora GL_BACK

Po narysowaniu całej sceny, kiedy można ją pokazać, wykonywany jest transfer danych do właściwego widocznego bufora (GL_FRONT) – operacja ta jest zależna od platformy

Np. w Qt, przed wywołaniem paintGL() domyślnie ustawiany jest bufor GL_BACK, o po zakończeniu paintGL() wykonywany jest transfer (zamiana) buforów

GL_FRONT_LEFT, GL_FRONT_RIGHT, GL_BACK_LEFT, GL_BACK_RIGHT

glDrawBuffer(…) ustawia aktualnie używany do rysowania bufor (lub bufory)

81

Modele

82

Modele obiektów

Aby posunąć się dalej z materiałem, jeden trójkąt to za mało

Ręczne wpisywanie modeli bardziej skomplikowanych jest niewygodne

Modele tworzymy zatem w zewnętrznych programach do modelowania (z ew. pomocą skanerów 3D)

83

Modele obiektów, c.d.

Aby model czegoś bardziej skomplikowanego niż trójkąt wyglądał jako tako przyzwoicie, to potrzebne jest: Wczytywanie współrzędnych położenia, współrzędnych tekstur oraz

normalnych wierzchołków

Przekształcenia geometryczne

Oświetlenie

Dopiero potem ma sens dodawanie kolejnych efektów…

84

Demo prostego modelu…

85

Przykład OpenGL07

86

Skąd brać modele (dygresja)

Można zrobić samemu

Można wynająć kogoś z zacięciem plastycznym

Można skorzystać z gotowych modeli http://tf3dm.com

http://graphics.stanford.edu/data/3Dscanrep

87

Przykład OpenGL08

88

glEnable(GL_DEPTH_TEST);

Geometria

89

Przekształcanie wierzchołków

Odbywa się w vertex shader

Współrzędne do vertex shadera trafiają z VBO

Na wyjściu muszą się znaleźć współrzędne wpisane w gl_Position znormalizowane do (-1, -1, -1) – (1, 1, 1)

90

Przekształcanie wierzchołków, c.d.

91

Przestrzenie i przekształcenia

Podział przekształceń na: Modelu (obiektu)

Widoku

Projekcji

oraz przestrzeni na: Modelu

Świata (sceny)

Widoku

jest całkowicie umowny, jednak stosowany jest w wielu pakietach, programach, systemach, artykułach, tutorialach itp., że warto się go trzymać

92

Macierze 4x4

Najwygodniej zakodować przekształcenia za pomocą macierzy 4x4. Można dzięki temu wykonywać: Przesunięcia

Skalowania

Obroty

Rzuty perspektywiczne

Składać w/w przekształcenia

Odwracać w/w przekształcenia

…w sposób łatwy, prosty i przyjemny 93

Przesunięcie (translacja)

94

Skalowanie

95

Obroty

96

Perspektywa

http://www.songho.ca/opengl/gl_projectionmatrix.html 97

Perspektywa, c.d.

98

Rzut równoległy

99

Biblioteki

Tylko najbardziej zawzięci programiści tworzą macierze ręcznie bo to żadne wyzwanie

a pomylić się łatwo

Korzystamy z gotowych bibliotek Np. w Qt jest klasa Matrix4x4, która posiada metody:

• setToIdentity, translate, scale, rotate, ortho, perspective, frustum, inverted, transposed itd.

100

Przekazanie macierzy do vertex shadera

QMatrix4x4 pvm_matrix = p_matrix*v_matrix*m_matrix;

int attr = glGetUniformLocation(shaderProgram, "pvm_matrix");

glUniformMatrix4fv(attr, 1, GL_FALSE, pvm_matrix.data());

Uniformy nie są związane z VBO, więc i do VAO nie da się ich włączyć

101

Przykład OpenGL09/10/11

102

Przód i tył trójkąta

która strona trójkąta to przód? glFrontFace(…); GL_CCW (wartość domyślna)

GL_CW

glEnable(GL_CULL_FACE);

którą stronę trójkątów odrzucać? glCullFace(…); GL_FRONT

GL_BACK 103

Przód i tył trójkąta, c.d.

bool gl_FrontFacing dostępne w fragment shader

Badany jest znak wyrażenia:

104

Przekształcenie normalnych

Wektorów normalnych nie można przekształcać tak samo, jak współrzędnych wierzchołków:

105

Przykład OpenGL12/13

107

Przekształcanie normalnych, c.d.

Vertex shader powinien dysponować dwoma macierzami:

in vec3 position;

in vec3 normal;

uniform mat4 pvm_matrix;

uniform mat3 norm_matrix;

out vec3 fragNormal;

void main()

{

gl_Position = pvm_matrix*vec4(position, 1.0);

fragNormal = normalize(norm_matrix*normal);

}

108

Przekształcanie normalnych, c.d.

Użycie normalnych w fragment shaderze: in vec3 fragNormal;

out vec4 color;

void main()

{

// przykładowe mapowanie normalnej na kolor:

color = vec4(abs(normalize(fragNormal)), 1.0);

}

109

Normalizacja normalnych

Czy jest potrzebna we fragment shaderze?

110

Normalizacja normalnych, c.d.

Czy jest potrzebna w vertex shaderze?

111

Normalizacja normalnych

Reasumując: Brak normalizacji w vertex shaderze może wprowadzać

błąd w kierunku normalnej

Brak interpolacji w fragment shaderze może wprowadzić błąd w długości normalnej

112

Przykład OpenGL14

113

Modele oświetlenia

114

Cel

Modele oświetlenia starają się oddać, jak najbardziej wiernie, zjawiska optyczne związane z postrzeganiem koloru obiektów

Oświetlenie znane z rzeczywistości jest zjawiskiem zbyt złożonym, aby udało się go odwzorować dokładnie, szczególnie w renderingu czasu rzeczywistego Konieczne są zatem uproszczenia

115

Oświetlenie lokalne i globalne

Lokalne: Brane jest pod uwagę jedynie źródło światła i oświetlany obiekt

Obliczane jest tylko jedno odbicie światła (od rozpatrywanego obiektu)

Globalne: Uwzględniane są optyczne interakcje pomiędzy obiektami

• rzucanie cienia

• wielokrotne odbicia

116

117

Oświetlenie lokalne i globalne, c.d.

Oświetlenie lokalne i globalne, c.d.

W grafice czasu rzeczywistego stosuje się oświetlenie lokalne

Dodatkowe efekty uzyskuje się poprzez zastosowanie pewnych elementów oświetlenia globalnego: Cienie

Mapowanie środowiskowe (odbicia, załamanie)

SSAO

itp.

118

Oko

Siatkówka oka

119

„Retina-diagram” autorstwa Fig_retine.png: Cajalderivative work Fig retine bended.png: Anka Friedrich (talk)derivative work: vectorisation by chris 論 - Fig_retine.pngFig retine bended.png. Licencja CC BY-SA 3.0 na podstawie Wikimedia Commons - https://commons.wikimedia.org/wiki/File:Retina-diagram.svg#/media/File:Retina-diagram.svg

Oko, c.d.

Widzenie kolorów zawdzięczamy czopkom, w percepcji barw uczestniczą barwniki: erythrolabe – reagujący z największą czułością na promieniowanie o λ = 590

nm (symbol D od długofalowe), wywołujące wrażenie czerwieni

chlorolabe – najbardziej czuły na promieniowanie o λ = 540 nm (wrażenie zieleni, symbol Śr)

cyanolabe – najbardziej czuły na promieniowanie o λ = 450 nm (wrażenie barwy niebieskiej, symbol K od krótkofalowe)

120

Oko, c.d.

121 "Cone-response PL". Licencja: CC BY-SA 3.0 na podstawie Wikimedia Commons - https://commons.wikimedia.org/wiki/File:Cone-response_PL.svg#/media/File:Cone-response_PL.svg

Model koloru

Dlatego model RGB jest bardzo popularny

Dostarczając do oka odpowiednią mieszankę kolorów czerwonego, zielonego i niebieskiego możemy zasymulować dowolny kolor

Niestety model ten nie jest odpowiedni przy rozpatrywaniu niektórych zjawisk optycznych (np. załamanie światła)

122

Modele źródeł światła

W grafice off-line można pozwolić sobie na lepsze przybliżenia źródeł światła

W grafice czasu rzeczywistego stosuje się kilka uproszczonych rodzajów źródeł światła Źródła punktowe

Źródła kierunkowe

Oświetlenie rozproszone (otoczenia)

123

Źródła punktowe

Zdefiniowane przez: Położenie (punkt w przestrzeni)

Kolor i natężenie emitowanego światła

Pewnym wariantem są źródła typu „spot light”, które dodatkowo charakteryzują się: Kierunkiem świecenia

Kątem oświetlania (ogólniej: funkcją jasności w zależności od kąta)

124

Zmiana jasności w zależności od odległości

Zgodnie z fizyką:

gdzie I – jasność, r – odległość od źródła światła, c – stała

Ze względu na pomijanie wielu zjawisk (głównie odbić) zastosowanie powyższego wzoru powoduje zbyt szybki zanik światła; stosuje się zatem wzór:

125

Źródła kierunkowe

Zdefiniowane przez: Kierunek padania

Kolor i natężenie światła

Jasność nie zmienia się

126

Źródła powierzchniowe

Kształt ma dużo mniejsze znaczenie niż powierzchnia

Najczęściej realizowane jako suma wielu źródeł punktowych

(obrazek obok został wygenerowany off-line)

127

Oświetlenie rozproszone

Zdefiniowane przez: Kolor (ale rzadko)

Natężenie

Pomaga uniknąć wysokich kontrastów i wrażenia ponurości…

Pomaga również na etapie modelowania obiektów i sceny

128

Oświetlenie Phonga

Połączenie światła odbitego (specular) i rozpraszanego (diffuse) od obiektu oraz światła rozproszonego (ambient)

129

Oświetlenie Phonga, c.d.

130

"Phong components version 4" by No machine-readable author provided. Rainwarrior~commonswiki assumed (based on copyright claims). - No machine-readable source provided. Own work assumed (based on copyright claims).. Licensed under CC BY-SA 3.0 via Commons - https://commons.wikimedia.org/wiki/File:Phong_components_version_4.png#/media/File:Phong_components_version_4.png

Oświetlenie Phonga, c.d.

Oznaczenia: N – wektor normalny

L – wektor w kierunku źródła światła

R – wektor odbicia źródła światła

V – wektor w kierunku kamery

Wszystkie wektory są znormalizowane

131

Oświetlenie Phonga, c.d.

132

Inne modele

Model oświetlenia Phonga jest bardzo wygodny, ale nie zawsze doskonale się nadaje – najlepiej sprawdza się dla powierzchni „plastikowych”, dla innych materiałów czasem trudniej dobrać parametry

Model Orena-Nayara Inny model światła rozproszonego (zależny od położenia kamery)

Model BRDF (Bidirectional reflectance distribution function) Inny, bardziej dokładny model światła odbitego

np. Cook’a – Torrance’a http://www.codinglabs.net/article_physically_based_rendering_cook_torrance.aspx

133

Odbicie anizotropowe

134

Odbicie anizotropowe, c.d.

Model Ashikhmina – Shirleya http://www.cs.utah.edu/~shirley/papers/jgtbrdf.pdf

Wykorzystuje model Cook’a – Torrance’a z rozkładem:

135

Obliczenia

Obliczenia można rozłożyć pomiędzy vertex shaderem i fragment shaderem Na ogół więcej jest fragmentów niż wierzchołków

Jeżeli wszystkie obliczenia wykonamy dla wierzchołków (w vertex shaderze) i uzyskany wynik interpolujemy dla fragmentów, to uzyskamy cieniowanie Gourauda

Jeżeli jedynie wektory są jest interpolowane, a reszta obliczeń przeprowadzana jest dla fragmentów, to jest to cieniowanie Phonga

136

Gouraud vs Phong

137

Przykład OpenGL15

138

Materiał

Informacja o kolorze (obiektu lub jego fragmentu) nie jest informacją wystarczającą do realistycznego renedringu

W zależności od przyjętego modelu oświetlenia potrzebne są jeszcze inne atrybuty, np. dla Phonga.: Współczynniki ka, ks, dd, n (shininess)

139

Przykład OpenGL16

140

Uniform Data Block

Pozwala załadować dane typu uniform z bufora OpenGL

Pozwala na dzielenie danych pomiędzy programami

Deklaracja w shaderze: layout (std140) uniform Nazwa

{

// pola

};

141

Uniform Data Block, c.d.

Załadowanie do OpenGL: glGenBuffers(1, &MAT);

glBindBuffer(GL_UNIFORM_BUFFER, MAT);

glBufferData(GL_UNIFORM_BUFFER, data_size, data, GL_DYNAMIC_DRAW);

glBindBufferBase(GL_UNIFORM_BUFFER, 0, MAT);

GLuint blockIndex = glGetUniformBlockIndex(shaderProgram, "Nazwa");

glUniformBlockBinding(shaderProgram, blockIndex, 0);

142

layout

Zgodnie z https://www.opengl.org/registry/specs/ARB/uniform_buffer_object.txt opcje layoutu, dotyczące upakowania, to: shared (domyślne) pozwala kompilatorowi zoptymalizować położenie pól, ale nie

pozwala ich usuwać, jeśli nie są używane; gwarantuje, że pakowanie będzie takie samo dla takich samych definicji bloku

packed podobnie jak share, jednak pola nieużywane mogą zostać usunięte

std140 położenie pól zgodne ze zdefiniowanymi regułami

143

layout std140

Dla: layout (std140) uniform Material

{

vec3 ambient;

vec3 diffuse;

vec3 specular;

float shininess;

}

144

(1) If the member is a scalar consuming <N> basic machine units, the base alignment is <N>.

(2) If the member is a two- or four-component vector with components consuming <N> basic machine units, the base alignment is 2<N> or 4<N>, respectively.

(3) If the member is a three-component vector with components consuming <N> basic machine units, the base alignment is 4<N>.

(4) If the member is an array of scalars or vectors, the base alignment and array stride are set to match the base alignment of a single array element, according to rules (1), (2), and (3), and rounded up to the base alignment of a vec4. The array may have padding at the end; the base offset of the member following the array is rounded up to the next multiple of the base alignment.

(5) If the member is a column-major matrix with <C> columns and <R> rows, the matrix is stored identically to an array of <C> column vectors with <R> components each, according to rule (4).

(6) If the member is an array of <S> column-major matrices with <C> columns and <R> rows, the matrix is stored identically to a row of <S>*<C> column vectors with <R> components each, according to rule (4).

(7) If the member is a row-major matrix with <C> columns and <R> rows, the matrix is stored identically to an array of <R> row vectors with <C> components each, according to rule (4).

(8) If the member is an array of <S> row-major matrices with <C> columns and <R> rows, the matrix is stored identically to a row of <S>*<R> row vectors with <C> components each, according to rule (4).

(9) If the member is a structure, the base alignment of the structure is <N>, where <N> is the largest base alignment value of any of its members, and rounded up to the base alignment of a vec4. The individual members of this sub-structure are then assigned offsets by applying this set of rules recursively, where the base offset of the first member of the sub-structure is equal to the aligned offset of the structure. The structure may have padding at the end; the base offset of the member following the sub-structure is rounded up to the next multiple of the base alignment of the structure.

(10) If the member is an array of <S> structures, the <S> elements of the array are laid out in order, according to rule (9).

145

Przykład OpenGL17

146

Tekstury

147

Tekstura (mapa)

Tekstury generalnie służą do tego, aby zastąpić we fragment shaderze: Interpolowane wartości

poprzez: Wartości z tekstury dla interpolowanych współrzędnych

Istnieje wiele rodzajów tekstur: GL_TEXTURE_1D, GL_TEXTURE_2D, GL_TEXTURE_3D, GL_TEXTURE_RECTANGLE, GL_TEXTURE_CUBE_MAP, …

148

Tekstura jako kolor

149

Współrzędne tekstury

Współrzędne tekstur, podobnie jak np. wektory normalne są generowane przez programy do tworzenia modeli

Ręczne generowanie jest raczej niewygodne…

Oznaczane są jako u i v lub s i t

150

Współrzędne tekstury, c.d.

W OpenGL punkt (0, 0) tekstury to lewy dolny róg

W większości programów do modelowania punkt (0, 0) to lewy górny róg…

Trzeba zatem na jakimś etapie dokonać odbicia współrzędnej Y: Można na etapie wczytywania modelu/tekstur (najlepsze rozwiązanie)

Można odbić tekstury (słabe rozwiązanie)

Można w vertex shaderze (może być)

Można we fragment shaderze (nieefektywne rozwiązanie) 151

Zakres współrzędnych tekstury

Współrzędne tekstur są z zakresu <0, 1>, jeśli wyjdziemy poza, to zachowanie może być różne (domyślnie GL_REPEAT):

152

Mipmapping

Jeżeli „rozdzielczość” fragmentów jest mniejsza niż tekstury, to aby ustalić wartość tekstury należałoby uśrednić pewien obszar tekstury

153

Mipmapping, c.d.

Aby uniknąć uśredniania w czasie renderingu, wcześniej należy przygotować odpowiedni zestaw tekstur

Generowane są pomniejszone tekstury (za każdym razem dwukrotnie), tzw. poziomy (level)

Mipmapping może być wykorzystywany tylko kiedy zachodzi konieczność pomniejszenia tekstury, przy powiększaniu wykorzystywana jest zawsze tekstura poziomu 0

154

Mipmapping, c.d.

155

"MipMap Example STS101" by en:User:Mulad, based on a NASA image - Created by en:User:Mulad based on File:ISS from Atlantis - Sts101-714-016.jpg. Licensed under CC BY-SA 3.0 via Commons - https://commons.wikimedia.org/wiki/File:MipMap_Example_STS101.jpg#/media/File:MipMap_Example_STS101.jpg

Mipmapping, c.d.

W zależności od ustawienia parametru GL_TEXTURE_MIN_FILTER: GL_NEAREST, GL_LINEAR

• mipmapping nie jest używany, stosowana jest tekstura poziomu 0

GL_NEAREST_MIPMAP_NEAREST, GL_LINEAR_MIPMAP_NEAREST • Wybierana jest jedna najlepsza mipmapa

GL_NEAREST_MIPMAP_LINEAR, GL_LINEAR_MIPMAP_LINEAR • Wybierane są dwie mipmapy i następuje interpolacja między nimi

156

Ładowanie tekstury

Qt ma klasę QImage do wczytywania i przetwarzania obrazków:

QImage tex(nazwa_pliku);

Następnie można wysłać teksturę do karty:

glGenTextures(1, &texture);

glBindTexture(GL_TEXTURE_2D, texture);

glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB,

tex.width(), tex.height(),

0, GL_BRGA, GL_UNSIGNED_BYTE, tex.bits());

157

Ładowanie tekstury, c.d.

Można zlecić wykonanie mipmap:

glGenerateMipmap(GL_TEXTURE_2D);

glTexParameteri(GL_TEXTURE_2D,

GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);

Końcowe podłączenie do shadera:

int attr_tex = glGetUniformLocation(shaderProgram, "textureBitmap");

glUniform1i(attr_tex, 0);

glActiveTexture(GL_TEXTURE0);

glBindTexture(GL_TEXTURE_2D, texture);

158

Użycie tekstury we fragment shaderze

in vec2 fragTexCoor;

uniform sampler2D textureBitmap;

vec4 color = texture(textureBitmap, fragTexCoor);

159

Przykład OpenGL18

160

Inne zastosowania tekstur

Użycie tekstury do pokolorowania powierzchni było ich pierwszym zastosowaniem

161

Inne zastosowania tekstur, c.d.

Obecnie, kiedy mamy pełną kontrolę nad danymi z tekstury (przez program w shaderze) możemy wykorzystywać je w praktycznie dowolny sposób

W szczególności: Do mapowania parametrów cieniowania (np. specular, shininess)

Do mapowania normalnych

Do mapowania paralaksy

Do generowania cieni

162

Przykład OpenGL19

163

Mapowanie normalnych

Pozwala uzyskać efekt nierówności powierzchni

Wymaga niestety pewnych manipulacji geometrycznych

164

Mapa normalnych

165

W składowych RGB kodujemy wektory normalne do powierzchni

Przestrzeń stycznych

Wektor normalny pobrany z mapy musi zostać odpowiednio przetransformowany do współrzędnych powierzchni do której się odnosi

166

Przestrzeń stycznych, c.d.

Wektory T (tangent) i B (bitangent) można wyliczyć ze współrzędnych tekstury dla wierzchołków

167

Przestrzeń stycznych, c.d.

168

Macierz TBN

Rozszerzając macierz o wektor normalny uzyskujemy tzw. macierz TBN:

Która transformuje pomiędzy przestrzenią mapy normalnych a przestrzenią modelu i posiada użyteczną własność:

169

VBO

Obliczone wektory T i B dodajemy do VBO

Czyli obliczeń T i B możemy dokonać po wczytaniu modelu (jeśli model już ich nie zawiera)

170

Obliczenia w shaderach, wersja 1

Vertex shader: in vec3 normal;

in vec3 tgnU;

in vec3 tgnV;

out mat3 fragTBN;

vec3 T = normalize(norm_matrix * tgnU);

vec3 B = normalize(norm_matrix * tgnV);

vec3 N = normalize(norm_matrix * normal);

fragTBN = mat3(T, B, N);

171

Obliczenia w shaderach, wersja 1, c.d.

Fragment shader: in mat3 fragTBN;

vec3 texNormal = texture(textureNormal, fragTexCoor).rgb * 2.0 - 1.0;

texNormal = normalize(fragTBN*texNormal);

172

Przykład OpenGL20

173

Obliczenia w shaderach, wersja 2

Vertex shader: uniform Light light;

uniform vec3 eyePos;

out vec3 fragTanEyePos;

out vec3 fragTanLightPos;

out vec3 fragTanFragPos;

out vec3 fragTanNormal;

fragTanLightPos = TBN * light.pos;

fragTanEyePos = TBN * eyePos;

fragTanFragPos = TBN * fragPos;

fragTanNormal = TBN * N;

174

Obliczenia w shaderach, wersja 2, c.d.

Fragment shader: in vec3 fragTanEyePos;

in vec3 fragTanLightPos;

in vec3 fragTanFragPos;

in vec3 fragTanNormal;

vec3 texNormal = normalize(texture(textureNormal, fragTexCoor).rgb * 2.0 - 1.0);

vec3 lightDir = normalize(fragTanLightPos - fragTanFragPos);

175

Porównanie

Wersja 1: Prostsza koncepcyjnie

Wersja 2: Wydajniejsza (mnożenie macierzy dla wierzchołków, nie dla fragmentów)

176

Przykład OpenGL21

177

Mapowanie paralaksy

Chcemy, aby teksturowana powierzchnia wyglądała jakby miała elementy przestrzenne à la płaskorzeźba

178

Mapowanie paralaksy, c.d.

Ale użycie takiej tekstury nie daje w pełni zadowalających efektów…

179

Mapowanie paralaksy, c.d.

Aby uzyskać dobry wynik, należałoby obliczyć poprawny punkt przecięcia na powierzchni (pkt B zamiast A):

Mapa wysokości

Aby uzyskać taki efekt potrzebna jest tekstura z wysokością/głębokością

181

Przesunięcie tekstury, wersja 1

W wersji najbardziej prymitywnej przesuwamy współrzędne tekstury o wysokość tekstury odczytaną z mapy wysokości

182

Przesunięcie tekstury, wersja 1, c.d.

Fragment shader: uniform sampler2D textureDepth;

vec2 ParallaxMapping(vec2 texCoor, vec3 viewDir)

{

const float height_scale = 2.0/128.0; float height = texture(textureDepth, texCoor).r * height_scale;

vec2 p = viewDir.xy / viewDir.z * height;

return texCoor - p;

} 183

Przykład OpenGL22

184

Przesunięcie tekstury, wersja 2

Wersja 1 sprawdza się tylko dla kątów patrzenia niezbyt odchylonych od normalnej (do mniej więcej 45 stopni)

Ale przesunięcia tekstury można szukać iteracyjnie (steep parallax mapping)

185

Przesunięcie tekstury, wersja 3

Jeśli jeszcze uśrednimy wynik z dwóch końcowych poziomów, to unikniemy efektu schodków i efekt będzie znacznie lepszy…

186

Przykład OpenGL23

187

Uwagi praktyczne dot. mapowania paralaksy

Mapowanie paralaksy może być czasochłonnym procesem Dobór parametrów (np. liczba warstw)

Nie zawsze daje oczekiwany (łatwo zauważalny) wzrost realizmu Zależy od odległości od tekstury, wielkości szczegółów, różnic w głębokości

itp.

188

Skybox

Służy do renderowania statycznego tła

Wykorzystuje teksturę typu GL_TEXTURE_CUBE_MAP 6 tekstur jednakowej wielkości

(X+, X-, Y+, Y-, Z+, Z-)

Wartość pobierana dla dowolnego wektora 3D

189

Skybox, c.d.

190

SkyboxSet by Heiko Irrgang ( http://gamvas.com ) is licensed under the Creative Commons Attribution-ShareAlike 3.0 Unported License. Based on a work at http://93i.de.

Skybox, c.d.

Obiektem, na którym renderowane jest tło jest kwadrat wielkości ekranu, którego współrzędna Z gwarantuje, że faktycznie będzie w tle

Obliczenia Vertex shader oblicza jedynie współrzędne tekstury tła (na podstawie odwrotnej

macierzy złożenia widoku i perspektywy) • Macierz ta może być policzona wcześniej przez CPU

Fragment shader pobiera kolor fragmentu z tekstury • Może dokonać modyfikacji, np. przyciemnienia, rozjaśnienia itp.

Skybox renderujemy na końcu

191

Przykład OpenGL24

192

Dwa ciekawe efekty

Dysponując skyboxem możemy uzyskać w prosty sposób dwa efekty: Obiekty lustrzane (odbicie światła)

Obiekty przejrzyste (załamanie światła)

Wykorzystujemy tu fakt, że skybox zawiera widok świata, który jest niezmienny dla wszystkich punktów sceny

193

Odbicie lustrzane skyboxa

We fragment shaderze: vec3 I = normalize(fragPos.xyz - eyePos);

vec3 R = reflect(I, normalize(fragNormal));

vec3 mirror = texture(textureSkybox, R).rgb;

color = vec4(material.ambient + diffuse + specular + mirror, 1.0);

194

Przykład OpenGL25

195

Odbicie lustrzane skyboxa, c.d.

Jeżeli nie cały obiekt ma być lustrzany, można np. zastosować dodatkową teksturę obiektu definiującą, które fragmenty powierzchni są odbijające

196

Załamanie światła

We fragment shaderze: float ratio = 1.0 / 1.52;

vec3 I = normalize(fragPos.xyz - eyePos);

vec3 R = refract(I, normalize(fragNormal), ratio);

vec3 refracted = texture(textureSkybox, R).rgb;

color = vec4(material.ambient + diffuse + specular + refracted, 1.0);

197

Przykład OpenGL26

198

Dwie tekstury na płaski obiekt

Zastosowanie dwóch tekstur dla płaskich obiektów pozwala uzyskać efekt prześwitywania

199

Przykład OpenGL27

200

Cienie, cz. I

201

Cienie od kierunkowych źródeł światła

Mapowanie cieni

Podstawowym sposobem generowania cieni w OpenGL jest tzw. shadow mapping

Algorytm działa dwuprzebiegowo: W pierwszym przebiegu generowana jest mapa głębokości obiektów

widziana z perspektywy źródła światła

W drugim przebiegu generowany jest właściwy obraz

Jeżeli źródeł światła jest więcej, to pierwszy przebieg wykonywany jest dla każdego źródła światła, generując oddzielną mapę

202

Mapowanie cieni, c.d.

W obu przebiegach renderowana jest ta sama scena

Pierwszy przebieg jest znacznie szybszy: Nie wykonujemy cieniowania

Nie wykonujemy przesunięć normalnych, paralaksy itp.

Interesuje nas wyłącznie obliczenie współrzędnej Z każdego fragmentu

Pierwszy przebieg można jeszcze przyspieszyć: Stosując mniej szczegółowe modele obiektów

Pomijając obiekty, które nie rzucają cienia (np. ściany)

Pomijając obiekty, o których wiemy, że nie zostaną objęte mapą cienia 203

Framebuffer

Domyślnie rendering wykonywany jest do framebuffera, który jest następnie mapowany (w kooperacji z systemem okienkowym) na ekran

Można jednak utworzyć własny framebuffer

Framebuffer składa się z kilku buforów: Głębokości (jeden)

Kolorów (kilka, w domyślnym: GL_FRONT_LEFT, GL_FRONT_RIGHT, GL_BACK_LEFT, GL_BACK_RIGHT, we własnych 0…N)

Szablonu (jeden) 204

Nowy framebuffer

Aby utworzyć framebuffer należy stworzyć odpowiednie tekstury, utworzyć obiekt framebuffera (FBO) i podczepić do niego utworzone tekstury w roli odpowiednich buforów

205

Tekstury dla framebuffera (W x H)

Tekstura bufora koloru: glGenTextures(1, &tex_FBO_color);

glBindTexture(GL_TEXTURE_2D, tex_FBO_color);

glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB,

W, H, 0, GL_RGB, GL_UNSIGNED_BYTE, NULL);

Tekstura bufora głębokości: glGenTextures(1, &tex_FBO_depth);

glBindTexture(GL_TEXTURE_2D, tex_FBO_depth);

glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT,

W, H, 0, GL_DEPTH_COMPONENT, GL_FLOAT, NULL);

206

Framebuffer

Utworzenie samego framebuffera jest już proste: glGenFramebuffers(1, &FBO);

glBindFramebuffer(GL_FRAMEBUFFER, FBO);

glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, tex_FBO_color, 0);

glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, tex_FBO_depth, 0);

207

Rendering do framebuffera

Aby rendering odbywał się do nowego framebuffera: glViewport(0, 0, W, H);

glBindFramebuffer(GL_FRAMEBUFFER, FBO);

A jak przywrócić stan pierwotny? Kiedyś było prościej:

glBindFramebuffer(GL_FRAMEBUFFER, 0);

Ale teraz: GLint FBO_screen;

glGetIntegerv(GL_FRAMEBUFFER_BINDING, &FBO_screen);

glBindFramebuffer(GL_FRAMEBUFFER, FBO_screen);

I jeszcze trzeba pamiętać o przywróceniu rozdzielczości: glViewport(0, 0, width(), height());

208

Przykład OpenGL28

209

Mapa cienia dla światła kierunkowego

Rendering z perspektywą równoległą zgodną z kierunkiem światła

Do ustalenia: Rozdzielczość framebuffera

Rozmiar framebuffera

Głębokości graniczne dla bufora głębokości (near plane, far plane)

210

Generacja mapy cienia

W tym przebiegu interesuje nas tylko bufor głębokości, zatem w utworzonym FBO nie będzie żadnego bufora kolorów

Aby dodatkowo zasygnalizować, że kolor ma nie być renderowany: glDrawBuffer(GL_NONE);

211

Macierz dla mapy cienia

W Qt (przykładowe dane): light_matrix.setToIdentity();

light_matrix.ortho(-5.0, 5.0, // x

-5.0, 5.0, // y

0.0, 20.0); // z

light_matrix.lookAt(

QVector3D(light.dir[0], light.dir[1], light.dir[2]).normalized()*5.0, // eye

QVector3D(0, 0, 0), // center

QVector3D(1, 1, 1)); // up 212

Shadery dla mapy cienia

Vertex shader (nie najbardziej optymalny): in vec3 position;

uniform mat4 light_matrix;

uniform mat4 m_matrix;

void main()

{

gl_Position = light_matrix*m_matrix*vec4(position, 1.0);

}

Fragment shader: void main() { }

213

Rendering z wykorzystaniem mapy cienia

Vertex shader wykonuje to samo obliczenie, co w przebiegu generacji mapy cienia (oprócz innych obliczeń)

Fragment shader sprawdza, czy dany fragment jest w cieniu, czy nie i odpowiednio modyfikuje kolor

214

Testowanie cienia bool inShadow(vec3 lightdir, vec3 normal)

{

vec3 p = (fragPosLight.xyz / fragPosLight.w)*0.5 + 0.5; if (p.x < 0.0 || p.x > 1.0 || p.y < 0.0 || p.y > 1.0 || p.z > 1.0) return false;

float d = texture(textureShadow, p.xy).x;

float bias = max(0.01 * (1.0 - dot(normal, lightdir)), 0.001);

return p.z - bias > d;

}

215

Efekt moiré

216

bias

Aby uniknąć efektu moiré (samocieniowania) należy zastosować odpowiednie przesunięcie współrzędnej Z

Nie za małe, bo efekt nie zostanie usunięty

Nie za duże, bo powstanie nowy niepożądany efekt, tzw. efekt Piotrusia Pana (peter panning)

Może być adaptacyjne, jak w przykładzie na poprzednim slajdzie

Istnieją też inne, bardziej precyzyjne algorytmy 217

Przykład OpenGL29

218

PCF (Percentage-Closer Filtering)

Cienie ostre: Rzadko wyglądają dobrze

Ze względu na ograniczoną rozdzielczość mapy cienia widoczne są poszarpane krawędzie cieni

Cienie miękkie: Wyglądają lepiej

Rozmazują krawędzie cieni ukrywając poszarpanie

219

PCF, c.d.

Metoda PCF polega na próbkowaniu kilku/kilkunastu/kilkudziesięciu próbek mapy cienia zamiast jednej

float shadow = 0.0;

vec2 texel = 1.0/textureSize(textureShadow, 0);

for (float i = -1.5; i <= 1.51; i += 1.0)

for (float j = -1.5; j <= 1.51; j += 1.0)

{

float d = texture(textureShadow, p.xy + vec2(i, j)*texel).x;

shadow += (p.z - bias > d) ? 1.0 : 0.0;

}

return 1.0 - shadow/16.0; 220

PCF z ditheringiem

Zamiast próbkować 16 razy można 4 wykorzystując technikę ditheringu http://http.developer.nvidia.com/GPUGems/gpugems_ch11.html

221

Przykład OpenGL30

222

Mapa cienia dla światła punktowego

Sprawa się komplikuje i, aby zrobić to efektywnie, będziemy potrzebowali…

223

Geometry shader

224

Nie tylko trójkąty

Do tej pory we wszystkich przykładach obiekty były rysowane jako zbiór trójkątów glDrawArrays…(GL_TRIANGLES, …);

albo

glDrawElements…(GL_TRIANGLES, …);

Są jednak także inne możliwości

225

Nie tylko trójkąty, c.d.

226

GL_TRIANGLE_STRIP, GL_TRIANGLE_FAN

227

Nie tylko trójkąty, c.d.

228

Zastosowanie geometry shadera

Geometry shader dostaje na wejściu wierzchołki pojedynczego prymitywu, a następnie na ich podstawie może wygenerować dowolną liczbę dowolnych prymitywów (ale zawsze tych samych) i ich wierzchołki

229

OpenGL 4.5 rendering pipeline (przypomnienie)

230

Wejście do geometry shadera

Musimy określić, jakie prymitywy trafiają do geometry shadera z vertex shadera (tesselation shadera): layout (points) in;

• Dla: GL_POINTS

layout (lines) in; • Dla: GL_LINES i GL_LINE_STRIP

layout (triangles) in; • Dla: GL_TRIANGLES, GL_TRIANGLE_STRIP, GL_TRIANGLE_FAN

layout (lines_adjacency) in; • Dla: GL_LINES_ADJACENCY i GL_LINE_STRIP_ADJACENCY

layout (triangles_adjacency) in; • Dla: GL_TRIANGLES_ADJACENCY i GL_TRIANGLE_STRIP_ADJACENCY

231

Wejście do geometry shadera, c.d.

Za każdym razem geometry shader dostanie na wejściu tablicę wierzchołków: points: gl_in[1]

lines: gl_in[2]

triangles: gl_in[3]

lines_adjacency: gl_in[4]

triangles_adjacency: gl_in[6]

232

Zmienne wbudowane

W geometry shaderze mamy do dyspozycji tablicę gl_in[], której elementy zawierają pola: vec4 gl_Position;

float gl_PointSize;

float gl_ClipDistance[];

float gl_CullDistance[];

Mamy też do dyspozycji licznik prymitywów: int gl_PrimitiveIDIn;

233

Wejście do geometry shadera, c.d.

Również każda wyjściowa dana z vertex shadera staje się automatycznie tablicą w geometry shaderze: Vertex shader:

out vec3 abc;

Geometry shader: in vec3 abc[];

Rozmiar tablicy określa rodzaj prymitywu (czyli 1, 2, 3, 4 lub 6)

234

Wyjście z geometry shadera

Musimy określić jakie prymitywy będzie generował geometry shader: layout (points, max_vertices = …) out;

layout (line_strip, max_vertices = …) out;

layout (triangle_strip, max_vertices = …) out;

W każdym przypadku musimy podać maksymalną liczbę wierzchołków jakie wygenerujemy

235

Przykład OpenGL31

236

Przykład OpenGL32

237

Cienie, cz. II

238

Cienie od punktowych źródeł światła

Cienie punktowych źródeł światła

Po pierwsze należy rozważyć, czy cienie światła punktowego nie mogą być mapowane tak, jak w przypadku światła kierunkowego

Może się tak stać, jeśli: Źródło światła jest „poza” sceną

Źródło światła oświetla mniej niż połowę sfery (np. światło typu spotlight)

Inne przypadki

239

Cienie punktowych źródeł światła, c.d.

Wówczas można jedynie zastosować tylko inne przekształcenie (perspektywiczne zamiast równoległego)

240

Mapa cienia typu CUBE

241

W pozostałych przypadkach, aby objąć całą przestrzeń otaczającą źródło światła, można zastosować teksturę typu CUBE

Mapa cienia typu CUBE, c.d.

Problem polega na tym, że nie można do framebufora podczepić textury typu CUBE jako bufora głębokości i liczyć, że to od razu zadziała…

Każdą ze ścian skyboxa należy potraktować oddzielnie i co za tym idzie dokonać mapowania cieni sześciokrotnie

Można to zrobić na 2 sposoby: W paintGL() najpierw 6 razy generujemy mapy cieni odpowiednio

zmieniając framebufory

Wykorzystać do tego geometry shader 242

Co należy przygotować na CPU?

6 macierzy widoku sceny z punktu źródła światła w kierunku wszystkich sześciu ścian

Teksturę typu CUBE

Framebufor

243

gl_Layer

Specjalna zmienna gl_Layer służy do wyboru ściany tekstury CUBE, która zostanie wykorzystana

244

gl_Layer tekstura

0 GL_TEXTURE_CUBEMAP_POSITIVE_X

1 GL_TEXTURE_CUBEMAP_NEGATIVE_X

2 GL_TEXTURE_CUBEMAP_POSITIVE_Y

3 GL_TEXTURE_CUBEMAP_NEGATIVE_Y

4 GL_TEXTURE_CUBEMAP_POSITIVE_Z

5 GL_TEXTURE_CUBEMAP_NEGATIVE_Z

Działanie geometry shadera

Geometry shader „rozmnaża” każdy trójkąt: for (int face = 0; face < 6; face++) {

gl_Layer = face;

for (int i = 0; i < 3; i++) {

fragPos = gl_in[i].gl_Position;

gl_Position = light_matrix[face] * fragPos;

EmitVertex();

}

EndPrimitive();

}

245

Przykład OpenGL33

246

PCF dla cieni od punktowych źródeł światła

Próbkowanie z tekstury typu CUBE odbywa się na bazie wektora 3D, a nie 2D

Może to powodować nadmierną liczbę próbkowań

Rozwiązaniem jest wykorzystanie tablicy z predefiniowanymi punktami w 3D

247

Przykład OpenGL34

248

HDR

249

High Dynamic Range

Historia

HDR (High Dynamic Range) ma swój rodowód w fotografii 1850, Gustave Le Gray

250

"Gustave Le Gray - Brig upon the Water - Google Art Project" by Gustave Le Gray - dwEJBbTOxE61pQ at Google Cultural Institute, zoom level maximum. Licensed under Public Domain via Commons - https://commons.wikimedia.org/wiki/File:Gustave_Le_Gray_-_Brig_upon_the_Water_-_Google_Art_Project.jpg#/media/File:Gustave_Le_Gray_-_Brig_upon_the_Water_-_Google_Art_Project.jpg

251

"StLouisArchMultExpEV-4.72" by Kevin McCoy - Own work. Licensed under CC BY-SA 3.0 via Commons - https://commons.wikimedia.org/wiki/File:StLouisArchMultExpEV-4.72.JPG#/media/File:StLouisArchMultExpEV-4.72.JPG

-4

252

"StLouisArchMultExpEV-4.72" by Kevin McCoy - Own work. Licensed under CC BY-SA 3.0 via Commons - https://commons.wikimedia.org/wiki/File:StLouisArchMultExpEV-4.72.JPG#/media/File:StLouisArchMultExpEV-4.72.JPG

-2

253

"StLouisArchMultExpEV-4.72" by Kevin McCoy - Own work. Licensed under CC BY-SA 3.0 via Commons - https://commons.wikimedia.org/wiki/File:StLouisArchMultExpEV-4.72.JPG#/media/File:StLouisArchMultExpEV-4.72.JPG

+2

254

"StLouisArchMultExpEV-4.72" by Kevin McCoy - Own work. Licensed under CC BY-SA 3.0 via Commons - https://commons.wikimedia.org/wiki/File:StLouisArchMultExpEV-4.72.JPG#/media/File:StLouisArchMultExpEV-4.72.JPG

+4

255

"StLouisArchMultExpEV-4.72" by Kevin McCoy - Own work. Licensed under CC BY-SA 3.0 via Commons - https://commons.wikimedia.org/wiki/File:StLouisArchMultExpEV-4.72.JPG#/media/File:StLouisArchMultExpEV-4.72.JPG

Simple contrast reduction

256

"StLouisArchMultExpEV-4.72" by Kevin McCoy - Own work. Licensed under CC BY-SA 3.0 via Commons - https://commons.wikimedia.org/wiki/File:StLouisArchMultExpEV-4.72.JPG#/media/File:StLouisArchMultExpEV-4.72.JPG

Local tone mapping

I jeszcze jeden przykład

257

by Dean S. Pemberton, 6 exposures illustrating the Steps to take an HDR Image

258

LDR

Standardowo bufory kolorów przechodują dane w formacie LDR

Każdy komponent jest z zakresu [0.0…1.0], z dokładnością 1/256

Problemy: Sumowanie oświetlenia z kilku źródeł może doprowadzić, do przekroczenia

wartości 1.0 (nastąpi wówczas przycięcie do tej wartości)

Brak możliwości elastycznego różnicowania jasności źródeł światła

Itp. 259

LDR, dodawanie kolorów

260

HDR

Rendering wykonujemy do bufora, który ma więcej niż 8 bitów na kolor i nie przycina wartości do zakresu [0.0…1.0] GL_RGB16F, GL_RGBA16F

GL_RGB32F, GL_RGBA32F

Następnie renderujemy ten bufor na prostokąt ekranu (podobnie jak w przypadku skyboxa) zmieniając wartości HDR na LDR

261

HDR output? c.d. http://www.firstshowing.net/2015/dolby-impresses-cinemacon-with-

10000001-hdr-projection-demo

263

Typy zmiennoprzecinkowe w OpenGL

264

https://www.opengl.org/wiki/Small_Float_Formats

https://en.wikipedia.org/wiki/IEEE_754-1985

Tone mapping

Istnieje wiele metod na mapowanie HDR LDR, które przy okazji pozwalają uzyskać dodatkowe efekty

Mapowanie Reinharda Bardzo proste

Zachowuje większy kontrast dla ciemnych kolorów

265

Tone mapping, c.d.

Ekspozycja

266

Tone mapping, c.d.

W http://filmicgames.com/archives/75 można znaleźć kilka ciekawych wzorów

Np. Jim Hejl i Richard Burgess-Dawson:

267

Adaptacyjny tone mapping

Próbkowanie pobliskich 25 punktów, określenie ich jasności („luminancji”)

Na ich podstawie określenie lokalnej jasności i dopasowanie ekspozycji

268

Skala szarości

Niektórzy uważają, że jak coś jest czarno-białe, to robi się bardziej „artystyczne”

Wzór dla nich wygląda tak:

A jak ma być cieplej, to:

269

Tekstury HDR

Format RADIANCE (*.hdr) 1985 by Greg Ward, format RGBE

32 bit/pixel

Kod C do dekodowania: http://www.graphics.cornell.edu/~bjw/rgbe.html

Format OpenEXR (*.exr) 2003 by Industrial Light and Magic

16 lub 32 bit/kolor

Lib do dekodowania: http://www.openexr.com

Format KTX (*.ktx) Khronos

https://www.khronos.org/opengles/sdk/tools/KTX/file_format_spec 270

Korekcja gamma

271

Oko ludzkie nie odbiera jasności kolorów w sposób liniowy

Stosuje się tzw. korekcję gamma, która powoduje, że skala kolorów jest bardziej naturalna (pokazać obrazek gamma-test.png!)

Wartości parametru gamma wahają się w okolicy 2 CRT: 2.2

LCD: ~ 1.8

Projektory: ???

Korekcja gamma, c.d.

Niestety, fakt że kolory są przesunięte zgodnie ze krzywą gamma powoduje, że dodawanie kolorów nie jest do końca poprawne nawet w HDR

Można to oczywiście zignorować, albo pracować na kolorach „zlinearyzowanych”, a następnie nałożyć korektę gamma

W OpenGL możemy wykorzystać specjalny format tekstury GL_SRGB (GL_SRGB_ALPHA), oczywiście tylko do tekstur z informacją o kolorach (tekstury z normalnymi, mapami głębokości itp. nie podlegają korekcji gamma!)

272

Porównanie

273

Osłabianie światła (attenuation)

Stosowanie korekcji gamma pozwala na użycie liniowej zależności pomiędzy odległością od punktowego źródła światła, a jego intensywnością

Normalnie zależność ta jest kwadratowa, ale skoro stosujemy gammę w okolicach 2.0, to jest to akceptowalne…

274

Przykład OpenGL35

275

Rozmycie gaussowskie

Służy do miękkiego rozmycia obrazu

Wzór: określa wartość współczynnika w odległości (x, y) od środka

276

Rozmycie gaussowskie, c.d.

Tabela współczynników może wyglądać np. tak:

Jest symetryczna, współczynniki na końcu są pomijalnie małe

277

Rozmycie gaussowskie, c.d.

Gdyby bezpośrednio zastosować tabelkę z poprzedniego slajdu, to dla każdego pixela trzeba by wykonać 49 (7x7) sumowań

Na szczęście rozmycie gaussowskie ma tę ciekawą własność, że można je obliczyć jako złożenie rozmycia jednowymiarowego w kierunku X i kierunku Y

Każde z rozmyć jednowymiarowych to 7 składników, zatem ostatecznie będzie tylko 14 (7+7)

278

Rozmycie gaussowskie, c.d.

279

W celu uzyskania większego rozmycia można: Zwiększyć promień rozmycia

Rozmyć powtórnie już rozmyty obraz

(Rysunek poglądowy…)

Współczynniki

Współczynniki można albo obliczyć bezpośrednio z rozkładu Gaussa, albo wykorzystać trójkąt Pascala

280

Współczynniki, c.d.

281

Fragment shader dla rozmycia gaussowskiego uniform float horizontal;

float w[5] = {0.227027, 0.1945946, 0.1216216, 0.054054, 0.016216};

vec2 texel = 1.0/textureSize(textureIn, 0);

texel.x *= horizontal;

texel.y *= (1.0 - horizontal);

color = texture(textureIn, fragTexCoor)*w[0];

for (int i = 1; i < w.length; i++)

color += texture(textureIn, fragTexCoor + vec2(texel.x*i, texel.y*i))*w[i] + texture(textureIn, fragTexCoor - vec2(texel.x*i, texel.y*i))*w[i];

282

Efekt poświaty

Aby uwidocznić w scenie obiekty o większej jasności stosuje się tzw. poświatę (glow, bloom), bo w większości przypadków nie ma fizycznej możliwości, aby zaświecić piksele mocniej niż (255, 255, 255)…

283

Efekt poświaty

Do uzyskania efektu poświaty należy: Wykryć fragmenty o jasności większej niż zadany próg (co jest możliwe

dzięki HDR)

Wykryte fragmenty zapisać do oddzielnej tekstury

Rozmyć teksturę z jasnymi fragmentami

Połączyć (dodać) obraz oryginalny i rozmyte jasne fragmenty

284

Efekt poświaty, c.d.

285

Przykład OpenGL36

286

Przetwarzanie w OpenGL36

287

Opóźnione cieniowanie

288

Deferred shading

Cel opóźnienia cieniowania

Proces cieniowania staje się coraz bardziej czasochłonny

Dla każdego fragmentu należy obliczyć: Światło odbite (diffuse)

Światło rozproszone (specular)

Cienie, na bazie map cieni

PCF cieni

Mapowanie normalnych

Mapowanie paralaksy

Mapowanie środowiskowe

itp. 289

Cel opóźnienia cieniowania, c.d.

Te wszystkie obliczenia wykonuje się także dla fragmentów, które potem są zasłaniane przez inne fragmenty, a więc de facto te obliczenia są całkiem zbędne

Problem pogłębia się wraz ze złożonością sceny oraz komplikacją shaderów obliczających cieniowanie 290

Wizualizacja 60 000 sfer

291

Rozwiązanie

Stąd pomysł, aby cieniowanie wykonać dopiero wtedy, kiedy będzie dokładnie wiadomo, które fragmenty są widoczne

Wykonywany jest zatem najpierw szybki przebieg renderingu, który: Zapamiętuje wszystkie potrzebne do cieniowania dane (np. pozycje, normalne,

kolory tekstur)

Stara się jak najmniej obliczać…

A następnie wykonywany jest przebieg cieniujący, który korzysta z przygotowanych danych, i który oblicza cieniowanie tylko dla widocznych fragmentów

292

G-buffer

Framebuffer, do którego w pierwszym przebiegu wykonywany jest rendering nosi nazwę „g-buffer”

„g” od geometry, gdyż zawiera także dane związane z geometrią fragmentów, takie jak położenie i normalne

G-buffer z przykładu, który zaraz nastąpi, zawiera dla każdego fragmentu: Pozycję

Informację, że fragment istnieje w danym miejscu ekranu

Wektor normalny

Kolor

Natężenie światła rozproszonego (ambient) 293

Tekstury g-bufora Pozycje i istnienie:

glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA16F, width(), height(), 0, GL_RGBA, GL_FLOAT, NULL);

Normale:

glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB16F, width(), height(), 0, GL_RGB, GL_FLOAT, NULL);

Kolor i ambient (tu: LDR):

glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width(), height(), 0, GL_RGBA, GL_FLOAT, NULL);

Bufor głębokości:

glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT, width(), height(), 0, GL_DEPTH_COMPONENT, GL_FLOAT, NULL); 294

Fragment shader do generacji g-bufora in vec3 fragNormal;

in vec3 fragPos;

in vec2 fragTexCoor;

uniform sampler2D textureBitmap;

uniform float ambient;

layout (location = 0) out vec4 gPosition;

layout (location = 1) out vec3 gNormal;

layout (location = 2) out vec4 gColor;

void main() {

gPosition = vec4(fragPos, 0.0); // pozycja + istnienie

gNormal = normalize(fragNormal); // normalna

gColor = vec4(texture(textureBitmap, fragTexCoor).rgb, ambient); // kolor + ambient

}

295

Przykład OpenGL37

296

Przetwarzanie w OpenGL37

297

Zawartość g-bufora w OpenGL37

298

Cienie + PCF + HDR + Gauss + mapowanie normalnych + Opóźnione cieniowanie + SkyBox +… ?

Nie tylko, że się da - tak działa większość silników 3D!

299

Przykład OpenGL38

300

Przetwarzanie w OpenGL38

301

Wady opóźnionego cieniowania

Dwie podstawowe wady opóźnionego cieniowania: Wszystkie obiekty muszą być przetwarzane w taki sam sposób

Nie można bezpośrednio korzystać z kanału alfa

Istnieją obejścia w/w problemów Warunkowe/wieloprzebiegowe cieniowanie

Łączenie opóźnionego cieniowania z normalnym (trzeba tylko zachować i wykorzystać bufor głębokości z etapu tworzenia g-bufora)

Pojawiają się za to nowe możliwości…

302

SSAO

303

Screen-Space Ambient Occlusion

SSAO wymyślone przez Crytek dla gry Crysis

304

"Screen space ambient occlusion" by Vlad3D at en.wikipedia - Transferred from en.wikipedia. Licensed under Public Domain via Commons - https://commons.wikimedia.org/wiki/File:Screen_space_ambient_occlusion.jpg#/media/File:Screen_space_ambient_occlusion.jpg

Vladimir Kajalin, 2007

AO (Ambient Occlusion)

Generowanie zacienienia miejsc z mniejszym dostępem światła w dobrze oświetlonym otoczeniu

Sprawdzenie: Ile przestrzeni w otoczeniu każdego

punktu jest wolne od obiektów?

305

AO, c.d.

Wykonanie takiego testu w przestrzeni sceny byłoby dość skomplikowane:

Obiekty są definiowane jako powierzchnie, a nie objętości

Trudno określić, dla których miejsc i jak gęsto dokonywać sprawdzania

306

SSAO

Stąd powstał prawdopodobnie pomysł, aby detekcji zacienienia dokonywać w przestrzeni ekranu, czyli już po etapie wygenerowania g-bufora

Po dołączeniu do g-bufora tekstury z głębokością zawiera on przybliżone dane 3D sceny

Detekcja odbywa się dla każdego fragmentu: współrzędne x i y to współrzędne fragmentu we framebuferze, z jest pobierane z g-bufora

307

Bufor głębokości w g-buforze

Po przekształceniu perspektywicznym głębokość (współrzędna Z) nie jest liniowa

To bardzo utrudniałoby próbkowanie w shaderze SSAO

Dlatego zamiast wykorzystać automatycznie tworzony bufor głębokości, należy utworzyć dodatkowy, w którym zapisywane wartości będą liniowe

308

Mapowanie głębokości

Do przejścia z (near, far) na (0, 1): Zamiast:

OpenGL stosuje:

309

SSAO, c.d.

310

Próbkowanie otoczenia

Nie da się przejrzeć całej kuli otaczającej punkt, ale można wygenerować kilkadziesiąt punktów próbkujących

311

Kształt otoczenia

Próbkowanie otoczenia w kuli jest najprostszym rozwiązaniem, jednak ma tę wadę, że nawet całkiem płaska ściana jest wykrywana jako w 50% zacieniona…

Aby tego uniknąć stosuje się półkule, zorientowane zgodnie z normalną do badanej powierzchni

312

Wynik SSAO

313

Usprawnienia SSAO

Punkty próbkowania powinny być wylosowane niejednorodnie – więcej punktów powinno znaleźć się bliżej środka kuli/półkuli

Punkty powinny być dodatkowo randomizowane dla poszczególnych fragmentów

Tekstura uzyskana po SSAO powinna zostać rozmyta

314

Schemat działania

315

Zamiast:

Kontrola zasięgu

Dodatkowe sprawdzenie, które pozwala uniknąć zacieniania pomiędzy fragmentami znacząco się różniącymi głębokością

316

Cechy SSAO

Szybkość działania SSAO nie zależy od: Złożoności sceny

Liczby świateł

Szybkość działania zależy od: Rozdzielczości ekranu (czyli liczby fragmentów)

Liczby próbek na fragment

317

Konfiguracja SSAO

SSAO posiada kilka parametrów konfiguracyjnych, których dobór jest kluczowy dla uzyskania dobrego efektu: Promień półkuli

Liczba próbek w półkuli

Rozkład próbek w półkuli

Stopień rozmycia

318

Przykład OpenGL39

319

Rendering instancyjny

320

Instancing

Rendering wielu jednakowych/podobnych obiektów Jeżeli każdy obiekt będzie

zlecany do renderingu oddzielnie przez CPU, to czas będzie tracony na: Przesył danych do GPU i wywołanie

funkcji OpenGL

Przygotowanie danych dla shaderów w GPU

321

Rendering instancyjny

Problem dostrzeżono już dawno i od OpenGL 3.1 jest możliwość zlecenia renderingu wielu kopii tego samego obiektu (a właściwie zawartości VBO)

322

Rendering instancyjny, c.d.

Wywołanie renderingu instacyjnego: glDrawArraysInstanced(mode, first, count, instances_count);

glDrawElementsInstanced(mode, count, type, void *indices, instances_count);

Zamiast pojedynczego: glDrawArrays(mode, first, count);

glDrawElements(mode, count, type, void *indices);

Dodatkowy argument instances_count mówi, ile razy rendering ma być wykonany

323

Rozróżnianie instancji

Jeżeli w shaderach nie rozróżnimy instancji, to wizualnie nic nie uzyskamy…

Najprostszym sposobem jest wykorzystanie zmiennej gl_InstanceID dostępnej w vertex shaderze

gl_InstanceID Przyjmuje wartości 0..instances_count-1

Jeżeli nie wykorzystujemy renderingu instancyjnego, to zmienna ta ma zawsze wartość 0

324

Przykład OpenGL40

325

Rozróżnianie instancji, c.d.

Użycie gl_InstanceID czasami jest jednak niewygodne

Bardziej uniwersalna metoda polega na: Przygotowaniu VBO z danymi dla poszczególnych instancji

Podłączeniu tych danych jako wejściowych dla vertex shadera

326

VBO z parametrami instancji

Przygotowanie i przesłanie do GPU identyczne, jak dla VBO z parametrami wierzchołków, np.:

struct InstanceData { GLfloat x, y, z, r, g, b; };

InstanceData positions_and_colors[1000];

GLuint VBO_positions;

glGenBuffers(1, &VBO_positions);

glBindBuffer(GL_ARRAY_BUFFER, VBO_positions);

glBufferData(GL_ARRAY_BUFFER, sizeof(InstanceData)*1000, positions_and_colors, GL_STATIC_DRAW);

glBindBuffer(GL_ARRAY_BUFFER, 0); 327

VBO z parametrami instancji, c.d.

Podczepienie VBO pod VAO: glBindVertexArray(VAO);

attr = glGetAttribLocation(shaderProgram, "instancePosition");

glBindBuffer(GL_ARRAY_BUFFER, VBO_positions);

glVertexAttribPointer(attr, 3, GL_FLOAT, GL_FALSE, sizeof(InstanceData), 0);

glVertexAttribDivisor(attr, 1);

glEnableVertexAttribArray(attr);

328

VBO z danymi wierzchołków i VBO z danymi instancji

W pseudokodzie, poszczególne inwokacje vertex shadera będą otrzymywać następujące dane:

for (int i = 0; i < inst_count; i++)

for (int k = 0; k < vert_count; k++)

vertex_shader(uniformy, VBO_vertex[k], VBO_instance[i]);

329

Przykład OpenGL41

330

Tesselation shaders

331

Tesselacja

Wygenerowanie prymitywów (potencjalnie ich dużej ilości) na podstawie punktów kontrolnych (potencjalnie małej ilości)

LOD (Level of Detail), czyli uzależnienie szczegółowości modelu od jego wielkości na ekranie

332

Trzy etapy tesselacji

333

Dostępne od OpenGL 4.0

Opcjonalna tesselacja następuje po vertex shaderze

Tesselation control shader (TCS)

Vertex shader generuje zestawy wierzchołków

Zestaw nosi nazwę patch, a wierzchołki, które się na niego składają to tzw. punkty kontrolne (control points, CP)

Każdy patch ma zawsze tę samą liczbę punktów kontrolnych, maksymalnie 32, choć dana implementacja OpenGL może podnieść ten limit, sprawdzić to można poprzez: glGetIntegerv(GL_MAX_PATCH_VERTICES, …);

Liczbę punktów kontrolnych ustawia się poleceniem glPatchParameteri(GL_PATCH_VERTICES, …);

334

Tesselation control shader, c.d.

TCS jest wywoływany dla każdego wyjściowego punktu kontrolnego

TCS musi określić stopień (czyli gęstość) tesselacji wypełniając tablice gl_TessLevelOuter[] i gl_TessLevelInner[] Maksymalna wartość określa GL_MAX_TESS_GEN_LEVEL, obecnie na ogół jest to 64

TCS może zmienić punkty kontrolne, dodać im nowe atrybuty itp.

TCS może też wygenerować parametr dla całego patcha, poprzedzając deklarację słowem kluczowym patch, np.: patch out vec3 jakisparametr;

335

Tesselation control shader, c.d.

Dane wejściowe punktów kontrolnych dostępne są w tablicy gl_in[]

Dane wyjściowe zapisuje się w tablicy gl_out[]

Numer aktualnie przetwarzanego wyjściowego punktu kontrolnego określa zmienna wbudowana gl_InvocationID

Każdy dodatkowy atrybut punktu kontrolnego na wejściu i na wyjściu jest tablicą

Liczba punktów na wyjściu z TCS określa deklaracja, np.: layout (vertices = 3) out;

336

Tesselation engine

Kiedy patch zostanie obrobiony przez TCS (co oznacza, że tablice kontrolne tesselacji też zostały wypełnione) do pracy przystępuje tesselation engine, który generuje współrzędne punktów tesselacji

Dla każdego wygenerowanego punktu tesselacji uruchamiany jest tesselation evaluation shader (TES), który ma dostęp do wszystkiego, co ustawił TCS oraz dodatkowo do współrzędnych wygenerowanego wierzchołka poprzez zmienną wbudowaną gl_TessCoord 337

Tesselation evaluation shader (TES)

Zadaniem TES jest wygenerowanie wierzchołków dla docelowych prymitywów (trójkątów, linii lub punktów)

TES określa sposób (tryb) przeprowadzenia tesselacji: layout (triangles) in;

layout (quads) in;

layout (isolines) in;

Dostęp do punktów kontrolnych uzyskiwany jest przez tablicę gl_in[], dostęp do ich atrybutów poprzez zdefiniowane tablice, dostęp do wygenerowanego punku tesselacji poprzez gl_TessCoord

338

Tryby tesselacji

Dostępne są trzy tryby tesselacji: Trójkąty

Kwadraty

Izolinie

339

Tryb tesselacji: trójkąt

Występuje, gdy kompilator znajdzie w TES deklarację: layout (triangles) in;

W trójkącie generowane są punkty wg schematu

340

gl_TessLevelOuter

Podział każdej krawędzi jest definiowany osobno, aby możliwe było dokładne dopasowanie sąsiadujących patchy

341

Tryb tesselacji: trójkąt, c.d.

Współrzędne są w tzw. systemie barycentrycznym https://pl.wikipedia.org/wiki/Współrzędne_barycentryczne_(matematyka)

Układ punktów zależny jest tylko od gl_TessLevel*[], nie zależy w szczególności od punktów kontrolnych

342

Przykład OpenGL42

343

Tryb tesselacji: kwadrat

Występuje, gdy kompilator znajdzie w TES deklarację: layout (quads) in;

W kwadracie generowane są punkty wg schematu

344

Tryb tesselacji: kwadrat, c.d.

Współrzędne są w układzie kartezjańskim

Układ punktów zależny jest tylko od gl_TessLevel*[], nie zależy w szczególności od punktów kontrolnych

345

Przykład OpenGL43

346

Tryb tesselacji: izolinie

Występuje, gdy kompilator znajdzie w TES deklarację: layout (isolines) in;

W kwadracie generowane są punkty wg schematu

347

Dodatkowe modyfikatory

W deklaracji TES: layout (mode, …) in możliwe jest podanie dodatkowych modyfikatorów:

Dotyczących rozkładu: equal_spacing, fractional_even_spacing, fractional_odd_spacing

Generującego punkty: point_mode

Dotyczących „skrętności” trójkątów wynikowych: cw, ccw 348

Krzywe Bézier

Pierre Étienne Bézier 1960(?) (Sergei Natanovich Bernstein 1912, algorytm Paula de Casteljau 1959)

https://en.wikipedia.org/wiki/Bézier_curve

349

Płaty Bézier

350

"Bicubic Patches" by Philip Rideout - Own work. Licensed under CC BY-SA 3.0 via Commons - https://commons.wikimedia.org/wiki/File:Bicubic_Patches.png#/media/File:Bicubic_Patches.png

Ed Catmull – model słonia Gumbo

Składa się z płatów Bézier

Każdy płat kontrolowany jest przez 16 punktów (w tym przykładzie)

Przykład OpenGL44

351

Przykład OpenGL45

353

Mgła

354

Mgła

Efekt mgły pozwala na bardziej realistyczne odwzorowanie otwartych przestrzeni dodając im dodatkowej głębi

355 http://www.iquilezles.org/www/articles/fog/fog.htm

Mgła, c.d.

Mgła pozwala także na uniknięcie problemu skończoności modelu terenu – przy odpowiednio dodanych parametrach mgły „końca świata” nie będzie widać

Efekt mgły można oczywiście także stosować we wnętrzach

356

Mgła w funkcji odległości

W OpenGL 1.0 można było uzyskać efekt mgły wykorzystując jeden z trzech predefiniowanych modeli Liniowy:

Wykładniczy:

Wykładniczy, wersja 2:

357

Mgła w funkcji odległości, c.d.

Gdzie: f – współczynnik „mglistości”

z – odległość fragmentu od kamery

d – gęstość mgły

start, end – zasięg mgły w modelu liniowym

Obecnie w shaderach można zaprogramować dowolną funkcję mgły – należy dobrać taką, która najlepiej odpowiada wymaganiom

358

Mgła w shaderach

Należy ustalić kolor mgły, a następnie na ten właśnie kolor ustawić kolor tła

Vertex shader (lub tesselation evaluation shader): float z = length(gl_Position - eyePos);

fogFactor = clamp(exp(-fogDensity*fogDensity * z*z), 0.0, 1.0);

Fragment shader: color = mix(vec4(fogColor, 1.0), color, fogFactor);

359

Mgła w funkcji wysokości

Efekt zalegania mgły „w dolinach”

Natężenie mgły zależne od wysokości terenu h:

Jest to wzór przybliżony, ale daje dobre rezultaty wizualne…

360

Mgła w funkcji wysokości, c.d.

Można też policzyć dokładniej:

361

Przykład OpenGL46

362

Głębia ostrości

363

Depth of Field

Głębia ostrości

Jest to kolejny efekt mający na celu podniesienie realizmu renderowanej sceny

Wynika z braku możliwości takiego ustawienia układu optycznego (kamery, aparatu fotograficznego, źrenicy oka), aby obiekty o różnym oddaleniu od obiektywu były ostre na elemencie światłoczułym (kliszy, detektorze, siatkówce)

364

Krążek rozmycia (Circle of Confusion)

365

CoC zależy od średnicy soczewki (proporcjonalnie)

CoC jest ograniczone dla obiektów „w nieskończoności”

CoC nie jest ograniczone dla obiektów bliskich soczewce Obiekty bliskie są bardziej rozmyte niż odległe

Krążek rozmycia, c.d.

Wzór określający CoC:

f – ogniskowa

d – średnica apertury

https://en.wikipedia.org/wiki/Circle_of_confusion

366

Krążek rozmycia w praktyce

367

Głębia ostrości – czy zawsze warto stosować?

Jeżeli chcemy, aby nasza scena przypominała zdjęcie lub film, to można to rozważyć

Jeżeli scena ma przypominać świat rzeczywisty, jakim widzimy go dookoła (zakładając dobry wzrok lub poprawne szkła korygujące), to już niekoniecznie… Bo nasze oczy automatycznie dostosowują się do różnej odległości poprzez

akomodację, tak aby to na co patrzymy, było maksymalnie ostre

Jeśli jakiś fragment obrazu rozmyjemy, to żadne wytężanie wzroku już nie pomoże…

368

Porównajmy…

369 http://www.trusim.com/

Metody

Istnieje kilka metod na uzyskanie efektu głębi ostrości, różnią się uzyskaną dokładnością oraz złożonością Wykorzystanie akumulacji

Ray tracing dla obszaru soczewki

Wykorzystanie bufora głębokości

Metody oparte o bufor głębokości są najszybsze, tym bardziej, że bufor głębokości i tak często jest generowany jako element g-bufora

370

Metody oparte o bufor głębokości

Sposób 1 – bardziej poprawny Należy przeprowadzić rozmycie zależne od różnicy odległości fragmentu i

odległości o prawidłowej ostrości

Tu ponownie jest kilka metod do wyboru

Sposób 2 – mniej poprawny Wykonujemy rozmytą kopię całej sceny

W trakcie końcowego renderingu mieszamy obraz rozmyty i ostry w stosunku zależnym od różnicy między odległością fragmentu i odległości o prawidłowej ostrości

371

Przykład OpenGL47

372

Obiekty przejrzyste

373

Kanał alfa

Model kolorów w OpenGL to RGBA

Kanał alfa dodany w 1971-72 (Edwin „Ed” Catmull & Alvy Ray Smith)

Nazwa od greckiej litery α w równaniu interpolacji liniowej:

374

Kanał alfa, c.d.

Zgodnie z konwencją A określa stopień nieprzejrzystości (1.0 - całkowite zasłanianie, 0.0 całkowita transparentność)

Domyślnie A jest ignorowane – jeśli chcemy korzystać z przejrzystości należy włączyć jej obsługę i określić tryb mieszania kolorów (blending)

Albo wykorzystać wartość A we fragment shaderze do odrzucania fragmentu

375

Test alfa

Ta druga możliwość nosi nazwę testu alfa (alpha test) i polega na tym, że we fragment shaderze, po ustaleniu koloru fragmentu wykonujemy operację: if (color.a < jakiś_próg)

discard;

Ponieważ odrzucanie jest zerojedynkowe, aby wynikowy obraz nie był postrzępiony, konieczne jest użycie antyaliasingu

376

Testowe drzewo

377

model

tekstura

Przykład OpenGL48

378

Włączenie mieszania (blending)

Mieszanie pozwala określić jaka wartość RGBA ma zostać umieszczona w framebuforze, po obliczeniu nowych wartości przez fragment shader

Aby włączyć funkcję mieszania należy wywołać funkcję: glEnable(GL_BLEND);

W przeciwnym wypadku do framebufora zostanie zawsze skopiowana nowa wartość RGBA policzona we fragment shaderze

379

Określenie mieszania

Funkcje określające sposób mieszania wartości już istniejącej w framebuforze oraz wartości obliczonej przez fragment shader: glBlendFunc(GLenum src, GLenum dst)

glBlendFuncSeparate(GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha)

Druga wersja umożliwia ustawienie innego mieszania dla komponentu A, a innego dla RGB

Możliwe stałe src i dst przedstawia tabelka na następnym slajdzie src oznacza wartość z fragment shadera

dst oznacza wartość z framebufora

380

381

Funkcja mieszania

Po określeniu, jak ma zostać przetworzone src i dst, ostateczny wynik może zostać: Dodany: p(src) + p(dst) operacja domyślna

Odjęty: p(src) – p(dst)

Odjęty, ale odwrotnie: p(dst) – p(src)

Ustalony jako minimum: min(p(src), p(dst))

Ustalony jako maximum: max(p(src), p(dst))

Określa się to funkcją glBlendEquation(), lub glBlendEquationSeparate() z parametrem: GL_FUNC_ADD, GL_FUNC_SUBTRACT, GL_FUNC_REVERSE_SUBTRACT, GL_MIN albo GL_MAX

Przykład mieszania

Najbardziej popularne ustawienie to: glEnable(GL_BLEND);

• Włącza mieszanie

glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

glBlendEquation(GL_FUNC_ADD); • Ostateczny kolor umieszczony we framebufferze to:

• Czyli stopień wymieszania z „tłem” określa Asrc ustalone przez fragment shader

383

Mieszanie we fragment shaderze

Mieszanie we fragment shaderze jest dostępne na razie jedynie jako rozszerzenie na OpenGL ES: EXT_shader_framebuffer_fetch https://www.khronos.org/registry/gles/extensions/EXT/EXT_shader_framebuffer_fetch.txt

Rozszerzenie udostępnia zmienną gl_LastFragData z aktualną zawartość framebufera

384

Rendering obiektów przejrzystych

Umieszczenie w scenie obiektów przejrzystych wymaga następujących kroków:

Włączenie odpowiedniego mieszania kolorów

Wyrenderowanie całej sceny z pominięciem obiektów prześwitujących

Wyłączenie uaktualniania bufora głębokości glDepthMask(GL_FALSE);

Wyrenderowanie obiektów przejrzystych w kolejności od najdalszych do najbliższych

385

Sortowanie względem głębokości

Jest zadaniem nie zawsze jednoznacznym…

386

Przykład OpenGL49

387

A może można prościej?…

Prościej, czyli bez oddzielania nieprzejrzystych obiektów od przejrzystych i bez sortowania tych drugich…

Można:

glEnable(GL_SAMPLE_ALPHA_TO_COVERAGE);

388

Alpha to coverage

Realizowany przez kartę algorytm alfa test, ale na poziomie antyaliasingu

Liczba odrzuconych fragmentów zależy od wartości alfa

Wadą jest to, że zaczyna ładnie wyglądać dopiero od 32 próbek na fragment

389

Alpha to coverage dla różnej liczby próbek

390

Przykład OpenGL50

391

Billboardy

Płaszczyzny (na ogół prostokąty), które, niezależnie od położenia kamery, są zawsze zwrócone do niej na wprost

392

Zastosowanie billboardów

Wizualizacja systemów cząsteczkowych Chmury

Ogień

Dym

Gwiazdy

itp.

W pewnych okolicznościach także np. drzewa, kempki trawy itp.

Paski życia (health bar) 393

„Eternal lands1” autorstwa Eternal Lands developers; screenshot taken by Sir Lothar - Eternal Lands. Licencja CC BY 3.0 na podstawie Wikimedia Commons - https://commons.wikimedia.org/wiki/File:Eternal_lands1.jpg#/media/File:Eternal_lands1.jpg

Generowanie billboardów

Jedną z metod jest generowanie billboardu w geometry shaderze Geometry shader na wejściu dostaje położenie punktu centralnego

i rozmiar billboardu

Geometry shader generuje 2 trójkąty stanowiące prostokąt

Geometry shader generuje także współrzędne tekstury

Właściwy rendering wykonuje fragment shader nakładając odpowiednią teksturę

394

Przykład OpenGL51

395

Chmury

396 https://tel.archives-ouvertes.fr/tel-00319974/file/defense.pdf

Chmury, dym, ogień, gwiazdy itp.

Na drodze symulacji (która również może być realizowana na GPU!) generujemy punkty (cząstki), których ruch i położenie imituje te zjawiska

Wizualizacja chmury cząstek najczęściej jest wówczas realizowana przy pomocy billboardów z teksturą o dużej przejrzystości (małym alfa)

397

Przykład OpenGL52

398

Przykład OpenGL53

399

Obrazowanie objętościowe

400

Volume rendering

Medycyna

Obrazowanie wolumetryczne wykorzystywane jest głównie w medycynie (ale też np. w archeologii)

Tomografia komputerowa (CT) Pierwszy tomograf powstał w 1968 roku

(nobel w 1979)

Pierwszy pacjent zbadany w 1972

Rezonans magnetyczny (MRI) Wymyślony w 1971 roku (nobel w 2003)

Pierwszy przydatny skan w 1980

Pozytonowa tomografia emisyjna (PET) – dodatkowo z CT lub MRI 401

Seria zdjęć

Wynikiem działania CT czy rezonansu jest seria obrazów o tej samej rozdzielczości przedstawiającej przekroje fragmentu ciała pacjenta (głowy, tułowia, stawu kolanowego itp.) w jednakowych odstępach

402

Seria zdjęć, c.d.

Sama seria zdjęć przynosi już lekarzowi bardzo dużo informacji

Chcemy jednak uzyskać także możliwość wizualizacji 3D oraz uzyskania dowolnego przekroju badanej części ciała

403

Główne problemy

Badanie MRI trwa kilka-kilkanaście minut – nie zawsze jest możliwe całkowite unieruchomienie pacjenta

Zbyt niska rozdzielczość obrazów lub zbyt duży odstęp między przekrojami

Nieostre obrazy

Szumy i inne zakłócenia

Różnice pomiędzy obrazami w poszczególnych warstwach

Mnogość formatów danych

404

Wyzwanie

Jednoczesna wizualizacja danych z wielu źródeł…

405

DICOM

Digital Imaging and Communications in Medicine

Format przechowywania obrazów medycznych Wiele dodatkowych danych dotyczących pacjenta, metody pomiaru itp.

Opracowana dla ujednolicenia wymiany danych

Główna wada: format jest zbyt obszerny, wielość możliwości powoduje, że w różnych programach lub placówkach medycznych są one wypełniane w różny sposób

Osobnym problemem jest brak mechanizmów szyfrowania/uwierzytelniania

406

Trywialna rekonstrukcja 3D

Polega na wyrenderowaniu odpowiedniej liczby prostokątów z naniesionymi teksturami

Pojawi się problem z obserwacją dla niewielkich kątów patrzenia

Pojawi się problem z kolejnością rysowania prostokątów

Dobór kanału alpha, progu odcięcia

Stosuje się na ogół rzutowanie równoległe zamiast perspektywicznego

Uwaga na problem lustrzanego odbicia! Ciało ludzkie jest prawie symetryczne, więc łatwo o pomyłkę

407

Przykład OpenGL54

408

Kolejność renderingu warstw

Kolejność renderingu warstw ma znaczenie

Należy wyświetlać je w kolejności od najdalszej do najbliższej (w stosunku do obserwatora)

409

Przykład OpenGL55

410

Tekstury 3D

W OpenGL mamy do dyspozycji także tekstury trójwymiarowe

Ich obsługa (alokowanie, wczytywanie, dostęp w shaderach) jest identyczny jak w przypadku tekstur 2D, dodana jest jedynie trzecia współrzędna określająca odpowiednio rozmiar tekstury lub położenie punktu w teksturze

411

Tekstury 3D, c.d.

Jedno z podejść polega na tym, że w czasie renderingu przekształcane są współrzędne tekstury 3D a nie obiektu

Często voxele (trójwymiarowe odpowiedniki pixeli) nie są sześcianami – OpenGL nie uwzględnia takiej możliwości (podobnie jak niekwadratowych pixeli) bezpośrednio, trzeba to uwzględnić w odpowiednim skalowaniu macierzy, np.: v_matrix.scale(1.0, width*spacing_x/(height*spacing_y),

width*spacing_x/(depth*spacing_z)); 412

Przykład OpenGL56

413

Inne metody

Splatting Rzutowanie vexeli jako billboardy

Shear warp Odpowiednie przeskalowanie i przesunięcie źródłowych tekstur

https://graphics.stanford.edu/papers/shear/shearwarp.pdf

414

Odtwarzanie geometrii

Innym sposobem wizualizacji jest próba rekonstrukcji geometrii na podstawie danych wolumetrycznych

Wymaga określenia progu, który umożliwi detekcję izopowierzchni – jest najłatwiejsze w przypadku kości, czy zastosowania kontrastu

415

Algorytm marching cubes

Wymyślony w 1987 (Williama E. Lorensen, Harvey E. Cline)

Algorytm opatentowany w USA w 1987, jednak już wygasł…

Podział przestrzeni na sześciany

416 "Marchingcubes-head". Licensed under CC BY-SA 2.5 via Commons - https://commons.wikimedia.org/wiki/File:Marchingcubes-head.png#/media/File:Marchingcubes-head.png

Marching cubes

W każdym z wierzchołków sześcianu sprawdzane jest, czy wartość pola skalarnego jest większa, czy mniejsza od progu

Jest zatem 256 możliwości (28), jednak ze względu na różne symetrie autorzy wyodrębnili jedynie 15 przypadków kanonicznych

417

„MarchingCubes” autorstwa Jmtrivial (talk). Licencja GPL na podstawie Wikimedia Commons - https://commons.wikimedia.org/wiki/File:MarchingCubes.svg#/media/File:MarchingCubes.svg

Teksturowanie proceduralne

418

Tekstury statyczne

Tradycyjne tekstury

Zaleta: dzięki sprzętowej realizacji i optymalizacji są bardzo szybkie

Wady: • Zajmują pamięć GPU

• Są statyczne

• Sprawiają kłopot przy projektowaniu obiektów o skomplikowanym kształcie

419

420

Tekstury proceduralne

Innym pomysłem na określenie koloru fragmentu jest jego algorytmiczne obliczenie, tak aby obiekt przypominał wykonanie z jakiegoś naturalnego materiału (klasyczne przykłady to drewno i marmur)

Tekstury proceduralne mogą być 2D lub 3D (a nawet 4D)

Wadą jest brak pełnej kontroli grafików nad powstającą teksturą (w odróżnieniu od tekstur klasycznych, którym zawsze można coś dorysować)

421

Tekstury proceduralne

Tekstury proceduralne mogą być obliczane: Off-line, czyli np. przed renderingiem sceny czy animacji i następnie

załadowane jako tradycyjne tekstury statyczne do GPU – to rozwiązanie dotyczy głównie tekstur 2D

On-line, czyli na bieżąco w shaderze w czasie redneringu – obliczenia powinny być zatem maksymalnie uproszczone i zoptymalizowane

Podobnie, jak tekstury tradycyjne, mogą być wykorzystywane także do zaburzania normalnych, przesunięcia paralaksy, generowania wysokości terenu itp. 422

Tekstury proceduralne 3D

Wartość tekstury obliczana jest w funkcji trójwymiarowej pozycji

mapowanie do współrzędnych tekstury UV nie jest potrzebne

Uzyskujemy efekt wycięcia obiektu z materiału

423

Tekstury proceduralne 3D, c.d

Często stosowany schemat:

gdzie: c – kolor wynikowy

p – funkcja periodyczna

n – wykładnik funkcji periodycznej (zmienia szerokości warstw)

f – funkcja pozycji (może być także zależna od czasu t)

s – funkcja szumu

424

Przykład 1 - drewno

Funkcje:

p – funkcja piłokształtna

425

Przykład 2 - marmur

426

Funkcje:

p – funkcja sin

Przykład OpenGL57

427

Świat nie jest idealny

Drewniane klocki z ostatniego przykładu wyglądają jakby: Wyciął je stolarz perfekcjonista (idealnie centralnie i symetrycznie)

Zostały wycięte z idealnego drzewa (słoje regularne i koncentryczne, o stałej grubości)

Marmurowe klocki wyglądają jeszcze gorzej…

428

Wprowadzenie zniekształceń

Można wprowadzić macierz przekształcenia tekstury, która poprzez translację i rotację, wyeliminuje problem idealnego rzemieślnika (stolarza, kamieniarza)

Do wprowadzenia zakłóceń w strukturze należy użyć funkcji szumu s

429

Funkcje szumu

Funkcje szumu służą do wprowadzenia kontrolowanej losowości do modelu tekstury

Szum musi być powtarzalny

Najczęściej jest realizowany poprzez pseudolosową funkcję s, której parametr (1,2,3…n wymiarowy) jest przekształcany na liczbę z zakresu [-1, 1] lub [0, 1]

Dla tego samego parametru funkcja musi zwrócić tę samą wartość

430

Funkcje szumu, c.d.

Funkcja szumu powinna mieć następujące własności: Średnia wartość szumu powinna być w połowie przedziału

Charakter statystyczny nie powinien zależeć od translacji i rotacji (powinien być izotropowy)

W GLSL dostępne są funkcje noiseN(…), jednak na większości kart nie działają Kompilacja shadera uda się, program się uruchomi, ale noise() zwraca stałą

wartość…

431

Kenneth H. "Ken" Perlin

1981 – praca przy filmie TRON

1983 – pierwszy generator szumu

1984 – pierwszy shader (język+interpreter)

1986-88 – Pixar, Alias, Softimage, Renderman, Dynamation, 3D Studio Max, …

• Filmy Jamesa Camerona (Abyss,Titanic,...), filmy animowane (Lion King, Moses,...), filmy ze Schwarzeneggerem (T2, True Lies, ...), filmy Star Wars, filmy Star Trek, filmy z Batmanem, …

1989 – hypertekstury

432

http://mrl.nyu.edu/~perlin/

To Ken Perlin for the development of Perlin Noise, a technique used to produce natural appearing textures on computer generated surfaces for motion picture visual effects.

The development of Perlin Noise has allowed computer graphics artists to better represent the complexity of natural phenomena in visual effects for the motion picture industry.

433

Nagroda Akademii „Technical Achievement Award” – 1997

Szum Perlina

Algorytm w skrócie: Funkcja Rn [-1, 1] (najczęściej n = 1…4)

W przestrzeni Rn mamy regularną siatkę z wygenerowanymi pseudolosowo wartościami gradientu (osobny algorytm)

Dla każdego punktu odnajdujemy jego 2n najbliższych węzłów

Dla każdego węzła obliczamy wektor do niego i mnożymy iloczynem skalarnym z wartością gradientu w węźle

Otrzymane wartości interpolujemy jakąś gładką funkcją np. 3x2 – 2x3

(potrzebne jest 2n - 1 interpolacji) 434

Szum Perlina, c.d. Użycie czasu jako dodatkowego wymiaru pozwala na uzyskanie

animacji (szum 3D i 4D):

435

http://www.noisemachine.com/talk1/

Szum Simplex

Inny sposób generacji szumu (Ken Perlin 2001) Mniejsza ilość obliczeń

Mniejsza złożoność obliczeniowa O(n2) zamiast O(2n) (n – wymiarowość)

Lepsza niezależność szumu od kierunku

Łatwiejsza implementacja sprzętowa

Szczegóły: http://webstaff.itn.liu.se/~stegu/simplexnoise/simplexnoise.pdf

436

Szum widmowy (fraktalny)

Prosta funkcja szumu nie daje czasem oczekiwanych rezultatów ze względu na mały zakres częstotliwości

W celu uzyskania szumu widmowego należy zastosować sumę szumów, za każdym razem zwiększając częstotliwość (2x) i zmniejszając amplitudę (2x)

437

Przykład OpenGL58

438

Użycie funkcji szumu w teksturach

Zaburzając współrzędne tekstury szumem możemy uzyskać bardziej naturalne efekty

Np. dla drewna:

439

Przykład OpenGL59

440

Szum Worley’a

Wprowadzony przez Stevena Worley’a w 1996

Zwany też szumem komórkowym (cell noise)

Bazuje na diagramie Woronoja (Георгий Феодосьевич Вороной)

Algorytm: Pseudolosowe wylosowanie punktów w przestrzeni

Funkcja szumu Fn(x,y,z) zwraca n najbliższych odległości od punktów

Szczegóły: http://www.rhythmiccanvas.com/research/papers/worley.pdf

441

Przykład OpenGL60

442

Zaznaczanie obiektów

443

Wskazywanie obiektów (object picking)

Często zdarza się, że powstaje potrzeba, aby użytkownik mógł wskazać (klikając myszką, dotykając palcem) obiekt lub jego fragment

Istnieje wiele metod na wykrycie, który obiekt został wskazany, wybór metody zależy od takich czynników, jak np.: Szybkość działania

Oczekiwana precyzja

Dostępne dane 444

Wskazywanie obiektów, c.d.

Mając dane współrzędne ekranu (x, y), należy znaleźć obiekt, który w tym miejscu został wyrenderowany

Metody geometryczne Ray-tracing pojedynczego promienia (od kamery przez (x, y)) i znalezienie

najbliższego przecięcia

Odczytanie z z-bufora wartości głębokości z i dokonując przekształceń odwrotnych można z punktu (x, y, z) odtworzyć punkt w przestrzeni modelu a następnie odnaleźć obiekt znajdujący się najbliżej

445

Wskazywanie obiektów, c.d.

Metody oparte o OpenGL Renderowanie obiektów z

zapamiętaniem ich identyfikatorów we framebuforze

• Można napisać oddzielny program na GPU, który wykona tę czynność wtedy kiedy taki odczyt będzie konieczny

• Można także wykonać tę czynność przy okazji generowania g-buffora w metodzie opóźnionego cieniowania

446

Przekazanie id obiektu do shadera

Jeżeli obiekty są renderowane oddzielnie jako uniform

Jeżeli wiele obiektów jest renderowanych z VBO id jako dodatkowe pole (obok położenia, normalnych itp.)

Jeżeli wykorzystujemy instancing można wykorzystać gl_InstanceID

Inne

447

Pobranie id z tekstury

W wersjach OpenGL < 4.5 Musimy pobrać całą teksturę do CPU

glBindTexture(GL_TEXTURE_2D, tex_id);

glGetTexImage(GL_TEXTURE_2D, 0, …, …, ids);

W OpenGL >= 4.5 Można pobrać dowolny prostokąt z tekstury, także taki o wymiarach 1x1:

glGetTextureSubImage(tex_id, 0, x, y, 0, 1, 1, 1, …, …, sizeof(id), &id);

448

Przykład OpenGL61

449

Obwódka obiektu (outline)

Wizualne sygnalizowanie wskazanego obiektu Zmiana koloru

Obwódka

Do zrobienia obwódki można wykorzystać: Bufor z id obiektów

• Obwódkę można dodatkowo rozmyć (np. gaussem), co może dać dodatkowy ładny efekt

Stencil buffer

450

Przykład OpenGL62

451

Stencil buffer

Dodatkowy bufor pozwalający na ciekawe operacje, np. maskowanie

Bufor najczęściej jest 8bitowy (8 bitów na każdy pixel), ale można to sprawdzić: int stencil_bits;

glGetIntegerv(GL_STENCIL_BITS, &stencil_bits);

452

Stencil buffer, c.d.

Stencil buffer wykonuje dwie czynności: testowanie i właściwą operację

Testowanie polega obliczeniu wyrażenia: (ref & mask) FUNC (stencil & mask) Gdzie:

• ref – referencyjna stała całkowita

• mask – stała całkowita umożliwiająca korzystanie z wybranych bitów stencil bufora

• FUNC – operacja logiczno-relacyjna (GL_NEVER, GL_ALWAYS, GL_LESS, GL_LEQUAL, GL_GREATER, GL_GEQUAL, GL_EQUAL, GL_NOTEQUAL

• stencil – zawartość stencil bufora

glStencilFunc(func, ref, mask) 453

Stencil buffer, c.d.

Właściwa akcja definiowana jest dla 3 sytuacji: sfail – stytuacja, kiedy test stencil bufora zwrócił 0

dpfail – sytuacja, kiedy test stencil bufora nie zwrócił 0, ale test głębokości wykazał, że fragment będzie niewidoczny

dppass – sytuacja gdy oba testy przeszły pomyślnie

Uwaga: fragment nie jest obliczany, jeśli stencil test zwrócił 0!

W każdym z w/w przypadków możliwa jest jedna z czynności: GL_KEEP, GL_ZERO, GL_REPLACE, GL_INCR, GL_INCR_WRAP, GL_DECR, GL_DECR_WRAP, GL_INVERT

glStencilOp(sfail, dpfail, dppass) 454

Czynności wykonywane na stencil buforze GL_KEEP - nie zmienia zawartości

GL_ZERO - ustawia na 0

GL_REPLACE - zamienia na wartość ref

GL_INCR - zwiększa zawartość stencil bufora o 1, aż do maksimum

GL_INCR_WRAP - zwiększa zawartość bufora, ale przechodzi na 0 po osiągnięciu maksimum

GL_DECR - zmiejsza wartość stencil bufora aż do 0

GL_DECR_WRAP - zmiejsza wartość stencil bufora, ale przechodzi na maksimum po osiągnięciu 0

GL_INVERT - neguje bity stencil bufora

455

Przykład - obwódka obiektu z wykorzystaniem stencil bufora glClearStencil(0); glClear(GL_STENCIL_BUFFER_BIT);

glEnable(GL_STENCIL_TEST);

glStencilFunc(GL_ALWAYS, 1, 0xFFFF);

glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE);

// tu renderujemy obiekt normalnie efekt: „1” tam gdzie obiekt

glStencilFunc(GL_NOTEQUAL, 1, 0xFFFF);

// tu renderujemy obiekt jako wireframe „grubymi” liniami

glDisable(GL_STENCIL_TEST); 456

457

1

2

Bufor koloru i stencil

Wady i zalety metody

Wady Obrysowywany obiekt wymaga dwukrotnego renderingu

Linie, szczególnie grubsze nie są ładnie rysowane przez OpenGL

Zalety Prostota implementacji

Brak konieczności alokowania i używania własnych buforów

458

Przykład OpenGL63

459

Wykrywanie krawędzi

W celu uzyskania „komiksowego” wyglądu można dokonać detekcji krawędzi w oparciu o: Wektory normalne

Bufor głębokości

Wykrywanie krawędzi – wiele algorytmów: Krzyż Robertsa

Operator Sobela

Operator Sharra

Algorytm Canny’ego

… 460

Krzyż Robertsa

461

Operator Sobela

462

Przykład OpenGL64

463

464