WebGL - szybki przewodnik
Kilka lat temu aplikacje Java - jako połączenie apletów i JOGL - były używane do przetwarzania grafiki 3D w sieci WWW poprzez adresowanie GPU (Graphical Processing Unit). Ponieważ aplety wymagają do działania maszyny JVM, trudno było polegać na apletach Java. Kilka lat później ludzie przestali używać apletów Java.
Interfejsy API Stage3D dostarczane przez firmę Adobe (Flash, AIR) oferowały architekturę akcelerowaną sprzętowo przez GPU. Korzystając z tych technologii, programiści mogliby tworzyć aplikacje z funkcjami 2D i 3D w przeglądarkach internetowych, a także na platformach IOS i Android. Ponieważ Flash był oprogramowaniem zastrzeżonym, nie był używany jako standard sieciowy.
W marcu 2011 r. Wydano WebGL. Jest to oprogramowanie typu openware, które może działać bez JVM. Jest całkowicie kontrolowany przez przeglądarkę internetową.
Nowa wersja HTML 5 ma kilka funkcji obsługujących grafikę 3D, takich jak 2D Canvas, WebGL, SVG, 3D CSS transforms i SMIL. W tym samouczku omówimy podstawy WebGL.
Co to jest OpenGL?
OpenGL (Open Graphics Library) to wielojęzyczny, wieloplatformowy interfejs API dla grafiki 2D i 3D. To zbiór poleceń. OpenGL4.5 to najnowsza wersja OpenGL. Poniższa tabela zawiera zestaw technologii związanych z OpenGL.
API | Zastosowana technologia |
---|---|
OpenGL ES | Jest to biblioteka grafiki 2D i 3D w systemach wbudowanych - w tym na konsolach, telefonach, urządzeniach i pojazdach. OpenGL ES 3.1 to jego najnowsza wersja. Jest utrzymywany przez grupę Khronos www.khronos.org |
JOGL | To jest powiązanie Java dla OpenGL. JOGL 4.5 to jego najnowsza wersja, utrzymywana przez jogamp.org. |
WebGL | Jest to powiązanie JavaScript dla OpenGL. WebGL 1.0 to jego najnowsza wersja, utrzymywana przez grupę khronos . |
OpenGLSL | OpenGL Shading Language. Jest to język programowania towarzyszący OpenGL 2.0 i nowszym. Jest to część podstawowej specyfikacji OpenGL 4.4. Jest to interfejs API specjalnie dostosowany do systemów wbudowanych, takich jak te obecne w telefonach komórkowych i tabletach. |
Note - W WebGL używamy GLSL do pisania shaderów.
Co to jest WebGL?
WebGL (Web Graphics Library) to nowy standard grafiki 3D w Internecie, zaprojektowany do renderowania grafiki 2D i interaktywnej grafiki 3D. Wywodzi się z biblioteki OpenGL ES 2.0, która jest niskopoziomowym interfejsem API 3D dla telefonów i innych urządzeń mobilnych. WebGL zapewnia podobną funkcjonalność jak ES 2.0 (systemy wbudowane) i działa dobrze na nowoczesnym sprzęcie graficznym 3D.
Jest to API JavaScript, którego można używać z HTML5. Kod WebGL jest zapisywany w tagu <canvas> HTML5. Jest to specyfikacja, która umożliwia przeglądarkom internetowym dostęp do procesorów graficznych (GPU) na tych komputerach, na których były używane.
Kto opracował WebGL
Amerykańsko-serbski inżynier oprogramowania o nazwisku Vladimir Vukicevic wykonał prace fundamentowe i kierował tworzeniem WebGL
W 2007 roku Vladimir rozpoczął pracę nad plikiem OpenGL prototyp elementu Canvas w dokumencie HTML.
W marcu 2011 roku Kronos Group stworzyła WebGL.
Wykonanie
Renderowanie to proces generowania obrazu z modelu przy użyciu programów komputerowych. W grafice wirtualna scena jest opisywana przy użyciu informacji, takich jak geometria, punkt widzenia, tekstura, oświetlenie i cieniowanie, które są przekazywane przez program renderujący. Wynikiem tego programu renderującego będzie obraz cyfrowy.
Istnieją dwa rodzaje renderowania -
Software Rendering - Wszystkie obliczenia renderowania są wykonywane przy pomocy procesora.
Hardware Rendering - Wszystkie obliczenia graficzne są wykonywane przez GPU (procesor graficzny).
Renderowanie może odbywać się lokalnie lub zdalnie. Jeśli renderowany obraz jest zbyt złożony, renderowanie odbywa się zdalnie na dedykowanym serwerze, który ma wystarczającą ilość zasobów sprzętowych wymaganych do renderowania złożonych scen. Nazywa się to również jakoserver-based rendering. Renderowanie może być również wykonywane lokalnie przez procesor. Nazywa się asclient-based rendering.
WebGL stosuje podejście oparte na renderowaniu opartym na kliencie, aby renderować sceny 3D. Całe przetwarzanie wymagane do uzyskania obrazu jest wykonywane lokalnie przy użyciu sprzętu graficznego klienta.
GPU
Według firmy NVIDIA, GPU to „jednoukładowy procesor ze zintegrowanym przetwarzaniem, oświetleniem, konfiguracją / obcinaniem trójkątów i silnikami renderującymi, zdolnymi do przetwarzania co najmniej 10 milionów wielokątów na sekundę”. W przeciwieństwie do procesorów wielordzeniowych z kilkoma rdzeniami zoptymalizowanymi pod kątem przetwarzania sekwencyjnego, GPU składa się z tysięcy mniejszych rdzeni, które wydajnie przetwarzają równoległe obciążenia. W związku z tym GPU przyspiesza tworzenie obrazów w buforze ramki (części pamięci RAM, która zawiera pełne dane ramki) przeznaczonych do wyprowadzenia na wyświetlacz.
Obliczenia przyspieszane przez GPU
W przypadku obliczeń z akceleracją GPU aplikacja jest ładowana do procesora. Ilekroć napotkacompute-intensiveczęść kodu, to ta część kodu zostanie załadowana i uruchomiona na GPU. Daje systemowi możliwość efektywnego przetwarzania grafiki.
Procesor graficzny będzie miał oddzielną pamięć i będzie uruchamiał wiele kopii niewielkiej części kodu naraz. GPU przetwarza wszystkie dane, które są w jego pamięci lokalnej, a nie w pamięci centralnej. Dlatego dane, które mają być przetworzone przez GPU, powinny zostać załadowane / skopiowane do pamięci GPU, a następnie przetworzone.
W systemach o powyższej architekturze należy zmniejszyć narzut komunikacyjny między CPU a GPU, aby uzyskać szybsze przetwarzanie programów 3D. W tym celu musimy skopiować wszystkie dane i zachować je na GPU, zamiast wielokrotnie komunikować się z GPU.
Obsługiwane przeglądarki
Poniższe tabele przedstawiają listę przeglądarek obsługujących WebGL -
Przeglądarki internetowe
Nazwa przeglądarki | Wersja | Wsparcie |
---|---|---|
Internet Explorer | 11 i nowsze | Pełne wsparcie |
Google Chrome | 39 i więcej | Pełne wsparcie |
Safari | 8 | Pełne wsparcie |
Firefox | 36 i więcej | Częściowe wsparcie |
Opera | 27 i więcej | Częściowe wsparcie |
Przeglądarki mobilne
Nazwa przeglądarki | Wersja | Wsparcie |
---|---|---|
Chrome na Androida | 42 | Częściowe wsparcie |
Przeglądarka Android | 40 | Częściowe wsparcie |
Safari na iOS | 8.3 | Pełne wsparcie |
Opera Mini | 8 | Nie wspiera |
Przeglądarka Blackberry | 10 | Pełne wsparcie |
IE mobile | 10 | Częściowe wsparcie |
Zalety WebGL
Oto zalety korzystania z WebGL -
JavaScript programming- Aplikacje WebGL są napisane w JavaScript. Korzystając z tych aplikacji, możesz bezpośrednio oddziaływać na inne elementy dokumentu HTML. Możesz również użyć innych bibliotek JavaScript (np. JQuery) i technologii HTML, aby wzbogacić aplikację WebGL.
Increasing support with mobile browsers - WebGL obsługuje również przeglądarki mobilne, takie jak iOS safari, przeglądarka Android i Chrome na Androida.
Open source- WebGL jest oprogramowaniem typu open source. Możesz uzyskać dostęp do kodu źródłowego biblioteki i zrozumieć, jak ona działa i jak została opracowana.
No need for compilation- JavaScript jest komponentem w połowie programującym, aw połowie HTML. Aby wykonać ten skrypt, nie ma potrzeby kompilowania pliku. Zamiast tego możesz bezpośrednio otworzyć plik za pomocą dowolnej przeglądarki i sprawdzić wynik. Ponieważ aplikacje WebGL są tworzone przy użyciu JavaScript, nie ma również potrzeby kompilowania aplikacji WebGL.
Automatic memory management- JavaScript obsługuje automatyczne zarządzanie pamięcią. Nie ma potrzeby ręcznego przydzielania pamięci. WebGL dziedziczy tę funkcję JavaScript.
Easy to set up- Ponieważ WebGL jest zintegrowany z HTML 5, nie ma potrzeby dodatkowej konfiguracji. Aby napisać aplikację WebGL, potrzebujesz tylko edytora tekstu i przeglądarki internetowej.
Konfiguracja środowiska
Nie ma potrzeby ustawiania innego środowiska dla WebGL. Przeglądarki obsługujące WebGL mają własną wbudowaną konfigurację dla WebGL.
Aby tworzyć aplikacje graficzne w sieci, HTML-5 zapewnia bogaty zestaw funkcji, takich jak 2D Canvas, WebGL, SVG, 3D CSS transforms i SMIL. Do pisania aplikacji WebGL używamy istniejącego elementu canvas HTML-5. Ten rozdział zawiera omówienie elementu canvas HTML-5 2D.
HTML5 Canvas
HTML-5 <canvas>zapewnia łatwą i wydajną opcję rysowania grafiki za pomocą JavaScript. Może być używany do rysowania wykresów, tworzenia kompozycji zdjęć lub wykonywania prostych (i nie tak prostych) animacji.
Oto prosty <canvas> element mający tylko dwa określone atrybuty width i height plus wszystkie podstawowe atrybuty HTML-5, takie jak id, nazwa i klasa.
Składnia
Składnię tagu HTML canvas podano poniżej. Musisz podać nazwę płótna w podwójnych cudzysłowach („”).
<canvas id = "mycanvas" width = "100" height = "100"></canvas>
Atrybuty płótna
Znacznik płótna ma trzy atrybuty, a mianowicie identyfikator, szerokość i wysokość.
Id- Id reprezentuje identyfikator elementu canvas w Document Object Model (DOM) .
Width - Szerokość reprezentuje szerokość płótna.
Height - Wysokość oznacza wysokość płótna.
Te atrybuty określają rozmiar płótna. Jeśli programista nie określa ich pod tagiem canvas, przeglądarki takie jak Firefox, Chrome i Web Kit domyślnie udostępniają element canvas o wymiarach 300 × 150.
Przykład - Utwórz płótno
Poniższy kod przedstawia sposób tworzenia kanwy. Użyliśmy CSS, aby nadać płótnie kolorową ramkę.
<html>
<head>
<style>
#mycanvas{border:1px solid red;}
</style>
</head>
<body>
<canvas id = "mycanvas" width = "100" height = "100"></canvas>
</body>
</html>
Podczas wykonywania powyższy kod wygeneruje następujący wynik -
Kontekst renderowania
Element <canvas> jest początkowo pusty. Aby wyświetlić coś w elemencie canvas, musimy użyć języka skryptowego. Ten język skryptowy powinien mieć dostęp do kontekstu renderowania i korzystać z niego.
Element canvas ma metodę DOM o nazwie getContext(), który służy do uzyskiwania kontekstu renderowania i jego funkcji rysowania. Ta metoda przyjmuje jeden parametr, typ kontekstu2d.
Aby uzyskać wymagany kontekst, należy napisać następujący kod. Możesz napisać ten skrypt wewnątrz tagu body, jak pokazano poniżej.
<!DOCTYPE HTML>
<html>
<body>
<canvas id = "mycanvas" width = "600" height = "200"></canvas>
<script>
var canvas = document.getElementById('mycanvas');
var context = canvas.getContext('2d');
context.font = '20pt Calibri';
context.fillStyle = 'green';
context.fillText('Welcome to Tutorialspoint', 70, 70);
</script>
</body>
</html>
Podczas wykonywania powyższy kod wygeneruje następujący wynik -
Aby uzyskać więcej przykładów na temat HTML-5 2D Canvas, sprawdź poniższe łącze HTML-5 Canvas .
Kontekst WebGL
HTML5 Canvas służy również do pisania aplikacji WebGL. Aby utworzyć kontekst renderowania WebGL w elemencie canvas, należy przekazać ciągexperimental-webgl, zamiast 2d do canvas.getContext()metoda. Niektóre przeglądarki obsługują tylko 'webgl”.
<!DOCTYPE html>
<html>
<canvas id = 'my_canvas'></canvas>
<script>
var canvas = document.getElementById('my_canvas');
var gl = canvas.getContext('experimental-webgl');
gl.clearColor(0.9,0.9,0.8,1);
gl.clear(gl.COLOR_BUFFER_BIT);
</script>
</html>
Podczas wykonywania powyższy kod wygeneruje następujący wynik -
WebGL jest głównie interfejsem API rasteryzacji niskiego poziomu, a nie interfejsem 3D. Aby narysować obraz za pomocą WebGL, musisz przekazać wektor reprezentujący obraz. Następnie konwertuje dany wektor do formatu pikselowego za pomocą OpenGL SL i wyświetla obraz na ekranie. Pisanie aplikacji WebGL obejmuje zestaw kroków, które będziemy wyjaśniać w tym rozdziale.
WebGL - układ współrzędnych
Podobnie jak w każdym innym systemie 3D, będziesz mieć osie X, Y i Z w WebGL, gdzie z oś oznacza depth. Współrzędne w WebGL są ograniczone do (1, 1, 1) i (-1, -1, - 1). To znaczy - jeśli weźmiesz pod uwagę ekran wyświetlający grafikę WebGL jako sześcian, to jeden róg sześcianu będzie (1, 1, 1), a przeciwległy - (-1, -1, -1). WebGL nie wyświetli niczego, co jest narysowane poza tymi granicami.
Poniższy diagram przedstawia układ współrzędnych WebGL. Oś Z oznacza głębokość. Dodatnia wartość z oznacza, że obiekt znajduje się blisko ekranu / przeglądarki, natomiast ujemna wartość z oznacza, że obiekt znajduje się z dala od ekranu. Podobnie dodatnia wartość x wskazuje, że obiekt znajduje się po prawej stronie ekranu, a wartość ujemna oznacza, że obiekt znajduje się po lewej stronie. Podobnie dodatnie i ujemne wartości y wskazują, czy obiekt znajduje się w górnej, czy w dolnej części ekranu.
Grafika WebGL
Po uzyskaniu kontekstu WebGL obiektu canvas, można rozpocząć rysowanie elementów graficznych za pomocą interfejsu API WebGL w JavaScript.
Oto kilka podstawowych pojęć, które musisz znać przed rozpoczęciem korzystania z WebGL.
Wierzchołki
Generalnie, aby narysować obiekty takie jak wielokąt, zaznaczamy punkty na płaszczyźnie i łączymy je w pożądany wielokąt. ZAvertexto punkt definiujący koniunkcję krawędzi obiektu 3D. Jest reprezentowany przez trzy wartości zmiennoprzecinkowe, z których każda reprezentuje odpowiednio osie x, y, z.
Przykład
W poniższym przykładzie rysujemy trójkąt z następującymi wierzchołkami - (0,5, 0,5), (-0,5, 0,5), (-0,5, -0,5).
Note - Musimy ręcznie przechowywać te wierzchołki za pomocą tablic JavaScript i przekazywać je do potoku renderującego WebGL przy użyciu bufora wierzchołków.
Indeksy
W WebGL do identyfikacji wierzchołków używane są wartości liczbowe. Te wartości liczbowe nazywane są indeksami. Te indeksy są używane do rysowania siatek w WebGL.
Note - Podobnie jak wierzchołki, przechowujemy indeksy za pomocą tablic JavaScript i przekazujemy je do potoku renderującego WebGL za pomocą bufora indeksów.
Tablice
W przeciwieństwie do OpenGL i JoGL, w WebGL nie ma predefiniowanych metod bezpośredniego renderowania wierzchołków. Musimy je przechowywać ręcznie za pomocą tablic JavaScript.
Przykład
var vertices = [ 0.5, 0.5, 0.1,-0.5, 0.5,-0.5]
Bufory
Bufory to obszary pamięci WebGL, które przechowują dane. Istnieją różne bufory, a mianowicie bufor rysowania, bufor ramki, bufor vetex i bufor indeksu. Plikvertex buffer i index buffer służą do opisu i przetwarzania geometrii modelu.
Obiekty bufora wierzchołków przechowują dane o wierzchołkach, podczas gdy obiekty bufora indeksów przechowują dane o indeksach. Po zapisaniu wierzchołków w tablicach, przekazujemy je do potoku graficznego WegGL za pomocą tych obiektów Buffer.
Frame bufferto część pamięci graficznej, która przechowuje dane sceny. Ten bufor zawiera szczegóły, takie jak szerokość i wysokość powierzchni (w pikselach), kolor każdego piksela, głębokość i bufory szablonów.
Siatka
Aby rysować obiekty 2D lub 3D, interfejs API WebGL udostępnia dwie metody, a mianowicie: drawArrays() i drawElements(). Te dwie metody akceptują parametr o nazwiemodeza pomocą którego możesz wybrać obiekt, który chcesz narysować. Opcje dostępne w tym polu są ograniczone do punktów, linii i trójkątów.
Aby narysować obiekt 3D za pomocą tych dwóch metod, musimy skonstruować jeden lub więcej prymitywnych wielokątów za pomocą punktów, linii lub trójkątów. Następnie, używając tych prymitywnych wielokątów, możemy utworzyć siatkę.
Obiekt 3D narysowany przy użyciu prymitywnych wielokątów nazywany jest a mesh. WebGL oferuje kilka sposobów rysowania obiektów graficznych 3D, jednak użytkownicy zwykle wolą rysować siatkę.
Przykład
W poniższym przykładzie możesz zauważyć, że narysowaliśmy kwadrat za pomocą dwóch trójkątów → {1, 2, 3} i {4, 1, 3}.
Programy shaderów
Zwykle do tworzenia siatek używamy trójkątów. Ponieważ WebGL używa obliczeń przyspieszanych przez GPU, informacje o tych trójkątach powinny być przesyłane z CPU do GPU, co wymaga dużego obciążenia komunikacyjnego.
WebGL zapewnia rozwiązanie zmniejszające narzut komunikacyjny. Ponieważ używa ES SL (Embedded System Shader Language), który działa na GPU, piszemy wszystkie wymagane programy do rysowania elementów graficznych w systemie klienta za pomocąshader programs (programy, które piszemy w języku OpenGL ES Shading Language / GLSL).
Te shadery to programy dla GPU, a językiem używanym do pisania programów shaderowych jest GLSL. W tych modułach cieniujących dokładnie definiujemy, w jaki sposób wierzchołki, transformacje, materiały, światła i kamera współdziałają ze sobą, tworząc określony obraz.
Krótko mówiąc, jest to fragment, który implementuje algorytmy do pobierania pikseli dla siatki. Więcej o shaderach omówimy w dalszych rozdziałach. Istnieją dwa typy shaderów - Vertex Shader i Fragment Shader.
Vertex Shader
Vertext Shader to kod programu wywoływany na każdym wierzchołku. Służy do przekształcania (przenoszenia) geometrii (np. Trójkąta) z jednego miejsca w drugie. Obsługuje dane każdego wierzchołka (dane na wierzchołek), takie jak współrzędne wierzchołków, normalne, kolory i współrzędne tekstury.
w ES GLkod Vertex Shadera, programiści muszą zdefiniować atrybuty do obsługi danych. Te atrybuty wskazują na plikVertex Buffer Object napisane w JavaScript.
Następujące zadania można wykonać za pomocą Vertex Shaderów -
- Transformacja wierzchołków
- Normalna transformacja i normalizacja
- Generowanie współrzędnych tekstury
- Transformacja współrzędnych tekstury
- Lighting
- Aplikacja materiału kolorowego
Fragment Shader (Pixel Shader)
Siatka składa się z wielu trójkątów, a powierzchnia każdego z nich jest nazywana fragment. Fragment Shader to kod, który działa na wszystkich pikselach każdego fragmentu. Jest napisany, aby obliczyć i wypełnić kolor na poszczególnych pikselach .
Następujące zadania można wykonać za pomocą shaderów fragmentów -
- Operacje na wartościach interpolowanych
- Dostęp do tekstur
- Aplikacja tekstury
- Fog
- Suma kolorów
Zmienne OpenGL ES SL
Pełna forma OpenGL ES SLto język OpenGL Embedded System Shading Language. Aby obsłużyć dane w programach shaderów, ES SL udostępnia trzy typy zmiennych. Są następujące -
Attributes- Te zmienne przechowują wartości wejściowe programu Vertex Shader. Atrybuty wskazują na obiekty bufora wierzchołków, które zawierają dane dla każdego wierzchołka. Za każdym razem, gdy wywoływany jest Vertex Shader, atrybuty wskazują na VBO różnych wierzchołków.
Uniforms - Te zmienne przechowują dane wejściowe, które są wspólne zarówno dla Vertex Shaderów, jak i Fragment Shaderów, takie jak pozycja światła, współrzędne tekstury i kolor.
Varyings - Te zmienne są używane do przekazywania danych z Vertex Shadera do Fragment Shadera.
Mając tak wiele podstaw, przejdziemy teraz do omówienia potoku graficznego.
Aby renderować grafikę 3D, musimy wykonać sekwencję kroków. Te kroki są znane jakographics pipeline lub rendering pipeline. Poniższy diagram przedstawia potok graficzny WebGL.
W kolejnych sekcjach omówimy kolejno rolę każdego kroku w potoku.
JavaScript
Tworząc aplikacje WebGL, piszemy kod języka Shader, aby komunikować się z GPU. JavaScript służy do pisania kodu sterującego programu, który obejmuje następujące akcje -
Initialize WebGL - JavaScript jest używany do inicjalizacji kontekstu WebGL.
Create arrays - Tworzymy tablice JavaScript do przechowywania danych geometrii.
Buffer objects - Tworzymy obiekty buforowe (wierzchołek i indeks), przekazując tablice jako parametry.
Shaders - Tworzymy, kompilujemy i łączymy shadery za pomocą JavaScript.
Attributes - Możemy tworzyć atrybuty, włączać je i kojarzyć z obiektami buforowymi za pomocą JavaScript.
Uniforms - Stroje możemy również skojarzyć za pomocą JavaScript.
Transformation matrix - Wykorzystując JavaScript możemy stworzyć macierz transformacji.
Początkowo tworzymy dane dla wymaganej geometrii i przekazujemy je do shaderów w postaci buforów. Zmienna atrybutu języka modułu cieniującego wskazuje na obiekty bufora, które są przekazywane jako dane wejściowe do modułu cieniującego wierzchołków.
Vertex Shader
Kiedy zaczynamy proces renderowania od wywołania metod drawElements() i drawArray(), Vertex Shader jest wykonywany dla każdego wierzchołka znajdującego się w obiekcie bufora wierzchołków. Oblicza położenie każdego wierzchołka prymitywnego wielokąta i zapisuje go w zmiennejgl_position. Oblicza również inne atrybuty, takie jakcolor, texture coordinates, i vertices które są zwykle skojarzone z wierzchołkiem.
Zgromadzenie prymitywne
Po obliczeniu pozycji i innych szczegółów każdego wierzchołka, następnym etapem jest primitive assembly stage. Tutaj trójkąty są składane i przekazywane do rasteryzatora.
Rasteryzacja
Na etapie rasteryzacji określa się piksele w ostatecznym obrazie prymitywu. Ma dwa kroki -
Culling- Na początku ustala się orientację wielokąta (czy jest skierowana do przodu czy do tyłu?). Wszystkie te trójkąty o niewłaściwej orientacji, które nie są widoczne w polu widzenia, są odrzucane. Ten proces nazywa się ubojem.
Clipping- Jeśli trójkąt znajduje się częściowo poza obszarem widoku, część poza obszarem widoku jest usuwana. Ten proces jest nazywany obcinaniem.
Fragment Shader
Dostaje Fragment Shader
- dane z Vertex Shadera w różnych zmiennych,
- prymitywy z etapu rasteryzacji, a następnie
- oblicza wartości kolorów dla każdego piksela między wierzchołkami.
Fragment Shader przechowuje wartości kolorów każdego piksela w każdym fragmencie. Dostęp do tych wartości kolorów można uzyskać podczas operacji na fragmentach, które omówimy dalej.
Operacje na fragmentach
Operacje na fragmentach są wykonywane po określeniu koloru każdego piksela w prymitywie. Te operacje fragmentaryczne mogą obejmować:
- Depth
- Mieszanka kolorów w buforze
- Dithering
Po przetworzeniu wszystkich fragmentów powstaje obraz 2D i wyświetlany na ekranie. Plikframe buffer to ostateczne miejsce docelowe potoku renderowania.
Bufor ramek
Bufor ramek to część pamięci graficznej, która zawiera dane sceny. Ten bufor zawiera szczegóły, takie jak szerokość i wysokość powierzchni (w pikselach), kolor każdego piksela oraz głębokość i bufory wzornika.
Omówiliśmy podstawy WebGL i potoku WebGL (procedura stosowana do renderowania aplikacji graficznych). W tym rozdziale weźmiemy przykładową aplikację do tworzenia trójkąta za pomocą WebGL i przyjrzymy się krokom wykonywanym w aplikacji.
Struktura aplikacji WebGL
Kod aplikacji WebGL to połączenie JavaScript i OpenGL Shader Language.
- Do komunikacji z procesorem wymagany jest JavaScript
- Do komunikacji z GPU wymagany jest język OpenGL Shader.
Przykładowa aplikacja
Weźmy teraz prosty przykład, aby dowiedzieć się, jak używać WebGL do rysowania prostego trójkąta ze współrzędnymi 2D.
<!doctype html>
<html>
<body>
<canvas width = "300" height = "300" id = "my_Canvas"></canvas>
<script>
/* Step1: Prepare the canvas and get WebGL context */
var canvas = document.getElementById('my_Canvas');
var gl = canvas.getContext('experimental-webgl');
/* Step2: Define the geometry and store it in buffer objects */
var vertices = [-0.5, 0.5, -0.5, -0.5, 0.0, -0.5,];
// Create a new buffer object
var vertex_buffer = gl.createBuffer();
// Bind an empty array buffer to it
gl.bindBuffer(gl.ARRAY_BUFFER, vertex_buffer);
// Pass the vertices data to the buffer
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertices), gl.STATIC_DRAW);
// Unbind the buffer
gl.bindBuffer(gl.ARRAY_BUFFER, null);
/* Step3: Create and compile Shader programs */
// Vertex shader source code
var vertCode =
'attribute vec2 coordinates;' +
'void main(void) {' + ' gl_Position = vec4(coordinates,0.0, 1.0);' + '}';
//Create a vertex shader object
var vertShader = gl.createShader(gl.VERTEX_SHADER);
//Attach vertex shader source code
gl.shaderSource(vertShader, vertCode);
//Compile the vertex shader
gl.compileShader(vertShader);
//Fragment shader source code
var fragCode = 'void main(void) {' + 'gl_FragColor = vec4(0.0, 0.0, 0.0, 0.1);' + '}';
// Create fragment shader object
var fragShader = gl.createShader(gl.FRAGMENT_SHADER);
// Attach fragment shader source code
gl.shaderSource(fragShader, fragCode);
// Compile the fragment shader
gl.compileShader(fragShader);
// Create a shader program object to store combined shader program
var shaderProgram = gl.createProgram();
// Attach a vertex shader
gl.attachShader(shaderProgram, vertShader);
// Attach a fragment shader
gl.attachShader(shaderProgram, fragShader);
// Link both programs
gl.linkProgram(shaderProgram);
// Use the combined shader program object
gl.useProgram(shaderProgram);
/* Step 4: Associate the shader programs to buffer objects */
//Bind vertex buffer object
gl.bindBuffer(gl.ARRAY_BUFFER, vertex_buffer);
//Get the attribute location
var coord = gl.getAttribLocation(shaderProgram, "coordinates");
//point an attribute to the currently bound VBO
gl.vertexAttribPointer(coord, 2, gl.FLOAT, false, 0, 0);
//Enable the attribute
gl.enableVertexAttribArray(coord);
/* Step5: Drawing the required object (triangle) */
// Clear the canvas
gl.clearColor(0.5, 0.5, 0.5, 0.9);
// Enable the depth test
gl.enable(gl.DEPTH_TEST);
// Clear the color buffer bit
gl.clear(gl.COLOR_BUFFER_BIT);
// Set the view port
gl.viewport(0,0,canvas.width,canvas.height);
// Draw the triangle
gl.drawArrays(gl.TRIANGLES, 0, 3);
</script>
</body>
</html>
To da następujący wynik -
Jeśli uważnie przyjrzysz się powyższemu programowi, wykonaliśmy pięć kolejnych kroków, aby narysować prosty trójkąt za pomocą WebGL. Kroki są następujące -
Step 1 − Prepare the canvas and get WebGL rendering context
Uzyskujemy aktualny obiekt płótna HTML i jego kontekst renderowania WebGL.
Step 2 − Define the geometry and store it in buffer objects
Definiujemy atrybuty geometrii, takie jak wierzchołki, indeksy, kolor itp. I przechowujemy je w tablicach JavaScript. Następnie tworzymy jeden lub więcej obiektów buforowych i przekazujemy tablice zawierające dane do odpowiedniego obiektu bufora. W tym przykładzie przechowujemy wierzchołki trójkąta w tablicy JavaScript i przekazujemy tę tablicę do obiektu bufora wierzchołków.
Step 3 − Create and compile Shader programs
Piszemy programy Vertex Shader i Fragment Shader, kompilujemy je i tworzymy połączony program, łącząc te dwa programy.
Step 4 − Associate the shader programs with buffer objects
Powiązujemy obiekty bufora i połączony program cieniujący.
Step 5 − Drawing the required object (triangle)
Ten krok obejmuje operacje takie jak wyczyszczenie koloru, wyczyszczenie bitu bufora, włączenie testu głębi, ustawienie portu widoku itp. Na koniec musisz narysować wymagane prymitywy za pomocą jednej z metod - drawArrays() lub drawElements().
Wszystkie te kroki wyjaśniono dalej w tym samouczku.
Aby napisać aplikację WebGL, pierwszym krokiem jest pobranie obiektu kontekstu renderowania WebGL. Ten obiekt współdziała z buforem rysowania WebGL i może wywoływać wszystkie metody WebGL. Aby uzyskać kontekst WebGL, wykonywane są następujące operacje -
- Utwórz płótno HTML-5
- Uzyskaj identyfikator kanwy
- Uzyskaj WebGL
Tworzenie elementu Canvas HTML-5
W rozdziale 5 omówiliśmy, jak utworzyć element canvas HTML-5. W treści dokumentu HTML-5 napisz kanwę, nadaj jej nazwę i przekaż jako parametr do atrybutu id. Możesz zdefiniować wymiary płótna za pomocą atrybutów szerokości i wysokości (opcjonalnie).
Przykład
Poniższy przykład pokazuje, jak stworzyć element canvas o wymiarach 500 × 500. Utworzyliśmy obramowanie płótna za pomocą CSS dla widoczności. Skopiuj i wklej następujący kod w pliku o nazwiemy_canvas.html.
<!DOCTYPE HTML>
<html>
<head>
<style>
#mycanvas{border:1px solid blue;}
</style>
</head>
<body>
<canvas id = "mycanvas" width = "300" height = "300"></canvas>
</body>
</html>
To da następujący wynik -
Uzyskaj identyfikator Canvas
Po utworzeniu płótna musisz pobrać kontekst WebGL. Pierwszą rzeczą do zrobienia w celu uzyskania kontekstu rysunkowego WebGL jest pobranie identyfikatora bieżącego elementu canvas.
Identyfikator kanwy uzyskuje się przez wywołanie metody DOM (Document Object Model) getElementById(). Ta metoda przyjmuje wartość ciągu jako parametr, więc przekazujemy do niej nazwę bieżącej kanwy.
Na przykład, jeśli nazwa obszaru roboczego to my_canvas, to identyfikator płótna jest uzyskiwany, jak pokazano poniżej -
var canvas = document.getElementById('my_Canvas');
Pobierz kontekst rysowania WebGL
Aby uzyskać obiekt WebGLRenderingContext (lub obiekt kontekstu rysunku WebGL lub po prostu kontekst WebGL), wywołaj getContext() metoda prądu HTMLCanvasElement. Składnia metody getContext () jest następująca -
canvas.getContext(contextType, contextAttributes);
Podaj struny webgl lub experimental-webgl jako contentType. PlikcontextAttributesparametr jest opcjonalny. (Kontynuując ten krok, upewnij się, że Twoja przeglądarka obsługuje technologię WebGL w wersji 1 (OpenGL ES 2.0)).
Poniższy fragment kodu pokazuje, jak uzyskać kontekst renderowania WebGL. Tutajgl jest zmienną odniesienia do uzyskanego obiektu kontekstu.
var canvas = document.getElementById('my_Canvas');
var gl = canvas.getContext('experimental-webgl');
WebGLContextAttributes
Parametr WebGLContextAttributesnie jest obowiązkowe. Ten parametr udostępnia różne opcje, które akceptują wartości logiczne wymienione poniżej -
Sr.No. | Atrybuty i opis |
---|---|
1 | Alpha Jeśli jego wartość jest prawdziwa, zapewnia bufor alfa do obszaru roboczego. Domyślnie jego wartość to true. |
2 | depth Jeśli jego wartość jest prawdziwa, otrzymasz bufor rysowania, który zawiera bufor głębi co najmniej 16 bitów. Domyślnie jego wartość to true. |
3 | stencil Jeśli jego wartość jest prawdziwa, otrzymasz bufor rysunkowy, który zawiera bufor szablonu o co najmniej 8 bitach. Domyślnie jego wartość to false. |
4 | antialias Jeśli jego wartość jest prawdziwa, otrzymasz bufor rysowania, który wykonuje wygładzanie. Domyślnie jego wartość to true. |
5 | premultipliedAlpha Jeśli jego wartość jest prawdziwa, otrzymasz bufor rysunkowy, który zawiera kolory ze wstępnie pomnożoną alfa. Domyślnie jego wartość to true. |
6 | preserveDrawingBuffer Jeśli jego wartość jest prawdziwa, bufory nie zostaną wyczyszczone i zachowają swoje wartości, dopóki nie zostaną wyczyszczone lub nadpisane przez autora. Domyślnie jego wartość to false. |
Poniższy fragment kodu pokazuje, jak utworzyć kontekst WebGL z buforem wzornika, który nie będzie działać anti-aliasing.
var canvas = document.getElementById('canvas1');
var context = canvas.getContext('webgl', { antialias: false, stencil: true });
W czasie tworzenia WebGLRenderingContext tworzony jest bufor rysunkowy. Obiekt Context zarządza stanem OpenGL i renderuje do bufora rysunkowego.
WebGLRenderingContext
Jest to główny interfejs w WebGL. Reprezentuje kontekst rysowania WebGL. Ten interfejs zawiera wszystkie metody używane do wykonywania różnych zadań w buforze rysunku. Atrybuty tego interfejsu podano w poniższej tabeli.
Sr.No. | Atrybuty i opis |
---|---|
1 | Canvas To jest odniesienie do elementu canvas, który utworzył ten kontekst. |
2 | drawingBufferWidth Ten atrybut reprezentuje rzeczywistą szerokość bufora rysunkowego. Może się różnić od atrybutu szerokości elementu HTMLCanvasElement. |
3 | drawingBufferHeight Ten atrybut reprezentuje rzeczywistą wysokość bufora rysunkowego. Może się różnić od atrybutu wysokości HTMLCanvasElement. |
Po uzyskaniu kontekstu WebGL musisz zdefiniować geometrię prymitywu (obiekt, który chcesz narysować) i zapisać go. W WebGL definiujemy szczegóły geometrii - na przykład wierzchołki, indeksy, kolor prymitywu - za pomocą tablic JavaScript. Aby przekazać te szczegóły do programów shaderowych, musimy utworzyć obiekty buforów i przechowywać (dołączać) tablice JavaScript zawierające dane w odpowiednich buforach.
Note: Później te obiekty bufora zostaną powiązane z atrybutami programu cieniującego (Vertex Shader).
Definiowanie wymaganej geometrii
Model 2D lub 3D narysowany za pomocą wierzchołków nazywa się a mesh. Każdy aspekt siatki nazywany jest apolygon a wielokąt składa się z 3 lub więcej wierzchołków.
Aby narysować modele w kontekście renderowania WebGL, musisz zdefiniować wierzchołki i indeksy za pomocą tablic JavaScript. Na przykład, jeśli chcemy utworzyć trójkąt, który leży na współrzędnych {(5,5), (-5,5), (-5, -5)}, jak pokazano na diagramie, możesz utworzyć tablicę dla wierzchołki jako -
var vertices = [
0.5,0.5, //Vertex 1
0.5,-0.5, //Vertex 2
-0.5,-0.5, //Vertex 3
];
Podobnie możesz utworzyć tablicę indeksów. Indeksy dla powyższych wskaźników trójkąta będą [0, 1, 2] i można je zdefiniować jako -
var indices = [ 0,1,2 ]
Aby lepiej zrozumieć indeksy, rozważ bardziej złożone modele, takie jak kwadrat. Możemy przedstawić kwadrat jako zestaw dwóch trójkątów. Jeśli (0,3,1) i (3,1,2) to dwa trójkąty, za pomocą których zamierzamy narysować kwadrat, to indeksy zostaną zdefiniowane jako -
var indices = [0,3,1,3,1,2];
Note -
Do rysowania prymitywów WebGL udostępnia dwie następujące metody -
drawArrays() - Używając tej metody, przekazujemy wierzchołki prymitywu za pomocą tablic JavaScript.
drawElements() - Używając tej metody, przekazujemy zarówno wierzchołki, jak i indeksy prymitywu za pomocą tablicy JavaScript.
Obiekty buforowe
Obiekt bufora to mechanizm udostępniany przez WebGL, który wskazuje obszar pamięci przydzielony w systemie. W tych obiektach buforowych możesz przechowywać dane modelu, który chcesz narysować, odpowiadające wierzchołkom, indeksom, kolorowi itp.
Korzystając z tych obiektów buforowych, można przekazać wiele danych do programu modułu cieniującego (modułu cieniującego wierzchołków) za pośrednictwem jednej z jego zmiennych atrybutów. Ponieważ te obiekty buforowe znajdują się w pamięci GPU, można je renderować bezpośrednio, co z kolei poprawia wydajność.
Do przetwarzania geometrii służą dwa typy obiektów buforów. Oni są -
Vertex buffer object (VBO)- Przechowuje dane dla każdego wierzchołka modelu graficznego, który ma być renderowany. Używamy obiektów bufora wierzchołków w WebGL do przechowywania i przetwarzania danych dotyczących wierzchołków, takich jak współrzędne wierzchołków, normalne, kolory i współrzędne tekstury.
Index buffer objects (IBO) - Przechowuje indeksy (dane indeksowe) modelu graficznego, który ma być renderowany.
Po zdefiniowaniu wymaganej geometrii i zapisaniu ich w tablicach JavaScript, musisz przekazać te tablice do obiektów buforowych, skąd dane zostaną przekazane do programów shaderowych. Aby przechowywać dane w buforach, należy wykonać następujące kroki.
Utwórz pusty bufor.
Powiąż odpowiedni obiekt tablicy z pustym buforem.
Przekaż dane (wierzchołki / indeksy) do bufora przy użyciu jednego z typed arrays.
Rozwiń bufor (opcjonalnie).
Tworzenie bufora
Aby utworzyć pusty obiekt bufora, WebGL udostępnia metodę o nazwie createBuffer(). Ta metoda zwraca nowo utworzony obiekt bufora, jeśli tworzenie się powiodło; w przeciwnym razie zwraca wartość null w przypadku niepowodzenia.
WebGL działa jako maszyna stanów. Po utworzeniu bufora każda kolejna operacja buforowa będzie wykonywana na bieżącym buforze, dopóki go nie odłączymy. Użyj następującego kodu, aby utworzyć bufor -
var vertex_buffer = gl.createBuffer();
Note - gl jest zmienną odniesienia do bieżącego kontekstu WebGL.
Bind the Buffer
Po utworzeniu pustego obiektu bufora należy powiązać z nim odpowiedni bufor tablicy (cel). WebGL udostępnia metodę o nazwiebindBuffer() w tym celu.
Składnia
Składnia bindBuffer() metoda jest następująca -
void bindBuffer (enum target, Object buffer)
Ta metoda akceptuje dwa parametry i zostały one omówione poniżej.
target- Pierwsza zmienna to wartość wyliczeniowa reprezentująca typ bufora, który chcemy powiązać z pustym buforem. Masz dwie wstępnie zdefiniowane wartości wyliczenia jako opcje tego parametru. Oni są -
ARRAY_BUFFER który reprezentuje dane wierzchołków.
ELEMENT_ARRAY_BUFFER który reprezentuje dane indeksu.
Object buffer- Druga to zmienna odniesienia do obiektu bufora utworzonego w poprzednim kroku. Zmienna odniesienia może być obiektem bufora wierzchołków lub obiektem bufora indeksu.
Przykład
Poniższy fragment kodu pokazuje, jak używać metody bindBuffer ().
//vertex buffer
var vertex_buffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, vertex_buffer);
//Index buffer
var Index_Buffer = gl.createBuffer();
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, index_buffer);
Przekazywanie danych do bufora
Następnym krokiem jest przekazanie danych (wierzchołków / indeksów) do bufora. Do tej pory dane są w postaci tablicy i przed przekazaniem ich do bufora należy je opakować w jedną z tablic wpisanych w WebGL. WebGL udostępnia metodę o nazwiebufferData() w tym celu.
Składnia
Składnia metody bufferData () jest następująca -
void bufferData (enum target, Object data, enum usage)
Ta metoda przyjmuje trzy parametry i zostały one omówione poniżej -
target - Pierwszym parametrem jest wartość wyliczenia reprezentująca typ używanego przez nas bufora tablicy. Opcje tego parametru to -
ARRAY_BUFFER które reprezentuje vertex data.
ELEMENT_ARRAY_BUFFER które reprezentuje index data.
Object data- Drugim parametrem jest wartość obiektu zawierająca dane do zapisania w obiekcie bufora. Tutaj musimy przekazać dane za pomocątyped arrays.
Usage- Trzecim parametrem tej metody jest zmienna wyliczeniowa, która określa, jak używać danych obiektu bufora (przechowywanych danych) do rysowania kształtów. Istnieją trzy opcje tego parametru, wymienione poniżej.
gl.STATIC_DRAW - Dane zostaną określone raz i użyte wielokrotnie.
gl.STREAM_DRAW - Dane zostaną określone raz i użyte kilka razy.
gl.DYNAMIC_DRAW - Dane będą określane wielokrotnie i wielokrotnie używane.
Przykład
Poniższy fragment kodu pokazuje, jak używać bufferData()metoda. Załóżmy, że wierzchołki i indeksy to tablice zawierające odpowiednio dane wierzchołków i indeksów.
//vertex buffer
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertices), gl.STATIC_DRAW);
//Index buffer
gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new Uint16Array(indices), gl.STATIC_DRAW);
Tablice typowane
WebGL udostępnia specjalny typ tablicy o nazwie typed arraysdo przesyłania elementów danych, takich jak wierzchołek indeksu i tekstura. Te tablice o określonych typach przechowują duże ilości danych i przetwarzają je w natywnym formacie binarnym, co zapewnia lepszą wydajność. Typowane tablice używane przez WebGL to Int8Array, Uint8Array, Int16Array, Uint16Array, Int32Array, UInt32Array, Float32Array i Float64Array.
Note
Ogólnie do przechowywania danych wierzchołków używamy Float32Array; a do przechowywania danych indeksowych używamyUint16Array.
Możesz tworzyć tablice typowane, tak jak tablice JavaScript, używając new słowo kluczowe.
Rozłącz bufory
Zaleca się rozpinanie buforów po ich użyciu. Można to zrobić, przekazując wartość null w miejsce obiektu bufora, jak pokazano poniżej.
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, null);
WebGL udostępnia następujące metody wykonywania operacji buforowych -
Sr.No. | Metody i opis |
---|---|
1 | unieważnić bindBuffer( cel wyliczenia , bufor obiektu ) cel - ARRAY_BUFFER, ELEMENT_ARRAY_BUFFER |
2 | unieważnić bufferData(wyliczenie docelowe , długi rozmiar , użycie wyliczenia ) cel - ARRAY_BUFFER, ELEMENT_ARRAY_BUFFER wykorzystanie - STATIC_DRAW, STREAM_DRAW, DYNAMIC_DRAW |
3 | unieważnić bufferData(wyliczenie docelowe , dane obiektu , użycie wyliczenia ) cel i użycie - to samo, co w przypadkubufferData powyżej |
4 | unieważnić bufferSubData(wyliczenie docelowe , długie przesunięcie , dane obiektu ) cel - ARRAY_BUFFER, ELEMENT_ARRAY_BUFFER |
5 | Obiekt createBuffer() |
6 | unieważnić deleteBuffer( Bufor obiektu ) |
7 | każdy getBufferParameter(enum target , enum pname ) cel - ARRAY_BUFFER, ELEMENT_ ARRAY_BUFFER PNAME - BUFFER_SIZE, BUFFER_USAGE |
8 | bool isBuffer( Bufor obiektu ) |
Shadery to programy działające na GPU. Shadery są napisane w języku OpenGL ES Shader Language (znanym jako ES SL). ES SL ma własne zmienne, typy danych, kwalifikatory, wbudowane wejścia i wyjścia.
Typy danych
Poniższa tabela zawiera listę podstawowych typów danych udostępnianych przez OpenGL ES SL.
Sr.No. | Typ i opis |
---|---|
1 | void Reprezentuje pustą wartość. |
2 | bool Akceptuje prawdę lub fałsz. |
3 | int To jest typ danych typu integer ze znakiem. |
4 | float To jest zmienny skalarny typ danych. |
5 | vec2, vec3, vec4 n-składnikowy wektor zmiennoprzecinkowy |
6 | bvec2, bvec3, bvec4 Wektor logiczny |
7 | ivec2, ivec3, ivec4 wektor całkowity ze znakiem |
8 | mat2, mat3, mat4 Matryca pływakowa 2x2, 3x3, 4x4 |
9 | sampler2D Uzyskaj dostęp do tekstury 2D |
10 | samplerCube Kostka dostępu odwzorowana na tekstury |
Kwalifikatory
W OpenGL ES SL istnieją trzy główne kwalifikatory -
Sr.No. | Kwalifikator i opis |
---|---|
1 | attribute Ten kwalifikator działa jako łącze między Vertex Shader i OpenGL ES dla danych na wierzchołek. Wartość tego atrybutu zmienia się przy każdym wykonaniu Vertex Shadera. |
2 | uniform Ten kwalifikator łączy programy cieniujące i aplikację WebGL. W przeciwieństwie do kwalifikatora atrybutu wartości mundurów nie zmieniają się. Mundury są tylko do odczytu; możesz ich używać z dowolnymi podstawowymi typami danych, aby zadeklarować zmienną. Example - mundur vec4 lightPosition; |
3 | varying Ten kwalifikator tworzy łącze między Vertex Shader i Fragment Shader dla danych interpolowanych. Może być używany z następującymi typami danych - float, vec2, vec3, vec4, mat2, mat3, mat4 lub arrays. Example - różny vec3 normalna; |
Vertex Shader
Vertex Shader to kod programu, który jest wywoływany w każdym wierzchołku. Przekształca (przesuwa) geometrię (np. Trójkąt) z jednego miejsca w drugie. Obsługuje dane każdego wierzchołka (dane na wierzchołek), takie jak współrzędne wierzchołków, normalne, kolory i współrzędne tekstury.
W kodzie ES GL Vertex Shadera programiści muszą zdefiniować atrybuty do obsługi danych. Te atrybuty wskazują na obiekt Vertex Buffer napisany w JavaScript. Następujące zadania można wykonać za pomocą Vertex Shaderów wraz z transformacją wierzchołków -
- Transformacja wierzchołków
- Normalna transformacja i normalizacja
- Generowanie współrzędnych tekstury
- Transformacja współrzędnych tekstury
- Lighting
- Aplikacja materiału kolorowego
Predefiniowane zmienne
OpenGL ES SL udostępnia następujące predefiniowane zmienne dla Vertex Shader -
Sr.No. | Zmienne i opis |
---|---|
1 | highp vec4 gl_Position; Utrzymuje pozycję wierzchołka. |
2 | mediump float gl_PointSize; Przechowuje przekształcony rozmiar w punktach. Jednostkami tej zmiennej są piksele. |
Przykładowy kod
Spójrz na poniższy przykładowy kod Vertex Shader. Przetwarza wierzchołki trójkąta.
attribute vec2 coordinates;
void main(void) {
gl_Position = vec4(coordinates, 0.0, 1.0);
};
Jeśli uważnie obserwujesz powyższy kod, zadeklarowaliśmy zmienną atrybutów o nazwie coordinates. (Ta zmienna zostanie powiązana z obiektem Vertex Buffer przy użyciu metodygetAttribLocation(). Atrybutcoordinates jest przekazywany jako parametr do tej metody wraz z obiektem programu modułu cieniującego).
W drugim kroku danego programu Vertex Shader gl_position zmienna jest zdefiniowana.
gl_Position
gl_Position to predefiniowana zmienna, która jest dostępna tylko w programie Vertex Shader. Zawiera pozycję wierzchołka. W powyższym kodziecoordinatesatrybut jest przekazywany w postaci wektora. Ponieważ Vertex Shader jest operacją dla każdego wierzchołka, wartość gl_position jest obliczana dla każdego wierzchołka.
Później wartość gl_position jest używana przez prymitywny montaż, obcinanie, usuwanie i inne operacje o ustalonej funkcjonalności, które działają na elementach pierwotnych po zakończeniu przetwarzania wierzchołków.
Możemy napisać programy Vertex Shader dla wszystkich możliwych operacji Vertex Shadera, które omówimy indywidualnie w tym samouczku.
Fragment Shader
ZA mesh składa się z wielu trójkątów, a powierzchnia każdego trójkąta jest nazywana a fragment. Fragment Shader to kod, który działa na każdym pikselu każdego fragmentu. Jest to napisane w celu obliczenia i wypełnienia koloru na poszczególnych pikselach. Następujące zadania można wykonać za pomocą Fragment Shaderów -
- Operacje na wartościach interpolowanych
- Dostęp do tekstur
- Aplikacja tekstury
- Fog
- Suma kolorów
Predefiniowane zmienne
OpenGL ES SL zapewnia następujące predefiniowane zmienne dla Fragment Shadera -
Sr.No. | Zmienne i opis |
---|---|
1 | mediump vec4 gl_FragCoord; Utrzymuje pozycję fragmentu w buforze ramki. |
2 | bool gl_FrontFacing; Zawiera fragment należący do prymitywu skierowanego do przodu. |
3 | mediump vec2 gl_PointCoord; Utrzymuje pozycję fragmentu w punkcie (tylko rasteryzacja punktów). |
4 | mediump vec4 gl_FragColor; Przechowuje wyjściową wartość koloru fragmentu modułu cieniującego |
5 | mediump vec4 gl_FragData[n] Utrzymuje kolor fragmentu do mocowania koloru n. |
Przykładowy kod
Poniższy przykładowy kod modułu cieniującego fragmenty pokazuje, jak zastosować kolor do każdego piksela w trójkącie.
void main(void) {
gl_FragColor = vec4(0, 0.8, 0, 1);
}
W powyższym kodzie colorwartość jest przechowywana w zmiennej gl.FragColor
. Program Fragment Shader przekazuje dane wyjściowe do potoku przy użyciu stałych zmiennych funkcyjnych; FragColor jest jednym z nich. Ta zmienna przechowuje wartość koloru pikseli modelu.
Przechowywanie i kompilowanie programów Shader
Ponieważ shadery są niezależnymi programami, możemy napisać je jako osobny skrypt i używać w aplikacji. Możesz też przechowywać je bezpośrednio wstring format, jak pokazano poniżej.
var vertCode =
'attribute vec2 coordinates;' +
'void main(void) {' +
' gl_Position = vec4(coordinates, 0.0, 1.0);' +
'}';
Kompilowanie modułu cieniującego
Kompilacja obejmuje trzy kroki -
- Tworzenie obiektu modułu cieniującego
- Dołączanie kodu źródłowego do utworzonego obiektu modułu cieniującego
- Kompilowanie programu
Tworzenie Vertex Shader
Aby utworzyć pusty moduł cieniujący, WebGL udostępnia metodę o nazwie createShader(). Tworzy i zwraca obiekt modułu cieniującego. Jego składnia jest następująca -
Object createShader (enum type)
Jak zauważono w składni, ta metoda akceptuje wstępnie zdefiniowaną wartość wyliczenia jako parametr. Mamy na to dwie opcje -
gl.VERTEX_SHADER do tworzenia Vertex Shader
gl.FRAGMENT_SHADER do tworzenia Fragment Shadera.
Podłączanie źródła do modułu cieniującego
Możesz dołączyć kod źródłowy do utworzonego obiektu modułu cieniującego przy użyciu metody shaderSource(). Jego składnia jest następująca -
void shaderSource(Object shader, string source)
Ta metoda akceptuje dwa parametry -
shader - Musisz przekazać utworzony obiekt modułu cieniującego jako jeden parametr.
Source - Musisz przekazać kod programu modułu cieniującego w formacie łańcucha.
Kompilowanie programu
Aby skompilować program, musisz użyć metody compileShader(). Jego składnia jest następująca -
compileShader(Object shader)
Ta metoda przyjmuje obiekt programu modułu cieniującego jako parametr. Po utworzeniu obiektu programu cieniującego dołącz do niego kod źródłowy i przekaż ten obiekt do tej metody.
Poniższy fragment kodu pokazuje, jak utworzyć i skompilować Vertex Shader, a także Fragment Shader w celu utworzenia trójkąta.
// Vertex Shader
var vertCode =
'attribute vec3 coordinates;' +
'void main(void) {' +
' gl_Position = vec4(coordinates, 1.0);' +
'}';
var vertShader = gl.createShader(gl.VERTEX_SHADER);
gl.shaderSource(vertShader, vertCode);
gl.compileShader(vertShader);
// Fragment Shader
var fragCode =
'void main(void) {' +
' gl_FragColor = vec4(0, 0.8, 0, 1);' +
'}';
var fragShader = gl.createShader(gl.FRAGMENT_SHADER);
gl.shaderSource(fragShader, fragCode);
gl.compileShader(fragShader);
Program łączony
Po utworzeniu i skompilowaniu obu programów do cieniowania należy utworzyć połączony program zawierający oba moduły cieniujące (wierzchołek i fragment). Należy wykonać następujące kroki -
- Utwórz obiekt programu
- Dołącz oba shadery
- Połącz oba shadery
- Skorzystaj z programu
Utwórz obiekt programu
Utwórz obiekt programu przy użyciu metody createProgram(). Zwróci pusty obiekt programu. Oto jego składnia -
createProgram();
Dołącz shadery
Dołącz moduły cieniujące do utworzonego obiektu programu przy użyciu metody attachShader(). Jego składnia jest następująca -
attachShader(Object program, Object shader);
Ta metoda akceptuje dwa parametry -
Program - Przekaż utworzony pusty obiekt programu jako jeden parametr.
Shader - Przekaż jeden ze skompilowanych programów shaderów (Vertex Shader, Fragment Shader)
Note - Musisz dołączyć oba shadery za pomocą tej metody.
Połącz Shadery
Połącz shadery za pomocą metody linkProgram(), przekazując obiekt programu, do którego dołączyłeś shadery. Jego składnia jest następująca -
linkProgram(shaderProgram);
Skorzystaj z programu
WebGL udostępnia metodę o nazwie useProgram(). Musisz przekazać do niego połączony program. Jego składnia jest następująca -
useProgram(shaderProgram);
Poniższy fragment kodu pokazuje, jak tworzyć, łączyć i używać połączonego programu cieniującego.
var shaderProgram = gl.createProgram();
gl.attachShader(shaderProgram, vertShader);
gl.attachShader(shaderProgram, fragShader);
gl.linkProgram(shaderProgram);
gl.useProgram(shaderProgram);
Każdy atrybut w programie Vertex Shader wskazuje na obiekt bufora wierzchołków. Po utworzeniu obiektów bufora wierzchołków programiści muszą powiązać je z atrybutami programu Vertex Shader. Każdy atrybut wskazuje tylko jeden obiekt bufora wierzchołków, z którego wyodrębnia wartości danych, a następnie atrybuty te są przekazywane do programu modułu cieniującego.
Aby skojarzyć obiekty Vertex Buffer z atrybutami programu Vertex Shader, musisz wykonać kroki podane poniżej -
- Uzyskaj lokalizację atrybutu
- Wskaż atrybut na obiekt bufora wierzchołków
- Włącz atrybut
Uzyskaj lokalizację atrybutu
WebGL udostępnia metodę o nazwie getAttribLocation()która zwraca lokalizację atrybutu. Jego składnia jest następująca -
ulong getAttribLocation(Object program, string name)
Ta metoda akceptuje obiekt programu Vertex Shader i wartości atrybutów programu Vertex Shader.
Poniższy fragment kodu pokazuje, jak używać tej metody.
var coordinatesVar = gl.getAttribLocation(shader_program, "coordinates");
Tutaj, shader_program jest obiektem programu cieniującego, a coordinates jest atrybutem programu Vertex Shader.
Wskaż atrybut na VBO
Aby przypisać obiekt bufora do zmiennej atrybutu, WebGL udostępnia metodę o nazwie vertexAttribPointer(). Oto składnia tej metody -
void vertexAttribPointer(location, int size, enum type, bool normalized, long stride, long offset)
Ta metoda akceptuje sześć parametrów i zostały one omówione poniżej.
Location- Określa miejsce przechowywania zmiennej atrybutu. W ramach tej opcji musisz przekazać wartość zwracaną przezgetAttribLocation() metoda.
Size - Określa liczbę komponentów na wierzchołek w obiekcie bufora.
Type - Określa rodzaj danych.
Normalized- To jest wartość logiczna. Jeśli prawda, dane niepływające są normalizowane do [0, 1]; w innym przypadku jest znormalizowana do [-1, 1].
Stride - Określa liczbę bajtów między różnymi elementami danych wierzchołków lub zero dla domyślnego kroku.
Offset- Określa przesunięcie (w bajtach) w obiekcie buforu, aby wskazać, z którego bajtu są przechowywane dane wierzchołków. Jeśli dane są przechowywane od początku, przesunięcie wynosi 0.
Poniższy fragment pokazuje, jak używać vertexAttribPointer() w programie -
gl.vertexAttribPointer(coordinatesVar, 3, gl.FLOAT, false, 0, 0);
Włączanie atrybutu
Aktywuj atrybut Vertex Shader, aby uzyskać dostęp do obiektu bufora w Vertex Shader. Do tej operacji WebGL udostępniaenableVertexAttribArray()metoda. Ta metoda akceptuje lokalizację atrybutu jako parametr. Oto jak używać tej metody w programie -
gl.enableVertexAttribArray(coordinatesVar);
Po skojarzeniu buforów z modułami cieniującymi, ostatnim krokiem jest narysowanie wymaganych prymitywów. WebGL udostępnia dwie metody, a mianowicie:drawArrays() i drawElements() rysować modele.
drawArrays ()
drawArrays()jest metodą używaną do rysowania modeli za pomocą wierzchołków. Oto jego składnia -
void drawArrays(enum mode, int first, long count)
Ta metoda przyjmuje następujące trzy parametry -
mode- W WebGL modele są rysowane przy użyciu typów pierwotnych. Używając trybu, programiści muszą wybrać jeden z typów pierwotnych udostępnianych przez WebGL. Możliwe wartości tej opcji to - gl.POINTS, gl.LINE_STRIP, gl.LINE_LOOP, gl.LINES, gl.TRIANGLE_STRIP, gl.TRIANGLE_FAN i gl.TRIANGLES.
first- Ta opcja określa element początkowy we włączonych tablicach. Nie może to być wartość ujemna.
count - Ta opcja określa liczbę elementów do renderowania.
Jeśli rysujesz model za pomocą drawArrays() metoda, następnie WebGL podczas renderowania kształtów tworzy geometrię w kolejności, w jakiej zdefiniowane są współrzędne wierzchołków.
Przykład
Jeśli chcesz narysować pojedynczy trójkąt za pomocą drawArray() musisz przekazać trzy wierzchołki i wywołać metodę drawArrays() metoda, jak pokazano poniżej.
var vertices = [-0.5,-0.5, -0.25,0.5, 0.0,-0.5,];
gl.drawArrays(gl.TRIANGLES, 0, 3);
Utworzy trójkąt, jak pokazano poniżej.
Załóżmy, że chcesz narysować sąsiednie trójkąty, a następnie musisz przekazać kolejne trzy wierzchołki w buforze wierzchołków i podać liczbę elementów, które mają być renderowane jako 6.
var vertices = [-0.5,-0.5, -0.25,0.5, 0.0,-0.5, 0.0,-0.5, 0.25,0.5, 0.5,-0.5,];
gl.drawArrays(gl.TRIANGLES, 0, 6);
Utworzy ciągły trójkąt, jak pokazano poniżej.
drawElements ()
drawElements()to metoda używana do rysowania modeli za pomocą wierzchołków i indeksów. Jego składnia jest następująca -
void drawElements(enum mode, long count, enum type, long offset)
Ta metoda przyjmuje następujące cztery parametry -
mode- Modele WebGL są rysowane przy użyciu typów pierwotnych. Używając trybu, programiści muszą wybrać jeden z typów pierwotnych udostępnianych przez WebGL. Lista możliwych wartości dla tej opcji to - gl.POINTS, gl.LINE_STRIP, gl.LINE_LOOP, gl.LINES, gl.TRIANGLE_STRIP, gl.TRIANGLE_FAN i gl.TRIANGLES.
count - Ta opcja określa liczbę elementów do renderowania.
type - Ta opcja określa typ danych indeksów, które muszą być UNSIGNED_BYTE lub UNSIGNED_SHORT.
offset- Ta opcja określa punkt początkowy renderowania. Zwykle jest to pierwszy element (0).
Jeśli rysujesz model za pomocą drawElements()metoda, to wraz z obiektem bufora wierzchołków należy również utworzyć obiekt index buffer. Jeśli użyjesz tej metody, dane wierzchołków zostaną przetworzone raz i użyte tyle razy, ile wskazano w indeksach.
Przykład
Jeśli chcesz narysować pojedynczy trójkąt za pomocą indeksów, musisz przekazać indeksy wraz z wierzchołkami i wywołać metodę drawElements() metoda, jak pokazano poniżej.
var vertices = [ -0.5,-0.5,0.0, -0.25,0.5,0.0, 0.0,-0.5,0.0 ];
var indices = [0,1,2];
gl.drawElements(gl.TRIANGLES, indices.length, gl.UNSIGNED_SHORT,0);
Wytworzy następujący wynik -
Jeśli chcesz narysować zaraźliwe trójkąty za pomocą drawElements() po prostu dodaj pozostałe wierzchołki i wymień indeksy pozostałych wierzchołków.
var vertices = [
-0.5,-0.5,0.0,
-0.25,0.5,0.0,
0.0,-0.5,0.0,
0.25,0.5,0.0,
0.5,-0.5,0.0
];
var indices = [0,1,2,2,3,4];
gl.drawElements(gl.TRIANGLES, indices.length, gl.UNSIGNED_SHORT,0);
Wytworzy następujący wynik -
Wymagane operacje
Przed narysowaniem prymitywu musisz wykonać kilka operacji, które wyjaśniono poniżej.
Wyczyść płótno
Przede wszystkim powinieneś wyczyścić płótno za pomocą clearColor()metoda. Do tej metody można przekazać wartości RGBA żądanego koloru jako parametr. Następnie WebGL czyści płótno i wypełnia je określonym kolorem. Dlatego możesz użyć tej metody do ustawienia koloru tła.
Spójrz na poniższy przykład. Tutaj podajemy wartość RGBA koloru szarego.
gl.clearColor(0.5, 0.5, .5, 1);
Włącz test głębokości
Włącz test głębokości za pomocą enable() metoda, jak pokazano poniżej.
gl.enable(gl.DEPTH_TEST);
Wyczyść bit bufora koloru
Wyczyść kolor, a także bufor głębi, używając rozszerzenia clear() metoda, jak pokazano poniżej.
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
Ustaw port widoku
Port widoku reprezentuje prostokątny widoczny obszar zawierający wyniki renderowania buforu rysunku. Możesz ustawić wymiary portu widoku za pomocąviewport()metoda. W poniższym kodzie wymiary portu widoku są ustawione na wymiary obszaru roboczego.
gl.viewport(0,0,canvas.width,canvas.height);
Omówiliśmy wcześniej (w rozdziale 5), jak postępować krok po kroku, aby narysować prymityw. Wyjaśniliśmy ten proces w pięciu krokach. Musisz powtarzać te kroki za każdym razem, gdy rysujesz nowy kształt. W tym rozdziale wyjaśniono, jak rysować punkty za pomocą współrzędnych 3D w WebGL. Zanim przejdziemy dalej, przyjrzyjmy się ponownie pięciu krokom.
Wymagane kroki
Aby utworzyć aplikację WebGL do rysowania punktów, wymagane są następujące kroki.
Step 1 − Prepare the Canvas and Get the WebGL Rendering Context
W tym kroku otrzymujemy obiekt kontekstu WebGL Rendering przy użyciu metody getContext().
Step 2 − Define the Geometry and Store it in the Buffer Objects
Ponieważ rysujemy trzy punkty, definiujemy trzy wierzchołki ze współrzędnymi 3D i przechowujemy je w buforach.
var vertices = [
-0.5,0.5,0.0,
0.0,0.5,0.0,
-0.25,0.25,0.0,
];
Step 3 − Create and Compile the Shader Programs
Na tym etapie musisz napisać programy Vertex Shader i Fragment Shader, skompilować je i utworzyć połączony program, łącząc te dwa programy.
Vertex Shader - W Vertex Shader z podanego przykładu definiujemy atrybut wektorowy do przechowywania współrzędnych 3D i przypisujemy go do gl_position zmienna.
gl_pointsizeto zmienna używana do przypisywania rozmiaru do punktu. Rozmiar punktu przypisujemy jako 10.
var vertCode = 'attribute vec3 coordinates;' +
'void main(void) {' +
' gl_Position = vec4(coordinates, 1.0);' +
'gl_PointSize = 10.0;'+
'}';
Fragment Shader - W Fragment Shader po prostu przypisujemy kolor fragmentu do pliku gl_FragColor zmienna
var fragCode = 'void main(void) {' +' gl_FragColor = vec4(1, 0.5, 0.0, 1);' +'}';
Step 4 − Associate the Shader Programs to Buffer Objects
W tym kroku skojarzymy obiekty bufora z programem cieniującym.
Step 5 − Drawing the Required Object
Używamy metody drawArrays()rysować punkty. Ponieważ liczba punktów, które chcemy narysować, wynosi trzy, wartość zliczenia wynosi 3.
gl.drawArrays(gl.POINTS, 0, 3)
Przykład - narysuj trzy punkty za pomocą WebGL
Oto pełny program WebGL do rysowania trzech punktów -
<!doctype html>
<html>
<body>
<canvas width = "570" height = "570" id = "my_Canvas"></canvas>
<script>
/*================Creating a canvas=================*/
var canvas = document.getElementById('my_Canvas');
gl = canvas.getContext('experimental-webgl');
/*==========Defining and storing the geometry=======*/
var vertices = [
-0.5,0.5,0.0,
0.0,0.5,0.0,
-0.25,0.25,0.0,
];
// Create an empty buffer object to store the vertex buffer
var vertex_buffer = gl.createBuffer();
//Bind appropriate array buffer to it
gl.bindBuffer(gl.ARRAY_BUFFER, vertex_buffer);
// Pass the vertex data to the buffer
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertices), gl.STATIC_DRAW);
// Unbind the buffer
gl.bindBuffer(gl.ARRAY_BUFFER, null);
/*=========================Shaders========================*/
// vertex shader source code
var vertCode =
'attribute vec3 coordinates;' +
'void main(void) {' +
' gl_Position = vec4(coordinates, 1.0);' +
'gl_PointSize = 10.0;'+
'}';
// Create a vertex shader object
var vertShader = gl.createShader(gl.VERTEX_SHADER);
// Attach vertex shader source code
gl.shaderSource(vertShader, vertCode);
// Compile the vertex shader
gl.compileShader(vertShader);
// fragment shader source code
var fragCode =
'void main(void) {' +
' gl_FragColor = vec4(0.0, 0.0, 0.0, 0.1);' +
'}';
// Create fragment shader object
var fragShader = gl.createShader(gl.FRAGMENT_SHADER);
// Attach fragment shader source code
gl.shaderSource(fragShader, fragCode);
// Compile the fragmentt shader
gl.compileShader(fragShader);
// Create a shader program object to store
// the combined shader program
var shaderProgram = gl.createProgram();
// Attach a vertex shader
gl.attachShader(shaderProgram, vertShader);
// Attach a fragment shader
gl.attachShader(shaderProgram, fragShader);
// Link both programs
gl.linkProgram(shaderProgram);
// Use the combined shader program object
gl.useProgram(shaderProgram);
/*======== Associating shaders to buffer objects ========*/
// Bind vertex buffer object
gl.bindBuffer(gl.ARRAY_BUFFER, vertex_buffer);
// Get the attribute location
var coord = gl.getAttribLocation(shaderProgram, "coordinates");
// Point an attribute to the currently bound VBO
gl.vertexAttribPointer(coord, 3, gl.FLOAT, false, 0, 0);
// Enable the attribute
gl.enableVertexAttribArray(coord);
/*============= Drawing the primitive ===============*/
// Clear the canvas
gl.clearColor(0.5, 0.5, 0.5, 0.9);
// Enable the depth test
gl.enable(gl.DEPTH_TEST);
// Clear the color buffer bit
gl.clear(gl.COLOR_BUFFER_BIT);
// Set the view port
gl.viewport(0,0,canvas.width,canvas.height);
// Draw the triangle
gl.drawArrays(gl.POINTS, 0, 3);
</script>
</body>
</html>
To da następujący wynik -
W poprzednim rozdziale (Rozdział 11) omówiliśmy, jak narysować trzy punkty za pomocą WebGL. W rozdziale 5 wzięliśmy przykładową aplikację, aby zademonstrować, jak narysować trójkąt. W obu przykładach narysowaliśmy prymitywy, używając tylko wierzchołków.
Aby narysować bardziej złożone kształty / siatki, przekazujemy również indeksy geometrii wraz z wierzchołkami do shaderów. W tym rozdziale zobaczymy, jak narysować trójkąt za pomocą indeksów.
Kroki wymagane do narysowania trójkąta
Aby utworzyć aplikację WebGL do rysowania trójkąta, wymagane są następujące kroki.
Step 1 − Prepare the Canvas and Get WebGL Rendering Context
W tym kroku otrzymujemy obiekt kontekstu renderowania WebGL za pomocą getContext().
Step 2 − Define the Geometry and Store it in Buffer Objects
Ponieważ rysujemy trójkąt za pomocą indeksów, musimy przekazać trzy wierzchołki trójkąta, w tym indeksy, i zapisać je w buforach.
var vertices = [
-0.5,0.5,0.0,
-0.5,-0.5,0.0,
0.5,-0.5,0.0,
];
indices = [0,1,2];
Step 3 − Create and Compile the Shader Programs
Na tym etapie musisz napisać programy Vertex Shader i Fragment Shader, skompilować je i utworzyć połączony program, łącząc te dwa programy.
Vertex Shader - W Vertex Shader programu definiujemy atrybut wektora do przechowywania współrzędnych 3D i przypisujemy go gl_position.
var vertCode =
'attribute vec3 coordinates;' +
'void main(void) {' +
' gl_Position = vec4(coordinates, 1.0);' +
'}';
Fragment Shader - W Fragment Shader po prostu przypisujemy kolor fragmentu do pliku gl_FragColor zmienna.
var fragCode = 'void main(void) {' +
' gl_FragColor = vec4(1, 0.5, 0.0, 1);' +
'}';
Step 4 − Associate the Shader Programs to the Buffer Objects
Na tym etapie kojarzymy obiekty bufora i program cieniujący.
Step 5 − Drawing the Required Object
Ponieważ rysujemy trójkąt za pomocą indeksów, użyjemy drawElements()
. Do tej metody musimy podać liczbę indeksów. Wartośćindices.length oznacza liczbę indeksów.
gl.drawElements(gl.TRIANGLES, indices.length, gl.UNSIGNED_SHORT,0);
Przykład - rysowanie trójkąta
Poniższy kod programu pokazuje, jak narysować trójkąt w WebGL za pomocą indeksów -
<!doctype html>
<html>
<body>
<canvas width = "570" height = "570" id = "my_Canvas"></canvas>
<script>
/*============== Creating a canvas ====================*/
var canvas = document.getElementById('my_Canvas');
gl = canvas.getContext('experimental-webgl');
/*======== Defining and storing the geometry ===========*/
var vertices = [
-0.5,0.5,0.0,
-0.5,-0.5,0.0,
0.5,-0.5,0.0,
];
indices = [0,1,2];
// Create an empty buffer object to store vertex buffer
var vertex_buffer = gl.createBuffer();
// Bind appropriate array buffer to it
gl.bindBuffer(gl.ARRAY_BUFFER, vertex_buffer);
// Pass the vertex data to the buffer
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertices), gl.STATIC_DRAW);
// Unbind the buffer
gl.bindBuffer(gl.ARRAY_BUFFER, null);
// Create an empty buffer object to store Index buffer
var Index_Buffer = gl.createBuffer();
// Bind appropriate array buffer to it
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, Index_Buffer);
// Pass the vertex data to the buffer
gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new Uint16Array(indices), gl.STATIC_DRAW);
// Unbind the buffer
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, null);
/*================ Shaders ====================*/
// Vertex shader source code
var vertCode =
'attribute vec3 coordinates;' +
'void main(void) {' +
' gl_Position = vec4(coordinates, 1.0);' +
'}';
// Create a vertex shader object
var vertShader = gl.createShader(gl.VERTEX_SHADER);
// Attach vertex shader source code
gl.shaderSource(vertShader, vertCode);
// Compile the vertex shader
gl.compileShader(vertShader);
//fragment shader source code
var fragCode =
'void main(void) {' +
' gl_FragColor = vec4(0.0, 0.0, 0.0, 0.1);' +
'}';
// Create fragment shader object
var fragShader = gl.createShader(gl.FRAGMENT_SHADER);
// Attach fragment shader source code
gl.shaderSource(fragShader, fragCode);
// Compile the fragmentt shader
gl.compileShader(fragShader);
// Create a shader program object to store
// the combined shader program
var shaderProgram = gl.createProgram();
// Attach a vertex shader
gl.attachShader(shaderProgram, vertShader);
// Attach a fragment shader
gl.attachShader(shaderProgram, fragShader);
// Link both the programs
gl.linkProgram(shaderProgram);
// Use the combined shader program object
gl.useProgram(shaderProgram);
/*======= Associating shaders to buffer objects =======*/
// Bind vertex buffer object
gl.bindBuffer(gl.ARRAY_BUFFER, vertex_buffer);
// Bind index buffer object
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, Index_Buffer);
// Get the attribute location
var coord = gl.getAttribLocation(shaderProgram, "coordinates");
// Point an attribute to the currently bound VBO
gl.vertexAttribPointer(coord, 3, gl.FLOAT, false, 0, 0);
// Enable the attribute
gl.enableVertexAttribArray(coord);
/*=========Drawing the triangle===========*/
// Clear the canvas
gl.clearColor(0.5, 0.5, 0.5, 0.9);
// Enable the depth test
gl.enable(gl.DEPTH_TEST);
// Clear the color buffer bit
gl.clear(gl.COLOR_BUFFER_BIT);
// Set the view port
gl.viewport(0,0,canvas.width,canvas.height);
// Draw the triangle
gl.drawElements(gl.TRIANGLES, indices.length, gl.UNSIGNED_SHORT,0);
</script>
</body>
</html>
Jeśli uruchomisz ten przykład, wygeneruje on następujące dane wyjściowe -
W poprzednim rozdziale (Rozdział 12) omówiliśmy, jak narysować trójkąt za pomocą WebGL. Oprócz trójkątów, WebGL obsługuje różne inne tryby rysowania. W tym rozdziale opisano tryby rysowania obsługiwane przez WebGL.
Tryb Parameter
Rzućmy okiem na składnię metod - drawElements() i narysuj Arrays().
void drawElements(enum mode, long count, enum type, long offset);
void drawArrays(enum mode, int first, long count);
Jeśli wyraźnie zauważysz, obie metody akceptują parametr mode. Za pomocą tego parametru programiści mogą wybrać tryb rysowania w WebGL.
W poniższej tabeli wymieniono tryby rysowania oferowane przez WebGL.
Sr.No. | Tryb i opis |
---|---|
1 | gl.POINTS Aby narysować serię punktów. |
2 | gl.LINES Rysowanie szeregu niepołączonych odcinków linii (pojedynczych linii). |
3 | gl.LINE_STRIP Aby narysować serię połączonych segmentów linii. |
4 | gl.LINE_LOOP Aby narysować serię połączonych segmentów linii. Łączy również pierwszy i ostatni wierzchołek, tworząc pętlę. |
5 | gl.TRIANGLES Aby narysować serię oddzielnych trójkątów. |
6 | gl.TRIANGLE_STRIP Aby narysować serię połączonych trójkątów w paski. |
7 | gl.TRIANGLE_FAN Narysować serię połączonych trójkątów, które mają wspólny wierzchołek w sposób podobny do wachlarza. |
Przykład - narysuj trzy równoległe linie
Poniższy przykład pokazuje, jak narysować trzy równoległe linie za pomocą gl.LINES.
<!doctype html>
<html>
<body>
<canvas width = "300" height = "300" id = "my_Canvas"></canvas>
<script>
/*======= Creating a canvas =========*/
var canvas = document.getElementById('my_Canvas');
var gl = canvas.getContext('experimental-webgl');
/*======= Defining and storing the geometry ======*/
var vertices = [
-0.7,-0.1,0,
-0.3,0.6,0,
-0.3,-0.3,0,
0.2,0.6,0,
0.3,-0.3,0,
0.7,0.6,0
]
// Create an empty buffer object
var vertex_buffer = gl.createBuffer();
// Bind appropriate array buffer to it
gl.bindBuffer(gl.ARRAY_BUFFER, vertex_buffer);
// Pass the vertex data to the buffer
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertices), gl.STATIC_DRAW);
// Unbind the buffer
gl.bindBuffer(gl.ARRAY_BUFFER, null);
/*=================== Shaders ====================*/
// Vertex shader source code
var vertCode =
'attribute vec3 coordinates;' +
'void main(void) {' +
' gl_Position = vec4(coordinates, 1.0);' +
'}';
// Create a vertex shader object
var vertShader = gl.createShader(gl.VERTEX_SHADER);
// Attach vertex shader source code
gl.shaderSource(vertShader, vertCode);
// Compile the vertex shader
gl.compileShader(vertShader);
// Fragment shader source code
var fragCode =
'void main(void) {' +
'gl_FragColor = vec4(0.0, 0.0, 0.0, 0.1);' +
'}';
// Create fragment shader object
var fragShader = gl.createShader(gl.FRAGMENT_SHADER);
// Attach fragment shader source code
gl.shaderSource(fragShader, fragCode);
// Compile the fragmentt shader
gl.compileShader(fragShader);
// Create a shader program object to store
// the combined shader program
var shaderProgram = gl.createProgram();
// Attach a vertex shader
gl.attachShader(shaderProgram, vertShader);
// Attach a fragment shader
gl.attachShader(shaderProgram, fragShader);
// Link both the programs
gl.linkProgram(shaderProgram);
// Use the combined shader program object
gl.useProgram(shaderProgram);
/*======= Associating shaders to buffer objects ======*/
// Bind vertex buffer object
gl.bindBuffer(gl.ARRAY_BUFFER, vertex_buffer);
// Get the attribute location
var coord = gl.getAttribLocation(shaderProgram, "coordinates");
// Point an attribute to the currently bound VBO
gl.vertexAttribPointer(coord, 3, gl.FLOAT, false, 0, 0);
// Enable the attribute
gl.enableVertexAttribArray(coord);
/*============ Drawing the triangle =============*/
// Clear the canvas
gl.clearColor(0.5, 0.5, 0.5, 0.9);
// Enable the depth test
gl.enable(gl.DEPTH_TEST);
// Clear the color and depth buffer
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
// Set the view port
gl.viewport(0,0,canvas.width,canvas.height);
// Draw the triangle
gl.drawArrays(gl.LINES, 0, 6);
// POINTS, LINE_STRIP, LINE_LOOP, LINES,
// TRIANGLE_STRIP,TRIANGLE_FAN, TRIANGLES
</script>
</body>
</html>
Jeśli uruchomisz ten przykład, wygeneruje on następujące dane wyjściowe -
Tryby rysowania
W powyższym programie, jeśli zmienisz tryb drawArrays() w jednym z poniższych trybów rysowania za każdym razem będzie generować inne wyniki.
Tryby rysowania | Wyjścia |
---|---|
LINE_STRIP |
|
LINE_LOOP |
|
TRIANGLE_STRIP |
|
TRIANGLE_FAN |
|
TRÓJKĄTY |
|
W poprzednim rozdziale omówiliśmy różne tryby rysowania oferowane przez WebGL. Możemy również używać indeksów do rysowania prymitywów przy użyciu jednego z tych trybów. Aby narysować modele w WebGL, musimy wybrać jeden z tych prymitywów i narysować wymaganą siatkę (tj. Model utworzony przy użyciu jednego lub więcej prymitywów).
W tym rozdziale weźmiemy przykład, aby zademonstrować, jak narysować czworokąt za pomocą WebGL.
Kroki, aby narysować czworokąt
Aby utworzyć aplikację WebGL do narysowania czworoboku, wymagane są następujące kroki.
Step 1 − Prepare the Canvas and Get the WebGL Rendering Context
W tym kroku otrzymujemy obiekt kontekstu renderowania WebGL za pomocą getContext().
Step 2 − Define the Geometry and Store it in the Buffer Objects
Kwadrat można narysować za pomocą dwóch trójkątów. W tym przykładzie podajemy wierzchołki dwóch trójkątów (z jedną wspólną krawędzią) i indeksy.
var vertices = [
-0.5,0.5,0.0,
-0.5,-0.5,0.0,
0.5,-0.5,0.0,
0.5,0.5,0.0
];
indices = [3,2,1,3,1,0];
Step 3 − Create and Compile the Shader Programs
Na tym etapie musisz napisać programy Vertex Shader i Fragment Shader, skompilować je i utworzyć połączony program, łącząc te dwa programy.
Vertex Shader - W Vertex Shader programu definiujemy atrybut wektora do przechowywania współrzędnych 3D i przypisujemy go gl_position.
var vertCode =
'attribute vec3 coordinates;' +
'void main(void) {' +
' gl_Position = vec4(coordinates, 1.0);' +
'}';
Fragment Shader - W Fragment Shader po prostu przypisujemy kolor fragmentu do pliku gl_FragColor zmienna.
var fragCode = 'void main(void) {' +' gl_FragColor = vec4(0.5, 0.3, 0.0, 7.5);' +'}';
Step 4 − Associate the Shader Programs to Buffer Objects
W tym kroku skojarzymy obiekty bufora z programem cieniującym.
Step 5 − Drawing the Required Object
Ponieważ rysujemy dwa trójkąty, aby utworzyć kwadrat, używając indeksów, użyjemy metody drawElements(). Do tej metody musimy podać liczbę indeksów. Wartośćindices.length podaje liczbę indeksów.
gl.drawElements(gl.TRIANGLES, indices.length, gl.UNSIGNED_SHORT,0);
Przykład - narysuj czworokąt
Poniższy program pokazuje, jak utworzyć aplikację WebGL do rysowania czworoboku.
<!doctype html>
<html>
<body>
<canvas width = "570" height = "570" id = "my_Canvas"></canvas>
<script>
/*============ Creating a canvas =================*/
var canvas = document.getElementById('my_Canvas');
gl = canvas.getContext('experimental-webgl');
/*========== Defining and storing the geometry =========*/
var vertices = [
-0.5,0.5,0.0,
-0.5,-0.5,0.0,
0.5,-0.5,0.0,
0.5,0.5,0.0
];
indices = [3,2,1,3,1,0];
// Create an empty buffer object to store vertex buffer
var vertex_buffer = gl.createBuffer();
// Bind appropriate array buffer to it
gl.bindBuffer(gl.ARRAY_BUFFER, vertex_buffer);
// Pass the vertex data to the buffer
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertices), gl.STATIC_DRAW);
// Unbind the buffer
gl.bindBuffer(gl.ARRAY_BUFFER, null);
// Create an empty buffer object to store Index buffer
var Index_Buffer = gl.createBuffer();
// Bind appropriate array buffer to it
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, Index_Buffer);
// Pass the vertex data to the buffer
gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new Uint16Array(indices), gl.STATIC_DRAW);
// Unbind the buffer
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, null);
/*====================== Shaders =======================*/
// Vertex shader source code
var vertCode =
'attribute vec3 coordinates;' +
'void main(void) {' +
' gl_Position = vec4(coordinates, 1.0);' +
'}';
// Create a vertex shader object
var vertShader = gl.createShader(gl.VERTEX_SHADER);
// Attach vertex shader source code
gl.shaderSource(vertShader, vertCode);
// Compile the vertex shader
gl.compileShader(vertShader);
// Fragment shader source code
var fragCode =
'void main(void) {' +
' gl_FragColor = vec4(0.0, 0.0, 0.0, 0.1);' +
'}';
// Create fragment shader object
var fragShader = gl.createShader(gl.FRAGMENT_SHADER);
// Attach fragment shader source code
gl.shaderSource(fragShader, fragCode);
// Compile the fragmentt shader
gl.compileShader(fragShader);
// Create a shader program object to
// store the combined shader program
var shaderProgram = gl.createProgram();
// Attach a vertex shader
gl.attachShader(shaderProgram, vertShader);
// Attach a fragment shader
gl.attachShader(shaderProgram, fragShader);
// Link both the programs
gl.linkProgram(shaderProgram);
// Use the combined shader program object
gl.useProgram(shaderProgram);
/* ======= Associating shaders to buffer objects =======*/
// Bind vertex buffer object
gl.bindBuffer(gl.ARRAY_BUFFER, vertex_buffer);
// Bind index buffer object
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, Index_Buffer);
// Get the attribute location
var coord = gl.getAttribLocation(shaderProgram, "coordinates");
// Point an attribute to the currently bound VBO
gl.vertexAttribPointer(coord, 3, gl.FLOAT, false, 0, 0);
// Enable the attribute
gl.enableVertexAttribArray(coord);
/*============= Drawing the Quad ================*/
// Clear the canvas
gl.clearColor(0.5, 0.5, 0.5, 0.9);
// Enable the depth test
gl.enable(gl.DEPTH_TEST);
// Clear the color buffer bit
gl.clear(gl.COLOR_BUFFER_BIT);
// Set the view port
gl.viewport(0,0,canvas.width,canvas.height);
// Draw the triangle
gl.drawElements(gl.TRIANGLES, indices.length, gl.UNSIGNED_SHORT,0);
</script>
</body>
</html>
Jeśli uruchomisz ten przykład, wygeneruje on następujące dane wyjściowe -
We wszystkich naszych poprzednich przykładach zastosowaliśmy kolor do obiektu, przypisując żądaną wartość koloru do elementu gl_FragColorzmienna. Oprócz tego możemy zdefiniować kolory dla każdego wierzchołka - podobnie jak współrzędne wierzchołków i indeksy. W tym rozdziale przedstawiono przykład pokazujący, jak zastosować kolory do czworoboku za pomocą WebGL.
Stosowanie kolorów
Aby zastosować kolory, musisz zdefiniować kolory dla każdego wierzchołka za pomocą wartości RGB w tablicy JavaScript. Możesz przypisać te same wartości wszystkim wierzchołkom, aby nadać obiektowi niepowtarzalny kolor. Po zdefiniowaniu kolorów musisz utworzyć bufor kolorów i zapisać w nim te wartości oraz powiązać je z atrybutami Vertex Shader.
W Vertex Shader, wraz z atrybutem współrzędnych (który określa położenie wierzchołków), definiujemy plik attribute i a varying do obsługi kolorów.
Plik color atrybut zawiera wartość koloru na wierzchołek, a varyingto zmienna przekazywana jako dane wejściowe do Fragment Shadera. Dlatego musimy przypisać plikcolor wartość do varying.
W Fragment Shader plik varying który zawiera przypisaną wartość koloru gl_FragColor, który zawiera ostateczny kolor obiektu.
Kroki, aby zastosować kolory
Poniższe kroki są wymagane, aby utworzyć aplikację WebGL, aby narysować Quad i zastosować do niego kolory.
Step 1 − Prepare the Canvas and Get the WebGL Rendering Context
W tym kroku otrzymujemy obiekt kontekstu renderowania WebGL za pomocą getContext().
Step 2 − Define the Geometry and Store it in the Buffer Objects
Kwadrat można narysować za pomocą dwóch trójkątów. Dlatego w tym przykładzie podajemy wierzchołki dwóch trójkątów (z jedną wspólną krawędzią) i indeksy. Ponieważ chcemy zastosować do niego kolory, definiowana jest również zmienna przechowująca wartości kolorów i przypisywane są do niej wartości kolorów (czerwony, niebieski, zielony i różowy).
var vertices = [
-0.5,0.5,0.0,
-0.5,-0.5,0.0,
0.5,-0.5,0.0,
0.5,0.5,0.0
];
var colors = [ 0,0,1, 1,0,0, 0,1,0, 1,0,1,];
indices = [3,2,1,3,1,0];
Step 3 − Create and Compile the Shader Programs
Na tym etapie musisz napisać programy Vertex Shader i Fragment Shader, skompilować je i utworzyć połączony program, łącząc te dwa programy.
Vertex Shader- W Vertex Shader programu definiujemy atrybuty wektorów do przechowywania współrzędnych 3D (pozycji) i koloru każdego wierzchołka. ZAvaringzadeklarowano, że zmienna przekazuje wartości kolorów z Vertex Shadera do Fragment Shadera. Na koniec przypisywana jest wartość przechowywana w atrybucie koloruvarying.
var vertCode = 'attribute vec3 coordinates;'+
'attribute vec3 color;'+
'varying vec3 vColor;'+
'void main(void) {' +
' gl_Position = vec4(coordinates, 1.0);' +
'vColor = color;'+
'}';
Fragment Shader - W Fragment Shader przypisujemy plik varying do gl_FragColor zmienna.
var fragCode = 'precision mediump float;'+
'varying vec3 vColor;'+
'void main(void) {'+
'gl_FragColor = vec4(vColor, 1.);'+
'}';
Step 4 − Associate the Shader Programs with the Buffer Objects
Na tym etapie kojarzymy obiekty bufora i program cieniujący.
Step 5 − Drawing the Required Object
Ponieważ rysujemy dwa trójkąty, które utworzą quad, używając indeksów, użyjemy metody drawElements(). Do tej metody musimy podać liczbę indeksów. Wartośćindices.length wskazuje liczbę indeksów.
gl.drawElements(gl.TRIANGLES, indices.length, gl.UNSIGNED_SHORT,0);
Przykład - nakładanie koloru
Poniższy program pokazuje, jak narysować czwórkę za pomocą aplikacji WebGL i zastosować do niej kolory.
<!doctype html>
<html>
<body>
<canvas width = "300" height = "300" id = "my_Canvas"></canvas>
<script>
/*============= Creating a canvas ==================*/
var canvas = document.getElementById('my_Canvas');
gl = canvas.getContext('experimental-webgl');
/*========== Defining and storing the geometry ==========*/
var vertices = [
-0.5,0.5,0.0,
-0.5,-0.5,0.0,
0.5,-0.5,0.0,
0.5,0.5,0.0
];
var colors = [0,0,1, 1,0,0, 0,1,0, 1,0,1,];
indices = [3,2,1,3,1,0];
// Create an empty buffer object and store vertex data
var vertex_buffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, vertex_buffer);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertices), gl.STATIC_DRAW);
gl.bindBuffer(gl.ARRAY_BUFFER, null);
// Create an empty buffer object and store Index data
var Index_Buffer = gl.createBuffer();
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, Index_Buffer);
gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new Uint16Array(indices), gl.STATIC_DRAW);
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, null);
// Create an empty buffer object and store color data
var color_buffer = gl.createBuffer ();
gl.bindBuffer(gl.ARRAY_BUFFER, color_buffer);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(colors), gl.STATIC_DRAW);
/*======================= Shaders =======================*/
// vertex shader source code
var vertCode = 'attribute vec3 coordinates;'+
'attribute vec3 color;'+
'varying vec3 vColor;'+
'void main(void) {' +
' gl_Position = vec4(coordinates, 1.0);' +
'vColor = color;'+
'}';
// Create a vertex shader object
var vertShader = gl.createShader(gl.VERTEX_SHADER);
// Attach vertex shader source code
gl.shaderSource(vertShader, vertCode);
// Compile the vertex shader
gl.compileShader(vertShader);
// fragment shader source code
var fragCode = 'precision mediump float;'+
'varying vec3 vColor;'+
'void main(void) {'+
'gl_FragColor = vec4(vColor, 1.);'+
'}';
// Create fragment shader object
var fragShader = gl.createShader(gl.FRAGMENT_SHADER);
// Attach fragment shader source code
gl.shaderSource(fragShader, fragCode);
// Compile the fragmentt shader
gl.compileShader(fragShader);
// Create a shader program object to
// store the combined shader program
var shaderProgram = gl.createProgram();
// Attach a vertex shader
gl.attachShader(shaderProgram, vertShader);
// Attach a fragment shader
gl.attachShader(shaderProgram, fragShader);
// Link both the programs
gl.linkProgram(shaderProgram);
// Use the combined shader program object
gl.useProgram(shaderProgram);
/* ======== Associating shaders to buffer objects =======*/
// Bind vertex buffer object
gl.bindBuffer(gl.ARRAY_BUFFER, vertex_buffer);
// Bind index buffer object
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, Index_Buffer);
// Get the attribute location
var coord = gl.getAttribLocation(shaderProgram, "coordinates");
// point an attribute to the currently bound VBO
gl.vertexAttribPointer(coord, 3, gl.FLOAT, false, 0, 0);
// Enable the attribute
gl.enableVertexAttribArray(coord);
// bind the color buffer
gl.bindBuffer(gl.ARRAY_BUFFER, color_buffer);
// get the attribute location
var color = gl.getAttribLocation(shaderProgram, "color");
// point attribute to the volor buffer object
gl.vertexAttribPointer(color, 3, gl.FLOAT, false,0,0) ;
// enable the color attribute
gl.enableVertexAttribArray(color);
/*============Drawing the Quad====================*/
// Clear the canvas
gl.clearColor(0.5, 0.5, 0.5, 0.9);
// Enable the depth test
gl.enable(gl.DEPTH_TEST);
// Clear the color buffer bit
gl.clear(gl.COLOR_BUFFER_BIT);
// Set the view port
gl.viewport(0,0,canvas.width,canvas.height);
//Draw the triangle
gl.drawElements(gl.TRIANGLES, indices.length, gl.UNSIGNED_SHORT,0);
</script>
</body>
</html>
Jeśli uruchomisz ten przykład, wygeneruje on następujące dane wyjściowe -
Do tej pory dyskutowaliśmy, jak narysować różne kształty i zastosować w nich kolory za pomocą WebGL. Tutaj, w tym rozdziale, weźmiemy przykład, aby pokazać, jak przetłumaczyć trójkąt.
Tłumaczenie
Tłumaczenie jest jednym z affine transformationsdostarczane przez WebGL. Używając translacji, możemy przesunąć trójkąt (dowolny obiekt) na płaszczyźnie xyz. Załóżmy, że mamy trójkąt [a, b, c] i chcemy przesunąć trójkąt do pozycji, która wynosi 5 jednostek w kierunku dodatniej osi X i 3 jednostki w kierunku dodatniej osi Y. Wtedy nowe wierzchołki byłyby [a + 5, b + 3, c + 0]. Oznacza to, że aby przetłumaczyć trójkąt, musimy dodać odległości translacji, powiedzmy, tx, ty, tz do każdego wierzchołka.
Ponieważ jest to plik per-vertex operation, możemy go przenieść w programie Vertex Shader.
W Vertex Shader wraz z atrybutem coordinates(które utrzymują pozycje wierzchołków), definiujemy zmienną jednorodną, która przechowuje odległości przesunięcia (x, y, z). Później dodajemy tę zmienną uniform do zmiennej współrzędnych i przypisujemy wynik dogl_Position zmienna.
Note - Ponieważ Vertex Shader zostanie uruchomiony na każdym wierzchołku, wszystkie wierzchołki trójkąta zostaną przetłumaczone.
Kroki do przetłumaczenia trójkąta
Aby utworzyć aplikację WebGL, aby narysować trójkąt, a następnie przetłumaczyć go na nowe położenie, wymagane są następujące kroki.
Step 1 − Prepare the Canvas and Get the WebGL Rendering Context
W tym kroku otrzymujemy obiekt kontekstu renderowania WebGL za pomocą getContext().
Step 2 − Define the Geometry and Store it in the Buffer Objects
Ponieważ rysujemy trójkąt, musimy przejść przez trzy wierzchołki trójkąta i przechowywać je w buforach.
var vertices = [ -0.5,0.5,0.0, -0.5,-0.5,0.0, 0.5,-0.5,0.0, ];
Step 3 − Create and Compile the Shader Programs
Na tym etapie musisz napisać programy Vertex Shader i Fragment Shader, skompilować je i utworzyć połączony program, łącząc te dwa programy.
Vertex Shader- W Vertex Shader programu definiujemy atrybut wektorowy do przechowywania współrzędnych 3D. Wraz z nim definiujemy zmienną jednolitą do przechowywania odległości tłumaczenia, a na koniec dodajemy te dwie wartości i przypisujemy dogl_position który zawiera ostateczne położenie wierzchołków.
var vertCode =
'attribute vec4 coordinates;' +
'uniform vec4 translation;'+
'void main(void) {' +
' gl_Position = coordinates + translation;' +
'}';
Fragment Shader - W Fragment Shader po prostu przypisujemy kolor fragmentu do zmiennej gl_FragColor.
var fragCode = 'void main(void) {' +' gl_FragColor = vec4(1, 0.5, 0.0, 1);' +'}';
Step 4 − Associate the Shader Programs to the Buffer Objects
W tym kroku skojarzymy obiekty bufora z programem cieniującym.
Step 5 − Drawing the Required Object
Ponieważ rysujemy trójkąt za pomocą indeksów, użyjemy metody drawArrays(). Do tej metody musimy przekazać liczbę wierzchołków / elementów do rozważenia. Ponieważ rysujemy trójkąt, jako parametr przekażemy 3.
gl.drawArrays(gl.TRIANGLES, 0, 3);
Przykład - Przetłumacz trójkąt
Poniższy przykład pokazuje, jak przetłumaczyć trójkąt na płaszczyźnie xyz.
<!doctype html>
<html>
<body>
<canvas width = "300" height = "300" id = "my_Canvas"></canvas>
<script>
/*=================Creating a canvas=========================*/
var canvas = document.getElementById('my_Canvas');
gl = canvas.getContext('experimental-webgl');
/*===========Defining and storing the geometry==============*/
var vertices = [
-0.5,0.5,0.0,
-0.5,-0.5,0.0,
0.5,-0.5,0.0,
];
//Create an empty buffer object and store vertex data
var vertex_buffer = gl.createBuffer();
//Create a new buffer
gl.bindBuffer(gl.ARRAY_BUFFER, vertex_buffer);
//bind it to the current buffer
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertices), gl.STATIC_DRAW);
// Pass the buffer data
gl.bindBuffer(gl.ARRAY_BUFFER, null);
/*========================Shaders============================*/
//vertex shader source code
var vertCode =
'attribute vec4 coordinates;' +
'uniform vec4 translation;'+
'void main(void) {' +
' gl_Position = coordinates + translation;' +
'}';
//Create a vertex shader program object and compile it
var vertShader = gl.createShader(gl.VERTEX_SHADER);
gl.shaderSource(vertShader, vertCode);
gl.compileShader(vertShader);
//fragment shader source code
var fragCode =
'void main(void) {' +
' gl_FragColor = vec4(0.0, 0.0, 0.0, 0.1);' +
'}';
//Create a fragment shader program object and compile it
var fragShader = gl.createShader(gl.FRAGMENT_SHADER);
gl.shaderSource(fragShader, fragCode);
gl.compileShader(fragShader);
//Create and use combiened shader program
var shaderProgram = gl.createProgram();
gl.attachShader(shaderProgram, vertShader);
gl.attachShader(shaderProgram, fragShader);
gl.linkProgram(shaderProgram);
gl.useProgram(shaderProgram);
/* ===========Associating shaders to buffer objects============*/
gl.bindBuffer(gl.ARRAY_BUFFER, vertex_buffer);
var coordinatesVar = gl.getAttribLocation(shaderProgram, "coordinates");
gl.vertexAttribPointer(coordinatesVar, 3, gl.FLOAT, false, 0, 0);
gl.enableVertexAttribArray(coordinatesVar);
/* ==========translation======================================*/
var Tx = 0.5, Ty = 0.5, Tz = 0.0;
var translation = gl.getUniformLocation(shaderProgram, 'translation');
gl.uniform4f(translation, Tx, Ty, Tz, 0.0);
/*=================Drawing the riangle and transforming it========================*/
gl.clearColor(0.5, 0.5, 0.5, 0.9);
gl.enable(gl.DEPTH_TEST);
gl.clear(gl.COLOR_BUFFER_BIT);
gl.viewport(0,0,canvas.width,canvas.height);
gl.drawArrays(gl.TRIANGLES, 0, 3);
</script>
</body>
</html>
Jeśli uruchomisz ten przykład, wygeneruje on następujące dane wyjściowe -
W tym rozdziale weźmiemy przykład, aby zademonstrować, jak zmodyfikować skalę trójkąta za pomocą WebGL.
skalowanie
Skalowanie to nic innego jak zwiększanie lub zmniejszanie rozmiaru obiektu. Na przykład, jeśli trójkąt ma wierzchołki o rozmiarze [a, b, c], to trójkąt z wierzchołkami [2a, 2b, 2c] będzie dwukrotnie większy. Dlatego, aby przeskalować trójkąt, musisz pomnożyć każdy wierzchołek przez współczynnik skalowania. Możesz również skalować określony wierzchołek.
Aby przeskalować trójkąt, w Vertex Shader programu tworzymy jednolitą macierz i mnożymy wartości współrzędnych za pomocą tej macierzy. Później mijamy macierz przekątną 4 × 4 mającą współczynniki skalowania współrzędnych x, y, z na pozycjach przekątnych (ostatnia pozycja przekątnej 1).
Wymagane kroki
Aby utworzyć aplikację WebGL do skalowania trójkąta, wymagane są następujące kroki.
Step 1 − Prepare the Canvas and Get the WebGL Rendering Context
W tym kroku otrzymujemy obiekt kontekstu renderowania WebGL za pomocą getContext().
Step 2 − Define the Geometry and Store it in the Buffer Objects
Ponieważ rysujemy trójkąt, musimy przejść przez trzy wierzchołki trójkąta i przechowywać je w buforach.
var vertices = [ -0.5,0.5,0.0, -0.5,-0.5,0.0, 0.5,-0.5,0.0, ];
Step 3 − Create and Compile the Shader Programs
Na tym etapie musisz napisać programy Vertex Shader i Fragment Shader, skompilować je i utworzyć połączony program, łącząc te dwa programy.
Vertex Shader- W Vertex Shader programu definiujemy atrybut wektorowy do przechowywania współrzędnych 3D. Wraz z nim definiujemy jednolitą macierz do przechowywania współczynników skalowania, a na koniec mnożymy te dwie wartości i przypisujemy dogl_position który zawiera ostateczne położenie wierzchołków.
var vertCode =
'attribute vec4 coordinates;' +
'uniform mat4 u_xformMatrix;' +
'void main(void) {' +
' gl_Position = u_xformMatrix * coordinates;' +
'}';
Fragment Shader - W Fragment Shader po prostu przypisujemy kolor fragmentu do pliku gl_FragColor zmienna.
var fragCode = 'void main(void) {' +' gl_FragColor = vec4(1, 0.5, 0.0, 1);' +'}';
Step 4 − Associate the Shader Programs with the Buffer Objects
W tym kroku skojarzymy obiekty bufora z programem cieniującym.
Step 5 − Drawing the Required Object
Ponieważ rysujemy trójkąt za pomocą indeksów, używamy drawArrays()metoda. Do tej metody musimy przekazać liczbę wierzchołków / elementów do rozważenia. Ponieważ rysujemy trójkąt, jako parametr przekażemy 3.
gl.drawArrays(gl.TRIANGLES, 0, 3);
Przykład - Skaluj trójkąt
Poniższy przykład pokazuje, jak skalować trójkąt -
<!doctype html>
<html>
<body>
<canvas width = "300" height = "300" id = "my_Canvas"></canvas>
<script>
/*=================Creating a canvas=========================*/
var canvas = document.getElementById('my_Canvas');
gl = canvas.getContext('experimental-webgl');
/*===========Defining and storing the geometry==============*/
var vertices = [
-0.5,0.5,0.0,
-0.5,-0.5,0.0,
0.5,-0.5,0.0,
];
//Create an empty buffer object and store vertex data
var vertex_buffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, vertex_buffer);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertices), gl.STATIC_DRAW);
gl.bindBuffer(gl.ARRAY_BUFFER, null);
/*========================Shaders============================*/
//Vertex shader source code
var vertCode =
'attribute vec4 coordinates;' +
'uniform mat4 u_xformMatrix;' +
'void main(void) {' +
' gl_Position = u_xformMatrix * coordinates;' +
'}';
//Create a vertex shader program object and compile it
var vertShader = gl.createShader(gl.VERTEX_SHADER);
gl.shaderSource(vertShader, vertCode);
gl.compileShader(vertShader);
//fragment shader source code
var fragCode =
'void main(void) {' +
' gl_FragColor = vec4(0.0, 0.0, 0.0, 0.1);' +
'}';
//Create a fragment shader program object and compile it
var fragShader = gl.createShader(gl.FRAGMENT_SHADER);
gl.shaderSource(fragShader, fragCode);
gl.compileShader(fragShader);
//Create and use combiened shader program
var shaderProgram = gl.createProgram();
gl.attachShader(shaderProgram, vertShader);
gl.attachShader(shaderProgram, fragShader);
gl.linkProgram(shaderProgram);
gl.useProgram(shaderProgram);
/*===================scaling==========================*/
var Sx = 1.0, Sy = 1.5, Sz = 1.0;
var xformMatrix = new Float32Array([
Sx, 0.0, 0.0, 0.0,
0.0, Sy, 0.0, 0.0,
0.0, 0.0, Sz, 0.0,
0.0, 0.0, 0.0, 1.0
]);
var u_xformMatrix = gl.getUniformLocation(shaderProgram, 'u_xformMatrix');
gl.uniformMatrix4fv(u_xformMatrix, false, xformMatrix);
/* ===========Associating shaders to buffer objects============*/
gl.bindBuffer(gl.ARRAY_BUFFER, vertex_buffer);
var coordinatesVar = gl.getAttribLocation(shaderProgram, "coordinates");
gl.vertexAttribPointer(coordinatesVar, 3, gl.FLOAT, false, 0, 0);
gl.enableVertexAttribArray(coordinatesVar);
/*=================Drawing the Quad========================*/
gl.clearColor(0.5, 0.5, 0.5, 0.9);
gl.enable(gl.DEPTH_TEST);
gl.clear(gl.COLOR_BUFFER_BIT);
gl.viewport(0,0,canvas.width,canvas.height);
gl.drawArrays(gl.TRIANGLES, 0, 3);
</script>
</body>
</html>
Jeśli uruchomisz ten przykład, wygeneruje on następujące dane wyjściowe -
W tym rozdziale weźmiemy przykład, aby zademonstrować, jak obrócić trójkąt za pomocą WebGL.
Przykład - Obróć trójkąt
Poniższy program pokazuje, jak obrócić trójkąt za pomocą WebGL.
<!doctype html>
<html>
<body>
<canvas width = "400" height = "400" id = "my_Canvas"></canvas>
<script>
/*=================Creating a canvas=========================*/
var canvas = document.getElementById('my_Canvas');
gl = canvas.getContext('experimental-webgl');
/*===========Defining and storing the geometry==============*/
var vertices = [ -1,-1,-1, 1,-1,-1, 1, 1,-1 ];
var colors = [ 1,1,1, 1,1,1, 1,1,1 ];
var indices = [ 0,1,2 ];
//Create and store data into vertex buffer
var vertex_buffer = gl.createBuffer ();
gl.bindBuffer(gl.ARRAY_BUFFER, vertex_buffer);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertices), gl.STATIC_DRAW);
//Create and store data into color buffer
var color_buffer = gl.createBuffer ();
gl.bindBuffer(gl.ARRAY_BUFFER, color_buffer);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(colors), gl.STATIC_DRAW);
//Create and store data into index buffer
var index_buffer = gl.createBuffer ();
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, index_buffer);
gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new Uint16Array(indices), gl.STATIC_DRAW);
/*==========================Shaders=========================*/
var vertCode = 'attribute vec3 position;'+
'uniform mat4 Pmatrix;'+
'uniform mat4 Vmatrix;'+
'uniform mat4 Mmatrix;'+
'attribute vec3 color;'+//the color of the point
'varying vec3 vColor;'+
'void main(void) { '+//pre-built function
'gl_Position = Pmatrix*Vmatrix*Mmatrix*vec4(position, 1.);'+
'vColor = color;'+
'}';
var fragCode = 'precision mediump float;'+
'varying vec3 vColor;'+
'void main(void) {'+
'gl_FragColor = vec4(vColor, 1.);'+
'}';
var vertShader = gl.createShader(gl.VERTEX_SHADER);
gl.shaderSource(vertShader, vertCode);
gl.compileShader(vertShader);
var fragShader = gl.createShader(gl.FRAGMENT_SHADER);
gl.shaderSource(fragShader, fragCode);
gl.compileShader(fragShader);
var shaderProgram = gl.createProgram();
gl.attachShader(shaderProgram, vertShader);
gl.attachShader(shaderProgram, fragShader);
gl.linkProgram(shaderProgram);
/*===========associating attributes to vertex shader ============*/
var Pmatrix = gl.getUniformLocation(shaderProgram, "Pmatrix");
var Vmatrix = gl.getUniformLocation(shaderProgram, "Vmatrix");
var Mmatrix = gl.getUniformLocation(shaderProgram, "Mmatrix");
gl.bindBuffer(gl.ARRAY_BUFFER, vertex_buffer);
var position = gl.getAttribLocation(shaderProgram, "position");
gl.vertexAttribPointer(position, 3, gl.FLOAT, false,0,0) ; //position
gl.enableVertexAttribArray(position);
gl.bindBuffer(gl.ARRAY_BUFFER, color_buffer);
var color = gl.getAttribLocation(shaderProgram, "color");
gl.vertexAttribPointer(color, 3, gl.FLOAT, false,0,0) ; //color
gl.enableVertexAttribArray(color);
gl.useProgram(shaderProgram);
/*========================= MATRIX ========================= */
function get_projection(angle, a, zMin, zMax) {
var ang = Math.tan((angle*.5)*Math.PI/180);//angle*.5
return [
0.5/ang, 0 , 0, 0,
0, 0.5*a/ang, 0, 0,
0, 0, -(zMax+zMin)/(zMax-zMin), -1,
0, 0, (-2*zMax*zMin)/(zMax-zMin), 0
];
}
var proj_matrix = get_projection(40, canvas.width/canvas.height, 1, 100);
var mov_matrix = [1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1];
var view_matrix = [1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1];
//translating z
view_matrix[14] = view_matrix[14]-6; //zoom
/*=======================rotation========================*/
function rotateZ(m, angle) {
var c = Math.cos(angle);
var s = Math.sin(angle);
var mv0 = m[0], mv4 = m[4], mv8 = m[8];
m[0] = c*m[0]-s*m[1];
m[4] = c*m[4]-s*m[5];
m[8] = c*m[8]-s*m[9];
m[1] = c*m[1]+s*mv0;
m[5] = c*m[5]+s*mv4;
m[9] = c*m[9]+s*mv8;
}
/*=================Drawing===========================*/
var time_old = 0;
var animate = function(time) {
var dt = time-time_old;
rotateZ(mov_matrix, dt*0.002);
time_old = time;
gl.enable(gl.DEPTH_TEST);
gl.depthFunc(gl.LEQUAL);
gl.clearColor(0.5, 0.5, 0.5, 0.9);
gl.clearDepth(1.0);
gl.viewport(0.0, 0.0, canvas.width, canvas.height);
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
gl.uniformMatrix4fv(Pmatrix, false, proj_matrix);
gl.uniformMatrix4fv(Vmatrix, false, view_matrix);
gl.uniformMatrix4fv(Mmatrix, false, mov_matrix);
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, index_buffer);
gl.drawElements(gl.TRIANGLES, indices.length, gl.UNSIGNED_SHORT, 0);
window.requestAnimationFrame(animate);
}
animate(0);
</script>
</body>
</html>
Jeśli uruchomisz ten przykład, wygeneruje on następujące dane wyjściowe -
W tym rozdziale weźmiemy przykład pokazujący, jak narysować obracającą się kostkę 3D za pomocą WebGL.
Przykład - narysuj obracającą się kostkę 3D
Poniższy program pokazuje, jak narysować obracającą się kostkę 3D -
<!doctype html>
<html>
<body>
<canvas width = "570" height = "570" id = "my_Canvas"></canvas>
<script>
/*============= Creating a canvas =================*/
var canvas = document.getElementById('my_Canvas');
gl = canvas.getContext('experimental-webgl');
/*============ Defining and storing the geometry =========*/
var vertices = [
-1,-1,-1, 1,-1,-1, 1, 1,-1, -1, 1,-1,
-1,-1, 1, 1,-1, 1, 1, 1, 1, -1, 1, 1,
-1,-1,-1, -1, 1,-1, -1, 1, 1, -1,-1, 1,
1,-1,-1, 1, 1,-1, 1, 1, 1, 1,-1, 1,
-1,-1,-1, -1,-1, 1, 1,-1, 1, 1,-1,-1,
-1, 1,-1, -1, 1, 1, 1, 1, 1, 1, 1,-1,
];
var colors = [
5,3,7, 5,3,7, 5,3,7, 5,3,7,
1,1,3, 1,1,3, 1,1,3, 1,1,3,
0,0,1, 0,0,1, 0,0,1, 0,0,1,
1,0,0, 1,0,0, 1,0,0, 1,0,0,
1,1,0, 1,1,0, 1,1,0, 1,1,0,
0,1,0, 0,1,0, 0,1,0, 0,1,0
];
var indices = [
0,1,2, 0,2,3, 4,5,6, 4,6,7,
8,9,10, 8,10,11, 12,13,14, 12,14,15,
16,17,18, 16,18,19, 20,21,22, 20,22,23
];
// Create and store data into vertex buffer
var vertex_buffer = gl.createBuffer ();
gl.bindBuffer(gl.ARRAY_BUFFER, vertex_buffer);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertices), gl.STATIC_DRAW);
// Create and store data into color buffer
var color_buffer = gl.createBuffer ();
gl.bindBuffer(gl.ARRAY_BUFFER, color_buffer);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(colors), gl.STATIC_DRAW);
// Create and store data into index buffer
var index_buffer = gl.createBuffer ();
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, index_buffer);
gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new Uint16Array(indices), gl.STATIC_DRAW);
/*=================== Shaders =========================*/
var vertCode = 'attribute vec3 position;'+
'uniform mat4 Pmatrix;'+
'uniform mat4 Vmatrix;'+
'uniform mat4 Mmatrix;'+
'attribute vec3 color;'+//the color of the point
'varying vec3 vColor;'+
'void main(void) { '+//pre-built function
'gl_Position = Pmatrix*Vmatrix*Mmatrix*vec4(position, 1.);'+
'vColor = color;'+
'}';
var fragCode = 'precision mediump float;'+
'varying vec3 vColor;'+
'void main(void) {'+
'gl_FragColor = vec4(vColor, 1.);'+
'}';
var vertShader = gl.createShader(gl.VERTEX_SHADER);
gl.shaderSource(vertShader, vertCode);
gl.compileShader(vertShader);
var fragShader = gl.createShader(gl.FRAGMENT_SHADER);
gl.shaderSource(fragShader, fragCode);
gl.compileShader(fragShader);
var shaderProgram = gl.createProgram();
gl.attachShader(shaderProgram, vertShader);
gl.attachShader(shaderProgram, fragShader);
gl.linkProgram(shaderProgram);
/* ====== Associating attributes to vertex shader =====*/
var Pmatrix = gl.getUniformLocation(shaderProgram, "Pmatrix");
var Vmatrix = gl.getUniformLocation(shaderProgram, "Vmatrix");
var Mmatrix = gl.getUniformLocation(shaderProgram, "Mmatrix");
gl.bindBuffer(gl.ARRAY_BUFFER, vertex_buffer);
var position = gl.getAttribLocation(shaderProgram, "position");
gl.vertexAttribPointer(position, 3, gl.FLOAT, false,0,0) ;
// Position
gl.enableVertexAttribArray(position);
gl.bindBuffer(gl.ARRAY_BUFFER, color_buffer);
var color = gl.getAttribLocation(shaderProgram, "color");
gl.vertexAttribPointer(color, 3, gl.FLOAT, false,0,0) ;
// Color
gl.enableVertexAttribArray(color);
gl.useProgram(shaderProgram);
/*==================== MATRIX =====================*/
function get_projection(angle, a, zMin, zMax) {
var ang = Math.tan((angle*.5)*Math.PI/180);//angle*.5
return [
0.5/ang, 0 , 0, 0,
0, 0.5*a/ang, 0, 0,
0, 0, -(zMax+zMin)/(zMax-zMin), -1,
0, 0, (-2*zMax*zMin)/(zMax-zMin), 0
];
}
var proj_matrix = get_projection(40, canvas.width/canvas.height, 1, 100);
var mov_matrix = [1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1];
var view_matrix = [1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1];
// translating z
view_matrix[14] = view_matrix[14]-6;//zoom
/*==================== Rotation ====================*/
function rotateZ(m, angle) {
var c = Math.cos(angle);
var s = Math.sin(angle);
var mv0 = m[0], mv4 = m[4], mv8 = m[8];
m[0] = c*m[0]-s*m[1];
m[4] = c*m[4]-s*m[5];
m[8] = c*m[8]-s*m[9];
m[1]=c*m[1]+s*mv0;
m[5]=c*m[5]+s*mv4;
m[9]=c*m[9]+s*mv8;
}
function rotateX(m, angle) {
var c = Math.cos(angle);
var s = Math.sin(angle);
var mv1 = m[1], mv5 = m[5], mv9 = m[9];
m[1] = m[1]*c-m[2]*s;
m[5] = m[5]*c-m[6]*s;
m[9] = m[9]*c-m[10]*s;
m[2] = m[2]*c+mv1*s;
m[6] = m[6]*c+mv5*s;
m[10] = m[10]*c+mv9*s;
}
function rotateY(m, angle) {
var c = Math.cos(angle);
var s = Math.sin(angle);
var mv0 = m[0], mv4 = m[4], mv8 = m[8];
m[0] = c*m[0]+s*m[2];
m[4] = c*m[4]+s*m[6];
m[8] = c*m[8]+s*m[10];
m[2] = c*m[2]-s*mv0;
m[6] = c*m[6]-s*mv4;
m[10] = c*m[10]-s*mv8;
}
/*================= Drawing ===========================*/
var time_old = 0;
var animate = function(time) {
var dt = time-time_old;
rotateZ(mov_matrix, dt*0.005);//time
rotateY(mov_matrix, dt*0.002);
rotateX(mov_matrix, dt*0.003);
time_old = time;
gl.enable(gl.DEPTH_TEST);
gl.depthFunc(gl.LEQUAL);
gl.clearColor(0.5, 0.5, 0.5, 0.9);
gl.clearDepth(1.0);
gl.viewport(0.0, 0.0, canvas.width, canvas.height);
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
gl.uniformMatrix4fv(Pmatrix, false, proj_matrix);
gl.uniformMatrix4fv(Vmatrix, false, view_matrix);
gl.uniformMatrix4fv(Mmatrix, false, mov_matrix);
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, index_buffer);
gl.drawElements(gl.TRIANGLES, indices.length, gl.UNSIGNED_SHORT, 0);
window.requestAnimationFrame(animate);
}
animate(0);
</script>
</body>
</html>
Jeśli uruchomisz ten przykład, wygeneruje on następujące dane wyjściowe -
W tym rozdziale weźmiemy przykład pokazujący, jak narysować kostkę 3D, którą można obracać za pomocą myszy.
Przykład - narysuj interaktywną kostkę
Poniższy program pokazuje, jak obracać kostkę za pomocą przycisków myszy -
<!doctype html>
<html>
<body>
<canvas width = "570" height = "570" id = "my_Canvas"></canvas>
<script>
/*============= Creating a canvas ======================*/
var canvas = document.getElementById('my_Canvas');
gl = canvas.getContext('experimental-webgl');
/*========== Defining and storing the geometry ==========*/
var vertices = [
-1,-1,-1, 1,-1,-1, 1, 1,-1, -1, 1,-1,
-1,-1, 1, 1,-1, 1, 1, 1, 1, -1, 1, 1,
-1,-1,-1, -1, 1,-1, -1, 1, 1, -1,-1, 1,
1,-1,-1, 1, 1,-1, 1, 1, 1, 1,-1, 1,
-1,-1,-1, -1,-1, 1, 1,-1, 1, 1,-1,-1,
-1, 1,-1, -1, 1, 1, 1, 1, 1, 1, 1,-1,
];
var colors = [
5,3,7, 5,3,7, 5,3,7, 5,3,7,
1,1,3, 1,1,3, 1,1,3, 1,1,3,
0,0,1, 0,0,1, 0,0,1, 0,0,1,
1,0,0, 1,0,0, 1,0,0, 1,0,0,
1,1,0, 1,1,0, 1,1,0, 1,1,0,
0,1,0, 0,1,0, 0,1,0, 0,1,0
];
var indices = [
0,1,2, 0,2,3, 4,5,6, 4,6,7,
8,9,10, 8,10,11, 12,13,14, 12,14,15,
16,17,18, 16,18,19, 20,21,22, 20,22,23
];
// Create and store data into vertex buffer
var vertex_buffer = gl.createBuffer ();
gl.bindBuffer(gl.ARRAY_BUFFER, vertex_buffer);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertices), gl.STATIC_DRAW);
// Create and store data into color buffer
var color_buffer = gl.createBuffer ();
gl.bindBuffer(gl.ARRAY_BUFFER, color_buffer);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(colors), gl.STATIC_DRAW);
// Create and store data into index buffer
var index_buffer = gl.createBuffer ();
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, index_buffer);
gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new Uint16Array(indices), gl.STATIC_DRAW);
/*=================== SHADERS =================== */
var vertCode = 'attribute vec3 position;'+
'uniform mat4 Pmatrix;'+
'uniform mat4 Vmatrix;'+
'uniform mat4 Mmatrix;'+
'attribute vec3 color;'+//the color of the point
'varying vec3 vColor;'+
'void main(void) { '+//pre-built function
'gl_Position = Pmatrix*Vmatrix*Mmatrix*vec4(position, 1.);'+
'vColor = color;'+
'}';
var fragCode = 'precision mediump float;'+
'varying vec3 vColor;'+
'void main(void) {'+
'gl_FragColor = vec4(vColor, 1.);'+
'}';
var vertShader = gl.createShader(gl.VERTEX_SHADER);
gl.shaderSource(vertShader, vertCode);
gl.compileShader(vertShader);
var fragShader = gl.createShader(gl.FRAGMENT_SHADER);
gl.shaderSource(fragShader, fragCode);
gl.compileShader(fragShader);
var shaderprogram = gl.createProgram();
gl.attachShader(shaderprogram, vertShader);
gl.attachShader(shaderprogram, fragShader);
gl.linkProgram(shaderprogram);
/*======== Associating attributes to vertex shader =====*/
var _Pmatrix = gl.getUniformLocation(shaderprogram, "Pmatrix");
var _Vmatrix = gl.getUniformLocation(shaderprogram, "Vmatrix");
var _Mmatrix = gl.getUniformLocation(shaderprogram, "Mmatrix");
gl.bindBuffer(gl.ARRAY_BUFFER, vertex_buffer);
var _position = gl.getAttribLocation(shaderprogram, "position");
gl.vertexAttribPointer(_position, 3, gl.FLOAT, false,0,0);
gl.enableVertexAttribArray(_position);
gl.bindBuffer(gl.ARRAY_BUFFER, color_buffer);
var _color = gl.getAttribLocation(shaderprogram, "color");
gl.vertexAttribPointer(_color, 3, gl.FLOAT, false,0,0) ;
gl.enableVertexAttribArray(_color);
gl.useProgram(shaderprogram);
/*==================== MATRIX ====================== */
function get_projection(angle, a, zMin, zMax) {
var ang = Math.tan((angle*.5)*Math.PI/180);//angle*.5
return [
0.5/ang, 0 , 0, 0,
0, 0.5*a/ang, 0, 0,
0, 0, -(zMax+zMin)/(zMax-zMin), -1,
0, 0, (-2*zMax*zMin)/(zMax-zMin), 0
];
}
var proj_matrix = get_projection(40, canvas.width/canvas.height, 1, 100);
var mo_matrix = [ 1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1 ];
var view_matrix = [ 1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1 ];
view_matrix[14] = view_matrix[14]-6;
/*================= Mouse events ======================*/
var AMORTIZATION = 0.95;
var drag = false;
var old_x, old_y;
var dX = 0, dY = 0;
var mouseDown = function(e) {
drag = true;
old_x = e.pageX, old_y = e.pageY;
e.preventDefault();
return false;
};
var mouseUp = function(e){
drag = false;
};
var mouseMove = function(e) {
if (!drag) return false;
dX = (e.pageX-old_x)*2*Math.PI/canvas.width,
dY = (e.pageY-old_y)*2*Math.PI/canvas.height;
THETA+= dX;
PHI+=dY;
old_x = e.pageX, old_y = e.pageY;
e.preventDefault();
};
canvas.addEventListener("mousedown", mouseDown, false);
canvas.addEventListener("mouseup", mouseUp, false);
canvas.addEventListener("mouseout", mouseUp, false);
canvas.addEventListener("mousemove", mouseMove, false);
/*=========================rotation================*/
function rotateX(m, angle) {
var c = Math.cos(angle);
var s = Math.sin(angle);
var mv1 = m[1], mv5 = m[5], mv9 = m[9];
m[1] = m[1]*c-m[2]*s;
m[5] = m[5]*c-m[6]*s;
m[9] = m[9]*c-m[10]*s;
m[2] = m[2]*c+mv1*s;
m[6] = m[6]*c+mv5*s;
m[10] = m[10]*c+mv9*s;
}
function rotateY(m, angle) {
var c = Math.cos(angle);
var s = Math.sin(angle);
var mv0 = m[0], mv4 = m[4], mv8 = m[8];
m[0] = c*m[0]+s*m[2];
m[4] = c*m[4]+s*m[6];
m[8] = c*m[8]+s*m[10];
m[2] = c*m[2]-s*mv0;
m[6] = c*m[6]-s*mv4;
m[10] = c*m[10]-s*mv8;
}
/*=================== Drawing =================== */
var THETA = 0,
PHI = 0;
var time_old = 0;
var animate = function(time) {
var dt = time-time_old;
if (!drag) {
dX *= AMORTIZATION, dY*=AMORTIZATION;
THETA+=dX, PHI+=dY;
}
//set model matrix to I4
mo_matrix[0] = 1, mo_matrix[1] = 0, mo_matrix[2] = 0,
mo_matrix[3] = 0,
mo_matrix[4] = 0, mo_matrix[5] = 1, mo_matrix[6] = 0,
mo_matrix[7] = 0,
mo_matrix[8] = 0, mo_matrix[9] = 0, mo_matrix[10] = 1,
mo_matrix[11] = 0,
mo_matrix[12] = 0, mo_matrix[13] = 0, mo_matrix[14] = 0,
mo_matrix[15] = 1;
rotateY(mo_matrix, THETA);
rotateX(mo_matrix, PHI);
time_old = time;
gl.enable(gl.DEPTH_TEST);
// gl.depthFunc(gl.LEQUAL);
gl.clearColor(0.5, 0.5, 0.5, 0.9);
gl.clearDepth(1.0);
gl.viewport(0.0, 0.0, canvas.width, canvas.height);
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
gl.uniformMatrix4fv(_Pmatrix, false, proj_matrix);
gl.uniformMatrix4fv(_Vmatrix, false, view_matrix);
gl.uniformMatrix4fv(_Mmatrix, false, mo_matrix);
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, index_buffer);
gl.drawElements(gl.TRIANGLES, indices.length, gl.UNSIGNED_SHORT, 0);
window.requestAnimationFrame(animate);
}
animate(0);
</script>
</body>
</html>
Jeśli uruchomisz ten przykład, wygeneruje on następujące dane wyjściowe -