464
Rendering w czasie rzeczywistym dr inż. Rafał Wcisło [email protected]

Rendering czasu rzeczywistego (PDF)

Embed Size (px)

Citation preview

Page 1: Rendering czasu rzeczywistego (PDF)

Rendering w czasie rzeczywistym

dr inż. Rafał Wcisło

[email protected]

Page 2: Rendering czasu rzeczywistego (PDF)

Wstęp

2

Page 3: Rendering czasu rzeczywistego (PDF)

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

Page 4: Rendering czasu rzeczywistego (PDF)

Zastosowania

Gry rozrywka

„Serious games” symulacje

edukacja

terapia

4

Page 5: Rendering czasu rzeczywistego (PDF)

Co się zmienia?

Oczekiwania użytkowników

5

Page 6: Rendering czasu rzeczywistego (PDF)

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

Page 7: Rendering czasu rzeczywistego (PDF)

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

Page 8: Rendering czasu rzeczywistego (PDF)

Combat Zone

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

8

Page 9: Rendering czasu rzeczywistego (PDF)

Doom

1993

9

Page 10: Rendering czasu rzeczywistego (PDF)

Unreal

1998

10

Page 11: Rendering czasu rzeczywistego (PDF)

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

Page 12: Rendering czasu rzeczywistego (PDF)

Wiedźmin III

2015

12

Page 13: Rendering czasu rzeczywistego (PDF)

Co się zmienia?

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

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

2D 3D

13

Page 14: Rendering czasu rzeczywistego (PDF)

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

Page 15: Rendering czasu rzeczywistego (PDF)

Co się zmienia?

Moc obliczeniowa CPU

GPU

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

Przepustowość

15

Page 16: Rendering czasu rzeczywistego (PDF)

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

Page 17: Rendering czasu rzeczywistego (PDF)

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

Page 18: Rendering czasu rzeczywistego (PDF)

Biblioteki graficzne, c.d.

Najczęściej stosowane biblioteki to OpenGL i DirectX

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

18

Page 19: Rendering czasu rzeczywistego (PDF)

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

Page 20: Rendering czasu rzeczywistego (PDF)

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

Page 21: Rendering czasu rzeczywistego (PDF)

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

Page 22: Rendering czasu rzeczywistego (PDF)

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

Page 23: Rendering czasu rzeczywistego (PDF)

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.

Page 24: Rendering czasu rzeczywistego (PDF)

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.

Page 25: Rendering czasu rzeczywistego (PDF)

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.

Page 26: Rendering czasu rzeczywistego (PDF)

Wersje OpenGL

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

26

Page 27: Rendering czasu rzeczywistego (PDF)

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

Page 28: Rendering czasu rzeczywistego (PDF)

Vulkan

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

next generation OpenGL initiative

higher performance and lower CPU usage

prekompilowane shadery

28

Page 30: Rendering czasu rzeczywistego (PDF)

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

Page 31: Rendering czasu rzeczywistego (PDF)

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

Page 32: Rendering czasu rzeczywistego (PDF)

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.

Page 33: Rendering czasu rzeczywistego (PDF)

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.

Page 34: Rendering czasu rzeczywistego (PDF)

OpenGL 3.0 rendering pipeline

34

Page 35: Rendering czasu rzeczywistego (PDF)

OpenGL 4.3 rendering pipeline

35

Page 36: Rendering czasu rzeczywistego (PDF)

OpenGL 4.5 rendering pipeline

36

Page 37: Rendering czasu rzeczywistego (PDF)

Skrócona wersja obrazkowa

37

Page 38: Rendering czasu rzeczywistego (PDF)

Pojedyncze podawanie wierzchołków

glBegin(GL_TRIANGLES);

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

DEPRECATED 38

Stare style programowania OpenGL

Page 39: Rendering czasu rzeczywistego (PDF)

Stare style programowania OpenGL, c.d.

Bufory z wierzchołkami

DEPRECATED

39

Page 40: Rendering czasu rzeczywistego (PDF)

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

Page 41: Rendering czasu rzeczywistego (PDF)

A zatem jak?

Shaders

Vertex shader

Tesselation shaders (2x)

Geometry shadrer

Fragment shader

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

41

Page 42: Rendering czasu rzeczywistego (PDF)

Literatura

42

Page 43: Rendering czasu rzeczywistego (PDF)

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

Page 44: Rendering czasu rzeczywistego (PDF)

44

Książki

Page 45: Rendering czasu rzeczywistego (PDF)

45

Książki, c.d.

Page 46: Rendering czasu rzeczywistego (PDF)

Zaczynamy

46

Page 47: Rendering czasu rzeczywistego (PDF)

Wersje OpenGL i GLSL

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

47

Page 48: Rendering czasu rzeczywistego (PDF)

Sprawdzenie wersji

glGetString(...) GL_RENDERER

karta graficzna

GL_VERSION wersja OpenGL

GL_SHADING_LANGUAGE_VERSION wersja GLSL

GL_EXTENSIONS obsługiwane rozszerzenia

48

Page 49: Rendering czasu rzeczywistego (PDF)

Przykład OpenGL01

49

Page 50: Rendering czasu rzeczywistego (PDF)

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

Page 51: Rendering czasu rzeczywistego (PDF)

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

Page 52: Rendering czasu rzeczywistego (PDF)

Przykład OpenGL02

52

Page 53: Rendering czasu rzeczywistego (PDF)

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

Page 54: Rendering czasu rzeczywistego (PDF)

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

Page 55: Rendering czasu rzeczywistego (PDF)

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

Page 56: Rendering czasu rzeczywistego (PDF)

Typy zmiennych, c.d.

Struktury struct {

} nazwa;

Tablice typ nazwa[rozmiar]

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

56

Page 57: Rendering czasu rzeczywistego (PDF)

Przesyłanie danych

57

Page 58: Rendering czasu rzeczywistego (PDF)

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

Page 59: Rendering czasu rzeczywistego (PDF)

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

Page 60: Rendering czasu rzeczywistego (PDF)

Aktualizacja fragmentu lub całości VBO

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

60

Page 61: Rendering czasu rzeczywistego (PDF)

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

Page 62: Rendering czasu rzeczywistego (PDF)

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

Page 63: Rendering czasu rzeczywistego (PDF)

VAO

63

Page 64: Rendering czasu rzeczywistego (PDF)

Uruchomienie rysowania VAO (=VBO+attr)

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

glBindVertexArray(VAO);

glDrawArrays(GL_TRIANGLES, offset, count);

64

Page 65: Rendering czasu rzeczywistego (PDF)

Przykład OpenGL03

65

Page 66: Rendering czasu rzeczywistego (PDF)

Element Buffer Object (EBO)

66

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

Page 67: Rendering czasu rzeczywistego (PDF)

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

67

Page 68: Rendering czasu rzeczywistego (PDF)

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

Page 69: Rendering czasu rzeczywistego (PDF)

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

Page 70: Rendering czasu rzeczywistego (PDF)

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

Page 71: Rendering czasu rzeczywistego (PDF)

EBO, c.d.

71

Page 72: Rendering czasu rzeczywistego (PDF)

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

Page 73: Rendering czasu rzeczywistego (PDF)

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

Page 74: Rendering czasu rzeczywistego (PDF)

Przykład OpenGL04

74

Page 75: Rendering czasu rzeczywistego (PDF)

EBO i kilka VBO

75

Page 76: Rendering czasu rzeczywistego (PDF)

Przykład OpenGL05

76

Page 77: Rendering czasu rzeczywistego (PDF)

Przepływ danych

W wersji bardzo uproszczonej:

77

Page 78: Rendering czasu rzeczywistego (PDF)

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

Page 79: Rendering czasu rzeczywistego (PDF)

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

Page 80: Rendering czasu rzeczywistego (PDF)

smooth vs noperspective

80

Page 81: Rendering czasu rzeczywistego (PDF)

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

Page 82: Rendering czasu rzeczywistego (PDF)

Modele

82

Page 83: Rendering czasu rzeczywistego (PDF)

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

Page 84: Rendering czasu rzeczywistego (PDF)

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

Page 85: Rendering czasu rzeczywistego (PDF)

Demo prostego modelu…

85

Page 86: Rendering czasu rzeczywistego (PDF)

Przykład OpenGL07

86

Page 87: Rendering czasu rzeczywistego (PDF)

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

Page 88: Rendering czasu rzeczywistego (PDF)

Przykład OpenGL08

88

glEnable(GL_DEPTH_TEST);

Page 89: Rendering czasu rzeczywistego (PDF)

Geometria

89

Page 90: Rendering czasu rzeczywistego (PDF)

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

Page 91: Rendering czasu rzeczywistego (PDF)

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

91

Page 92: Rendering czasu rzeczywistego (PDF)

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

Page 93: Rendering czasu rzeczywistego (PDF)

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

Page 94: Rendering czasu rzeczywistego (PDF)

Przesunięcie (translacja)

94

Page 95: Rendering czasu rzeczywistego (PDF)

Skalowanie

95

Page 96: Rendering czasu rzeczywistego (PDF)

Obroty

96

Page 97: Rendering czasu rzeczywistego (PDF)

Perspektywa

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

Page 98: Rendering czasu rzeczywistego (PDF)

Perspektywa, c.d.

98

Page 99: Rendering czasu rzeczywistego (PDF)

Rzut równoległy

99

Page 100: Rendering czasu rzeczywistego (PDF)

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

Page 101: Rendering czasu rzeczywistego (PDF)

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

Page 102: Rendering czasu rzeczywistego (PDF)

Przykład OpenGL09/10/11

102

Page 103: Rendering czasu rzeczywistego (PDF)

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

Page 104: Rendering czasu rzeczywistego (PDF)

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

bool gl_FrontFacing dostępne w fragment shader

Badany jest znak wyrażenia:

104

Page 105: Rendering czasu rzeczywistego (PDF)

Przekształcenie normalnych

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

105

Page 107: Rendering czasu rzeczywistego (PDF)

Przykład OpenGL12/13

107

Page 108: Rendering czasu rzeczywistego (PDF)

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

Page 109: Rendering czasu rzeczywistego (PDF)

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

Page 110: Rendering czasu rzeczywistego (PDF)

Normalizacja normalnych

Czy jest potrzebna we fragment shaderze?

110

Page 111: Rendering czasu rzeczywistego (PDF)

Normalizacja normalnych, c.d.

Czy jest potrzebna w vertex shaderze?

111

Page 112: Rendering czasu rzeczywistego (PDF)

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

Page 113: Rendering czasu rzeczywistego (PDF)

Przykład OpenGL14

113

Page 114: Rendering czasu rzeczywistego (PDF)

Modele oświetlenia

114

Page 115: Rendering czasu rzeczywistego (PDF)

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

Page 116: Rendering czasu rzeczywistego (PDF)

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

Page 117: Rendering czasu rzeczywistego (PDF)

117

Oświetlenie lokalne i globalne, c.d.

Page 118: Rendering czasu rzeczywistego (PDF)

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

Page 119: Rendering czasu rzeczywistego (PDF)

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

Page 120: Rendering czasu rzeczywistego (PDF)

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

Page 121: Rendering czasu rzeczywistego (PDF)

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

Page 122: Rendering czasu rzeczywistego (PDF)

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

Page 123: Rendering czasu rzeczywistego (PDF)

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

Page 124: Rendering czasu rzeczywistego (PDF)

Ź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

Page 125: Rendering czasu rzeczywistego (PDF)

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

Page 126: Rendering czasu rzeczywistego (PDF)

Źródła kierunkowe

Zdefiniowane przez: Kierunek padania

Kolor i natężenie światła

Jasność nie zmienia się

126

Page 127: Rendering czasu rzeczywistego (PDF)

Ź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

Page 128: Rendering czasu rzeczywistego (PDF)

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

Page 129: Rendering czasu rzeczywistego (PDF)

Oświetlenie Phonga

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

129

Page 130: Rendering czasu rzeczywistego (PDF)

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

Page 131: Rendering czasu rzeczywistego (PDF)

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

Page 132: Rendering czasu rzeczywistego (PDF)

Oświetlenie Phonga, c.d.

132

Page 133: Rendering czasu rzeczywistego (PDF)

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

Page 134: Rendering czasu rzeczywistego (PDF)

Odbicie anizotropowe

134

Page 135: Rendering czasu rzeczywistego (PDF)

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

Page 136: Rendering czasu rzeczywistego (PDF)

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

Page 137: Rendering czasu rzeczywistego (PDF)

Gouraud vs Phong

137

Page 138: Rendering czasu rzeczywistego (PDF)

Przykład OpenGL15

138

Page 139: Rendering czasu rzeczywistego (PDF)

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

Page 140: Rendering czasu rzeczywistego (PDF)

Przykład OpenGL16

140

Page 141: Rendering czasu rzeczywistego (PDF)

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

Page 142: Rendering czasu rzeczywistego (PDF)

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

Page 143: Rendering czasu rzeczywistego (PDF)

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

Page 144: Rendering czasu rzeczywistego (PDF)

layout std140

Dla: layout (std140) uniform Material

{

vec3 ambient;

vec3 diffuse;

vec3 specular;

float shininess;

}

144

Page 145: Rendering czasu rzeczywistego (PDF)

(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

Page 146: Rendering czasu rzeczywistego (PDF)

Przykład OpenGL17

146

Page 147: Rendering czasu rzeczywistego (PDF)

Tekstury

147

Page 148: Rendering czasu rzeczywistego (PDF)

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

Page 149: Rendering czasu rzeczywistego (PDF)

Tekstura jako kolor

149

Page 150: Rendering czasu rzeczywistego (PDF)

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

Page 151: Rendering czasu rzeczywistego (PDF)

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

Page 152: Rendering czasu rzeczywistego (PDF)

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

Page 153: Rendering czasu rzeczywistego (PDF)

Mipmapping

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

153

Page 154: Rendering czasu rzeczywistego (PDF)

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

Page 155: Rendering czasu rzeczywistego (PDF)

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

Page 156: Rendering czasu rzeczywistego (PDF)

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

Page 157: Rendering czasu rzeczywistego (PDF)

Ł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

Page 158: Rendering czasu rzeczywistego (PDF)

Ł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

Page 159: Rendering czasu rzeczywistego (PDF)

Użycie tekstury we fragment shaderze

in vec2 fragTexCoor;

uniform sampler2D textureBitmap;

vec4 color = texture(textureBitmap, fragTexCoor);

159

Page 160: Rendering czasu rzeczywistego (PDF)

Przykład OpenGL18

160

Page 161: Rendering czasu rzeczywistego (PDF)

Inne zastosowania tekstur

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

161

Page 162: Rendering czasu rzeczywistego (PDF)

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

Page 163: Rendering czasu rzeczywistego (PDF)

Przykład OpenGL19

163

Page 164: Rendering czasu rzeczywistego (PDF)

Mapowanie normalnych

Pozwala uzyskać efekt nierówności powierzchni

Wymaga niestety pewnych manipulacji geometrycznych

164

Page 165: Rendering czasu rzeczywistego (PDF)

Mapa normalnych

165

W składowych RGB kodujemy wektory normalne do powierzchni

Page 166: Rendering czasu rzeczywistego (PDF)

Przestrzeń stycznych

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

166

Page 167: Rendering czasu rzeczywistego (PDF)

Przestrzeń stycznych, c.d.

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

167

Page 168: Rendering czasu rzeczywistego (PDF)

Przestrzeń stycznych, c.d.

168

Page 169: Rendering czasu rzeczywistego (PDF)

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

Page 170: Rendering czasu rzeczywistego (PDF)

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

Page 171: Rendering czasu rzeczywistego (PDF)

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

Page 172: Rendering czasu rzeczywistego (PDF)

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

Page 173: Rendering czasu rzeczywistego (PDF)

Przykład OpenGL20

173

Page 174: Rendering czasu rzeczywistego (PDF)

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

Page 175: Rendering czasu rzeczywistego (PDF)

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

Page 176: Rendering czasu rzeczywistego (PDF)

Porównanie

Wersja 1: Prostsza koncepcyjnie

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

176

Page 177: Rendering czasu rzeczywistego (PDF)

Przykład OpenGL21

177

Page 178: Rendering czasu rzeczywistego (PDF)

Mapowanie paralaksy

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

178

Page 179: Rendering czasu rzeczywistego (PDF)

Mapowanie paralaksy, c.d.

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

179

Page 180: Rendering czasu rzeczywistego (PDF)

Mapowanie paralaksy, c.d.

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

Page 181: Rendering czasu rzeczywistego (PDF)

Mapa wysokości

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

181

Page 182: Rendering czasu rzeczywistego (PDF)

Przesunięcie tekstury, wersja 1

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

182

Page 183: Rendering czasu rzeczywistego (PDF)

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

Page 184: Rendering czasu rzeczywistego (PDF)

Przykład OpenGL22

184

Page 185: Rendering czasu rzeczywistego (PDF)

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

Page 186: Rendering czasu rzeczywistego (PDF)

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

Page 187: Rendering czasu rzeczywistego (PDF)

Przykład OpenGL23

187

Page 188: Rendering czasu rzeczywistego (PDF)

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

Page 189: Rendering czasu rzeczywistego (PDF)

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

Page 190: Rendering czasu rzeczywistego (PDF)

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.

Page 191: Rendering czasu rzeczywistego (PDF)

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

Page 192: Rendering czasu rzeczywistego (PDF)

Przykład OpenGL24

192

Page 193: Rendering czasu rzeczywistego (PDF)

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

Page 194: Rendering czasu rzeczywistego (PDF)

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

Page 195: Rendering czasu rzeczywistego (PDF)

Przykład OpenGL25

195

Page 196: Rendering czasu rzeczywistego (PDF)

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

Page 197: Rendering czasu rzeczywistego (PDF)

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

Page 198: Rendering czasu rzeczywistego (PDF)

Przykład OpenGL26

198

Page 199: Rendering czasu rzeczywistego (PDF)

Dwie tekstury na płaski obiekt

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

199

Page 200: Rendering czasu rzeczywistego (PDF)

Przykład OpenGL27

200

Page 201: Rendering czasu rzeczywistego (PDF)

Cienie, cz. I

201

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

Page 202: Rendering czasu rzeczywistego (PDF)

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

Page 203: Rendering czasu rzeczywistego (PDF)

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

Page 204: Rendering czasu rzeczywistego (PDF)

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

Page 205: Rendering czasu rzeczywistego (PDF)

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

Page 206: Rendering czasu rzeczywistego (PDF)

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

Page 207: Rendering czasu rzeczywistego (PDF)

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

Page 208: Rendering czasu rzeczywistego (PDF)

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

Page 209: Rendering czasu rzeczywistego (PDF)

Przykład OpenGL28

209

Page 210: Rendering czasu rzeczywistego (PDF)

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

Page 211: Rendering czasu rzeczywistego (PDF)

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

Page 212: Rendering czasu rzeczywistego (PDF)

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

Page 213: Rendering czasu rzeczywistego (PDF)

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

Page 214: Rendering czasu rzeczywistego (PDF)

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

Page 215: Rendering czasu rzeczywistego (PDF)

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

Page 216: Rendering czasu rzeczywistego (PDF)

Efekt moiré

216

Page 217: Rendering czasu rzeczywistego (PDF)

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

Page 218: Rendering czasu rzeczywistego (PDF)

Przykład OpenGL29

218

Page 219: Rendering czasu rzeczywistego (PDF)

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

Page 220: Rendering czasu rzeczywistego (PDF)

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

Page 221: Rendering czasu rzeczywistego (PDF)

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

Page 222: Rendering czasu rzeczywistego (PDF)

Przykład OpenGL30

222

Page 223: Rendering czasu rzeczywistego (PDF)

Mapa cienia dla światła punktowego

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

223

Page 224: Rendering czasu rzeczywistego (PDF)

Geometry shader

224

Page 225: Rendering czasu rzeczywistego (PDF)

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

Page 226: Rendering czasu rzeczywistego (PDF)

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

226

Page 227: Rendering czasu rzeczywistego (PDF)

GL_TRIANGLE_STRIP, GL_TRIANGLE_FAN

227

Page 228: Rendering czasu rzeczywistego (PDF)

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

228

Page 229: Rendering czasu rzeczywistego (PDF)

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

Page 230: Rendering czasu rzeczywistego (PDF)

OpenGL 4.5 rendering pipeline (przypomnienie)

230

Page 231: Rendering czasu rzeczywistego (PDF)

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

Page 232: Rendering czasu rzeczywistego (PDF)

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

Page 233: Rendering czasu rzeczywistego (PDF)

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

Page 234: Rendering czasu rzeczywistego (PDF)

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

Page 235: Rendering czasu rzeczywistego (PDF)

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

Page 236: Rendering czasu rzeczywistego (PDF)

Przykład OpenGL31

236

Page 237: Rendering czasu rzeczywistego (PDF)

Przykład OpenGL32

237

Page 238: Rendering czasu rzeczywistego (PDF)

Cienie, cz. II

238

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

Page 239: Rendering czasu rzeczywistego (PDF)

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

Page 240: Rendering czasu rzeczywistego (PDF)

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

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

240

Page 241: Rendering czasu rzeczywistego (PDF)

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

Page 242: Rendering czasu rzeczywistego (PDF)

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

Page 243: Rendering czasu rzeczywistego (PDF)

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

Page 244: Rendering czasu rzeczywistego (PDF)

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

Page 245: Rendering czasu rzeczywistego (PDF)

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

Page 246: Rendering czasu rzeczywistego (PDF)

Przykład OpenGL33

246

Page 247: Rendering czasu rzeczywistego (PDF)

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

Page 248: Rendering czasu rzeczywistego (PDF)

Przykład OpenGL34

248

Page 249: Rendering czasu rzeczywistego (PDF)

HDR

249

High Dynamic Range

Page 250: Rendering czasu rzeczywistego (PDF)

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

Page 251: Rendering czasu rzeczywistego (PDF)

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

Page 252: Rendering czasu rzeczywistego (PDF)

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

Page 253: Rendering czasu rzeczywistego (PDF)

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

Page 254: Rendering czasu rzeczywistego (PDF)

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

Page 255: Rendering czasu rzeczywistego (PDF)

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

Page 256: Rendering czasu rzeczywistego (PDF)

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

Page 257: Rendering czasu rzeczywistego (PDF)

I jeszcze jeden przykład

257

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

Page 258: Rendering czasu rzeczywistego (PDF)

258

Page 259: Rendering czasu rzeczywistego (PDF)

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

Page 260: Rendering czasu rzeczywistego (PDF)

LDR, dodawanie kolorów

260

Page 261: Rendering czasu rzeczywistego (PDF)

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

Page 263: Rendering czasu rzeczywistego (PDF)

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

10000001-hdr-projection-demo

263

Page 264: Rendering czasu rzeczywistego (PDF)

Typy zmiennoprzecinkowe w OpenGL

264

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

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

Page 265: Rendering czasu rzeczywistego (PDF)

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

Page 266: Rendering czasu rzeczywistego (PDF)

Tone mapping, c.d.

Ekspozycja

266

Page 267: Rendering czasu rzeczywistego (PDF)

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

Page 268: Rendering czasu rzeczywistego (PDF)

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

Page 269: Rendering czasu rzeczywistego (PDF)

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

Page 270: Rendering czasu rzeczywistego (PDF)

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

Page 271: Rendering czasu rzeczywistego (PDF)

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: ???

Page 272: Rendering czasu rzeczywistego (PDF)

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

Page 273: Rendering czasu rzeczywistego (PDF)

Porównanie

273

Page 274: Rendering czasu rzeczywistego (PDF)

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

Page 275: Rendering czasu rzeczywistego (PDF)

Przykład OpenGL35

275

Page 276: Rendering czasu rzeczywistego (PDF)

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

Page 277: Rendering czasu rzeczywistego (PDF)

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

Page 278: Rendering czasu rzeczywistego (PDF)

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

Page 279: Rendering czasu rzeczywistego (PDF)

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…)

Page 280: Rendering czasu rzeczywistego (PDF)

Współczynniki

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

280

Page 281: Rendering czasu rzeczywistego (PDF)

Współczynniki, c.d.

281

Page 282: Rendering czasu rzeczywistego (PDF)

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

Page 283: Rendering czasu rzeczywistego (PDF)

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

Page 284: Rendering czasu rzeczywistego (PDF)

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

Page 285: Rendering czasu rzeczywistego (PDF)

Efekt poświaty, c.d.

285

Page 286: Rendering czasu rzeczywistego (PDF)

Przykład OpenGL36

286

Page 287: Rendering czasu rzeczywistego (PDF)

Przetwarzanie w OpenGL36

287

Page 288: Rendering czasu rzeczywistego (PDF)

Opóźnione cieniowanie

288

Deferred shading

Page 289: Rendering czasu rzeczywistego (PDF)

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

Page 290: Rendering czasu rzeczywistego (PDF)

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

Page 291: Rendering czasu rzeczywistego (PDF)

Wizualizacja 60 000 sfer

291

Page 292: Rendering czasu rzeczywistego (PDF)

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

Page 293: Rendering czasu rzeczywistego (PDF)

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

Page 294: Rendering czasu rzeczywistego (PDF)

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

Page 295: Rendering czasu rzeczywistego (PDF)

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

Page 296: Rendering czasu rzeczywistego (PDF)

Przykład OpenGL37

296

Page 297: Rendering czasu rzeczywistego (PDF)

Przetwarzanie w OpenGL37

297

Page 298: Rendering czasu rzeczywistego (PDF)

Zawartość g-bufora w OpenGL37

298

Page 299: Rendering czasu rzeczywistego (PDF)

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

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

299

Page 300: Rendering czasu rzeczywistego (PDF)

Przykład OpenGL38

300

Page 301: Rendering czasu rzeczywistego (PDF)

Przetwarzanie w OpenGL38

301

Page 302: Rendering czasu rzeczywistego (PDF)

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

Page 303: Rendering czasu rzeczywistego (PDF)

SSAO

303

Screen-Space Ambient Occlusion

Page 304: Rendering czasu rzeczywistego (PDF)

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

Page 305: Rendering czasu rzeczywistego (PDF)

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

Page 306: Rendering czasu rzeczywistego (PDF)

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

Page 307: Rendering czasu rzeczywistego (PDF)

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

Page 308: Rendering czasu rzeczywistego (PDF)

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

Page 309: Rendering czasu rzeczywistego (PDF)

Mapowanie głębokości

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

OpenGL stosuje:

309

Page 310: Rendering czasu rzeczywistego (PDF)

SSAO, c.d.

310

Page 311: Rendering czasu rzeczywistego (PDF)

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

Page 312: Rendering czasu rzeczywistego (PDF)

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

Page 313: Rendering czasu rzeczywistego (PDF)

Wynik SSAO

313

Page 314: Rendering czasu rzeczywistego (PDF)

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

Page 315: Rendering czasu rzeczywistego (PDF)

Schemat działania

315

Zamiast:

Page 316: Rendering czasu rzeczywistego (PDF)

Kontrola zasięgu

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

316

Page 317: Rendering czasu rzeczywistego (PDF)

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

Page 318: Rendering czasu rzeczywistego (PDF)

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

Page 319: Rendering czasu rzeczywistego (PDF)

Przykład OpenGL39

319

Page 320: Rendering czasu rzeczywistego (PDF)

Rendering instancyjny

320

Instancing

Page 321: Rendering czasu rzeczywistego (PDF)

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

Page 322: Rendering czasu rzeczywistego (PDF)

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

Page 323: Rendering czasu rzeczywistego (PDF)

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

Page 324: Rendering czasu rzeczywistego (PDF)

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

Page 325: Rendering czasu rzeczywistego (PDF)

Przykład OpenGL40

325

Page 326: Rendering czasu rzeczywistego (PDF)

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

Page 327: Rendering czasu rzeczywistego (PDF)

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

Page 328: Rendering czasu rzeczywistego (PDF)

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

Page 329: Rendering czasu rzeczywistego (PDF)

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

Page 330: Rendering czasu rzeczywistego (PDF)

Przykład OpenGL41

330

Page 331: Rendering czasu rzeczywistego (PDF)

Tesselation shaders

331

Page 332: Rendering czasu rzeczywistego (PDF)

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

Page 333: Rendering czasu rzeczywistego (PDF)

Trzy etapy tesselacji

333

Dostępne od OpenGL 4.0

Opcjonalna tesselacja następuje po vertex shaderze

Page 334: Rendering czasu rzeczywistego (PDF)

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

Page 335: Rendering czasu rzeczywistego (PDF)

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

Page 336: Rendering czasu rzeczywistego (PDF)

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

Page 337: Rendering czasu rzeczywistego (PDF)

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

Page 338: Rendering czasu rzeczywistego (PDF)

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

Page 339: Rendering czasu rzeczywistego (PDF)

Tryby tesselacji

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

Kwadraty

Izolinie

339

Page 340: Rendering czasu rzeczywistego (PDF)

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

Page 341: Rendering czasu rzeczywistego (PDF)

gl_TessLevelOuter

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

341

Page 342: Rendering czasu rzeczywistego (PDF)

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

Page 343: Rendering czasu rzeczywistego (PDF)

Przykład OpenGL42

343

Page 344: Rendering czasu rzeczywistego (PDF)

Tryb tesselacji: kwadrat

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

W kwadracie generowane są punkty wg schematu

344

Page 345: Rendering czasu rzeczywistego (PDF)

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

Page 346: Rendering czasu rzeczywistego (PDF)

Przykład OpenGL43

346

Page 347: Rendering czasu rzeczywistego (PDF)

Tryb tesselacji: izolinie

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

W kwadracie generowane są punkty wg schematu

347

Page 348: Rendering czasu rzeczywistego (PDF)

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

Page 349: Rendering czasu rzeczywistego (PDF)

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

Page 350: Rendering czasu rzeczywistego (PDF)

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)

Page 351: Rendering czasu rzeczywistego (PDF)

Przykład OpenGL44

351

Page 353: Rendering czasu rzeczywistego (PDF)

Przykład OpenGL45

353

Page 354: Rendering czasu rzeczywistego (PDF)

Mgła

354

Page 355: Rendering czasu rzeczywistego (PDF)

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

Page 356: Rendering czasu rzeczywistego (PDF)

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

Page 357: Rendering czasu rzeczywistego (PDF)

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

Page 358: Rendering czasu rzeczywistego (PDF)

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

Page 359: Rendering czasu rzeczywistego (PDF)

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

Page 360: Rendering czasu rzeczywistego (PDF)

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

Page 361: Rendering czasu rzeczywistego (PDF)

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

Można też policzyć dokładniej:

361

Page 362: Rendering czasu rzeczywistego (PDF)

Przykład OpenGL46

362

Page 363: Rendering czasu rzeczywistego (PDF)

Głębia ostrości

363

Depth of Field

Page 364: Rendering czasu rzeczywistego (PDF)

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

Page 365: Rendering czasu rzeczywistego (PDF)

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

Page 366: Rendering czasu rzeczywistego (PDF)

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

Page 367: Rendering czasu rzeczywistego (PDF)

Krążek rozmycia w praktyce

367

Page 368: Rendering czasu rzeczywistego (PDF)

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

Page 369: Rendering czasu rzeczywistego (PDF)

Porównajmy…

369 http://www.trusim.com/

Page 370: Rendering czasu rzeczywistego (PDF)

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

Page 371: Rendering czasu rzeczywistego (PDF)

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

Page 372: Rendering czasu rzeczywistego (PDF)

Przykład OpenGL47

372

Page 373: Rendering czasu rzeczywistego (PDF)

Obiekty przejrzyste

373

Page 374: Rendering czasu rzeczywistego (PDF)

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

Page 375: Rendering czasu rzeczywistego (PDF)

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

Page 376: Rendering czasu rzeczywistego (PDF)

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

Page 377: Rendering czasu rzeczywistego (PDF)

Testowe drzewo

377

model

tekstura

Page 378: Rendering czasu rzeczywistego (PDF)

Przykład OpenGL48

378

Page 379: Rendering czasu rzeczywistego (PDF)

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

Page 380: Rendering czasu rzeczywistego (PDF)

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

Page 381: Rendering czasu rzeczywistego (PDF)

381

Page 382: Rendering czasu rzeczywistego (PDF)

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

Page 383: Rendering czasu rzeczywistego (PDF)

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

Page 384: Rendering czasu rzeczywistego (PDF)

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

Page 385: Rendering czasu rzeczywistego (PDF)

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

Page 386: Rendering czasu rzeczywistego (PDF)

Sortowanie względem głębokości

Jest zadaniem nie zawsze jednoznacznym…

386

Page 387: Rendering czasu rzeczywistego (PDF)

Przykład OpenGL49

387

Page 388: Rendering czasu rzeczywistego (PDF)

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

Page 389: Rendering czasu rzeczywistego (PDF)

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

Page 390: Rendering czasu rzeczywistego (PDF)

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

390

Page 391: Rendering czasu rzeczywistego (PDF)

Przykład OpenGL50

391

Page 392: Rendering czasu rzeczywistego (PDF)

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

Page 393: Rendering czasu rzeczywistego (PDF)

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

Page 394: Rendering czasu rzeczywistego (PDF)

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

Page 395: Rendering czasu rzeczywistego (PDF)

Przykład OpenGL51

395

Page 396: Rendering czasu rzeczywistego (PDF)

Chmury

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

Page 397: Rendering czasu rzeczywistego (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

Page 398: Rendering czasu rzeczywistego (PDF)

Przykład OpenGL52

398

Page 399: Rendering czasu rzeczywistego (PDF)

Przykład OpenGL53

399

Page 400: Rendering czasu rzeczywistego (PDF)

Obrazowanie objętościowe

400

Volume rendering

Page 401: Rendering czasu rzeczywistego (PDF)

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

Page 402: Rendering czasu rzeczywistego (PDF)

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

Page 403: Rendering czasu rzeczywistego (PDF)

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

Page 404: Rendering czasu rzeczywistego (PDF)

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

Page 405: Rendering czasu rzeczywistego (PDF)

Wyzwanie

Jednoczesna wizualizacja danych z wielu źródeł…

405

Page 406: Rendering czasu rzeczywistego (PDF)

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

Page 407: Rendering czasu rzeczywistego (PDF)

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

Page 408: Rendering czasu rzeczywistego (PDF)

Przykład OpenGL54

408

Page 409: Rendering czasu rzeczywistego (PDF)

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

Page 410: Rendering czasu rzeczywistego (PDF)

Przykład OpenGL55

410

Page 411: Rendering czasu rzeczywistego (PDF)

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

Page 412: Rendering czasu rzeczywistego (PDF)

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

Page 413: Rendering czasu rzeczywistego (PDF)

Przykład OpenGL56

413

Page 414: Rendering czasu rzeczywistego (PDF)

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

Page 415: Rendering czasu rzeczywistego (PDF)

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

Page 416: Rendering czasu rzeczywistego (PDF)

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

Page 417: Rendering czasu rzeczywistego (PDF)

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

Page 418: Rendering czasu rzeczywistego (PDF)

Teksturowanie proceduralne

418

Page 419: Rendering czasu rzeczywistego (PDF)

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

Page 420: Rendering czasu rzeczywistego (PDF)

420

Page 421: Rendering czasu rzeczywistego (PDF)

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

Page 422: Rendering czasu rzeczywistego (PDF)

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

Page 423: Rendering czasu rzeczywistego (PDF)

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

Page 424: Rendering czasu rzeczywistego (PDF)

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

Page 425: Rendering czasu rzeczywistego (PDF)

Przykład 1 - drewno

Funkcje:

p – funkcja piłokształtna

425

Page 426: Rendering czasu rzeczywistego (PDF)

Przykład 2 - marmur

426

Funkcje:

p – funkcja sin

Page 427: Rendering czasu rzeczywistego (PDF)

Przykład OpenGL57

427

Page 428: Rendering czasu rzeczywistego (PDF)

Ś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

Page 429: Rendering czasu rzeczywistego (PDF)

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

Page 430: Rendering czasu rzeczywistego (PDF)

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

Page 431: Rendering czasu rzeczywistego (PDF)

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

Page 432: Rendering czasu rzeczywistego (PDF)

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/

Page 433: Rendering czasu rzeczywistego (PDF)

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

Page 434: Rendering czasu rzeczywistego (PDF)

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

Page 435: Rendering czasu rzeczywistego (PDF)

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

animacji (szum 3D i 4D):

435

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

Page 436: Rendering czasu rzeczywistego (PDF)

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

Page 437: Rendering czasu rzeczywistego (PDF)

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

Page 438: Rendering czasu rzeczywistego (PDF)

Przykład OpenGL58

438

Page 439: Rendering czasu rzeczywistego (PDF)

Użycie funkcji szumu w teksturach

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

Np. dla drewna:

439

Page 440: Rendering czasu rzeczywistego (PDF)

Przykład OpenGL59

440

Page 441: Rendering czasu rzeczywistego (PDF)

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

Page 442: Rendering czasu rzeczywistego (PDF)

Przykład OpenGL60

442

Page 443: Rendering czasu rzeczywistego (PDF)

Zaznaczanie obiektów

443

Page 444: Rendering czasu rzeczywistego (PDF)

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

Page 445: Rendering czasu rzeczywistego (PDF)

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

Page 446: Rendering czasu rzeczywistego (PDF)

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

Page 447: Rendering czasu rzeczywistego (PDF)

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

Page 448: Rendering czasu rzeczywistego (PDF)

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

Page 449: Rendering czasu rzeczywistego (PDF)

Przykład OpenGL61

449

Page 450: Rendering czasu rzeczywistego (PDF)

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

Page 451: Rendering czasu rzeczywistego (PDF)

Przykład OpenGL62

451

Page 452: Rendering czasu rzeczywistego (PDF)

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

Page 453: Rendering czasu rzeczywistego (PDF)

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

Page 454: Rendering czasu rzeczywistego (PDF)

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

Page 455: Rendering czasu rzeczywistego (PDF)

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

Page 456: Rendering czasu rzeczywistego (PDF)

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

Page 457: Rendering czasu rzeczywistego (PDF)

457

1

2

Bufor koloru i stencil

Page 458: Rendering czasu rzeczywistego (PDF)

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

Page 459: Rendering czasu rzeczywistego (PDF)

Przykład OpenGL63

459

Page 460: Rendering czasu rzeczywistego (PDF)

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

Page 461: Rendering czasu rzeczywistego (PDF)

Krzyż Robertsa

461

Page 462: Rendering czasu rzeczywistego (PDF)

Operator Sobela

462

Page 463: Rendering czasu rzeczywistego (PDF)

Przykład OpenGL64

463

Page 464: Rendering czasu rzeczywistego (PDF)

464