WebGL - Guide rapide
Il y a quelques années, les applications Java - combinant applets et JOGL - étaient utilisées pour traiter des graphiques 3D sur le Web en adressant le GPU (Graphical Processing Unit). Comme les applets nécessitent une JVM pour fonctionner, il est devenu difficile de s'appuyer sur des applets Java. Quelques années plus tard, les gens ont cessé d'utiliser les applets Java.
Les API Stage3D fournies par Adobe (Flash, AIR) offraient une architecture accélérée par le matériel GPU. En utilisant ces technologies, les programmeurs pourraient développer des applications avec des capacités 2D et 3D sur les navigateurs Web ainsi que sur les plates-formes IOS et Android. Puisque Flash était un logiciel propriétaire, il n'était pas utilisé comme standard Web.
En mars 2011, WebGL est sorti. C'est un openware qui peut fonctionner sans JVM. Il est entièrement contrôlé par le navigateur Web.
La nouvelle version de HTML 5 dispose de plusieurs fonctionnalités pour prendre en charge les graphiques 3D tels que 2D Canvas, WebGL, SVG, les transformations CSS 3D et SMIL. Dans ce tutoriel, nous couvrirons les bases de WebGL.
Qu'est-ce qu'OpenGL?
OpenGL (Open Graphics Library) est une API cross-language et multiplateforme pour les graphiques 2D et 3D. C'est une collection de commandes. OpenGL4.5 est la dernière version d'OpenGL. Le tableau suivant répertorie un ensemble de technologies liées à OpenGL.
API | Technologie utilisée |
---|---|
OpenGL ES | C'est la bibliothèque pour les graphiques 2D et 3D sur les systèmes embarqués - y compris les consoles, les téléphones, les appareils et les véhicules. OpenGL ES 3.1 est sa dernière version. Il est maintenu par le groupe Khronos www.khronos.org |
JOGL | Il s'agit de la liaison Java pour OpenGL. JOGL 4.5 est sa dernière version et il est maintenu par jogamp.org. |
WebGL | Il s'agit de la liaison JavaScript pour OpenGL. WebGL 1.0 est sa dernière version et il est maintenu par le groupe khronos . |
OpenGLSL | OpenGL Shading Language. C'est un langage de programmation qui accompagne OpenGL 2.0 et supérieur. Il fait partie de la spécification OpenGL 4.4. Il s'agit d'une API spécialement conçue pour les systèmes embarqués tels que ceux présents sur les téléphones mobiles et les tablettes. |
Note - Dans WebGL, nous utilisons GLSL pour écrire des shaders.
Qu'est-ce que WebGL?
WebGL (Web Graphics Library) est le nouveau standard pour les graphiques 3D sur le Web.Il est conçu dans le but de rendre des graphiques 2D et des graphiques 3D interactifs. Il est dérivé de la bibliothèque ES 2.0 d'OpenGL qui est une API 3D de bas niveau pour les téléphones et autres appareils mobiles. WebGL fournit des fonctionnalités similaires à ES 2.0 (systèmes embarqués) et fonctionne bien sur le matériel graphique 3D moderne.
C'est une API JavaScript qui peut être utilisée avec HTML5. Le code WebGL est écrit dans la balise <canvas> de HTML5. Il s'agit d'une spécification qui permet aux navigateurs Internet d'accéder aux unités de traitement graphique (GPU) sur les ordinateurs où elles ont été utilisées.
Qui a développé WebGL
Un ingénieur logiciel américano-serbe nommé Vladimir Vukicevic a fait le travail de fondation et dirigé la création de WebGL
En 2007, Vladimir a commencé à travailler sur un OpenGL prototype pour l'élément Canvas du document HTML.
En mars 2011, Kronos Group a créé WebGL.
Le rendu
Le rendu est le processus de génération d'une image à partir d'un modèle à l'aide de programmes informatiques. Dans les graphiques, une scène virtuelle est décrite à l'aide d'informations telles que la géométrie, le point de vue, la texture, l'éclairage et l'ombrage, qui sont transmises à un programme de rendu. La sortie de ce programme de rendu sera une image numérique.
Il existe deux types de rendu -
Software Rendering - Tous les calculs de rendu sont effectués à l'aide du CPU.
Hardware Rendering - Tous les calculs graphiques sont effectués par le GPU (Unité de traitement graphique).
Le rendu peut être effectué localement ou à distance. Si l'image à rendre est beaucoup trop complexe, le rendu se fait à distance sur un serveur dédié disposant de suffisamment de ressources matérielles nécessaires pour rendre des scènes complexes. Il est également appelé commeserver-based rendering. Le rendu peut également être effectué localement par le CPU. Il est appelé commeclient-based rendering.
WebGL suit une approche de rendu basée sur le client pour rendre les scènes 3D. Tous les traitements nécessaires pour obtenir une image sont effectués localement à l'aide du matériel graphique du client.
GPU
Selon NVIDIA, un GPU est «un processeur à puce unique avec des moteurs intégrés de transformation, d'éclairage, de configuration / découpage de triangle et de rendu capable de traiter un minimum de 10 millions de polygones par seconde». Contrairement aux processeurs multicœurs avec quelques cœurs optimisés pour le traitement séquentiel, un GPU se compose de milliers de cœurs plus petits qui traitent efficacement les charges de travail parallèles. Par conséquent, le GPU accélère la création d'images dans un tampon de trame (une partie de la RAM qui contient des données de trame complètes) destiné à la sortie sur un écran.
Calcul accéléré par GPU
Dans le calcul accéléré par GPU, l'application est chargée dans le CPU. Chaque fois qu'il rencontre uncompute-intensivepartie du code, cette partie du code sera chargée et exécutée sur le GPU. Il donne au système la possibilité de traiter les graphiques de manière efficace.
Le GPU aura une mémoire séparée et exécutera plusieurs copies d'une petite partie du code à la fois. Le GPU traite toutes les données qui se trouvent dans sa mémoire locale, et non la mémoire centrale. Par conséquent, les données qui doivent être traitées par le GPU doivent être chargées / copiées dans la mémoire du GPU, puis traitées.
Dans les systèmes ayant l'architecture ci-dessus, la surcharge de communication entre le CPU et le GPU doit être réduite pour obtenir un traitement plus rapide des programmes 3D. Pour cela, nous devons copier toutes les données et les conserver sur le GPU, au lieu de communiquer avec le GPU à plusieurs reprises.
Navigateurs pris en charge
Les tableaux suivants présentent une liste de navigateurs prenant en charge WebGL -
Navigateurs Web
Nom du navigateur | Version | Soutien |
---|---|---|
IInternet Explorer | 11 et plus | Assistance complète |
Google Chrome | 39 et plus | Assistance complète |
Safari | 8 | Assistance complète |
Firefox | 36 et plus | Support partiel |
Opéra | 27 et plus | Support partiel |
Navigateurs mobiles
Nom du navigateur | Version | Soutien |
---|---|---|
Chrome pour Android | 42 | Support partiel |
Navigateur Android | 40 | Support partiel |
Safari sous iOS | 8.3 | Assistance complète |
Opera Mini | 8 | Ne supporte pas |
Navigateur Blackberry | dix | Assistance complète |
Mobile IE | dix | Support partiel |
Avantages de WebGL
Voici les avantages de l'utilisation de WebGL -
JavaScript programming- Les applications WebGL sont écrites en JavaScript. En utilisant ces applications, vous pouvez interagir directement avec d'autres éléments du document HTML. Vous pouvez également utiliser d'autres bibliothèques JavaScript (par exemple JQuery) et technologies HTML pour enrichir l'application WebGL.
Increasing support with mobile browsers - WebGL prend également en charge les navigateurs mobiles tels que iOS Safari, Android Browser et Chrome pour Android.
Open source- WebGL est une source ouverte. Vous pouvez accéder au code source de la bibliothèque et comprendre comment elle fonctionne et comment elle a été développée.
No need for compilation- JavaScript est un composant mi-programmation et mi-HTML. Pour exécuter ce script, il n'est pas nécessaire de compiler le fichier. Au lieu de cela, vous pouvez ouvrir directement le fichier à l'aide de l'un des navigateurs et vérifier le résultat. Étant donné que les applications WebGL sont développées à l'aide de JavaScript, il n'est pas nécessaire de compiler également les applications WebGL.
Automatic memory management- JavaScript prend en charge la gestion automatique de la mémoire. Il n'y a pas besoin d'allocation manuelle de mémoire. WebGL hérite de cette fonctionnalité de JavaScript.
Easy to set up- Étant donné que WebGL est intégré à HTML 5, aucune configuration supplémentaire n'est nécessaire. Pour écrire une application WebGL, il vous suffit d'un éditeur de texte et d'un navigateur Web.
Configuration de l'environnement
Il n'est pas nécessaire de définir un environnement différent pour WebGL. Les navigateurs prenant en charge WebGL ont leur propre configuration intégrée pour WebGL.
Pour créer des applications graphiques sur le Web, HTML-5 fournit un riche ensemble de fonctionnalités telles que 2D Canvas, WebGL, SVG, les transformations CSS 3D et SMIL. Pour écrire des applications WebGL, nous utilisons l'élément canvas existant de HTML-5. Ce chapitre donne un aperçu de l'élément de canevas 2D HTML-5.
Toile HTML5
HTML-5 <canvas>fournit une option simple et puissante pour dessiner des graphiques à l'aide de JavaScript. Il peut être utilisé pour dessiner des graphiques, créer des compositions photo ou faire des animations simples (et pas si simples).
Voici un simple <canvas> élément n'ayant que deux attributs spécifiques width et height plus tous les attributs HTML-5 de base tels que l'identifiant, le nom et la classe.
Syntaxe
La syntaxe de la balise HTML canvas est donnée ci-dessous. Vous devez mentionner le nom du canevas entre guillemets doubles («»).
<canvas id = "mycanvas" width = "100" height = "100"></canvas>
Attributs du canevas
La balise canvas a trois attributs à savoir, id, width et height.
Id- Id représente l'identifiant de l'élément canvas dans le Document Object Model (DOM) .
Width - La largeur représente la largeur de la toile.
Height - La hauteur représente la hauteur de la toile.
Ces attributs déterminent la taille du canevas. Si un programmeur ne les spécifie pas sous la balise canvas, les navigateurs tels que Firefox, Chrome et Web Kit fournissent par défaut un élément canvas de taille 300 × 150.
Exemple - Créer un canevas
Le code suivant montre comment créer un canevas. Nous avons utilisé CSS pour donner une bordure colorée à la toile.
<html>
<head>
<style>
#mycanvas{border:1px solid red;}
</style>
</head>
<body>
<canvas id = "mycanvas" width = "100" height = "100"></canvas>
</body>
</html>
Lors de l'exécution, le code ci-dessus produira la sortie suivante -
Le contexte de rendu
Le <canvas> est initialement vide. Pour afficher quelque chose sur l'élément canvas, nous devons utiliser un langage de script. Ce langage de script doit accéder au contexte de rendu et s'inspirer de celui-ci.
L'élément canvas a une méthode DOM appelée getContext(), qui est utilisé pour obtenir le contexte de rendu et ses fonctions de dessin. Cette méthode prend un paramètre, le type de contexte2d.
Le code suivant doit être écrit pour obtenir le contexte requis. Vous pouvez écrire ce script dans la balise body comme indiqué ci-dessous.
<!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>
Lors de l'exécution, le code ci-dessus produira la sortie suivante -
Pour plus d'exemples sur HTML-5 2D Canvas, consultez le lien suivant HTML-5 Canvas .
Contexte WebGL
HTML5 Canvas est également utilisé pour écrire des applications WebGL. Pour créer un contexte de rendu WebGL sur l'élément canvas, vous devez passer la chaîneexperimental-webgl, au lieu de 2d à la canvas.getContext()méthode. Certains navigateurs ne prennent en charge que "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>
Lors de l'exécution, le code ci-dessus produira la sortie suivante -
WebGL est principalement une API de rastérisation de bas niveau plutôt qu'une API 3D. Pour dessiner une image en utilisant WebGL, vous devez passer un vecteur représentant l'image. Il convertit ensuite le vecteur donné en format pixel à l'aide d'OpenGL SL et affiche l'image à l'écran. L'écriture d'une application WebGL implique un ensemble d'étapes que nous expliquerons dans ce chapitre.
WebGL - Système de coordonnées
Comme tout autre système 3D, vous aurez les axes x, y et z dans WebGL, où le z axe signifie depth. Les coordonnées dans WebGL sont limitées à (1, 1, 1) et (-1, -1, - 1). Cela signifie que si vous considérez l'écran projetant des graphiques WebGL comme un cube, alors un coin du cube sera (1, 1, 1) et le coin opposé sera (-1, -1, -1). WebGL n'affichera rien de ce qui est dessiné au-delà de ces limites.
Le diagramme suivant illustre le système de coordonnées WebGL. L'axe z signifie la profondeur. Une valeur positive de z indique que l'objet est proche de l'écran / de la visionneuse, tandis qu'une valeur négative de z indique que l'objet est loin de l'écran. De même, une valeur positive de x indique que l'objet est sur le côté droit de l'écran et une valeur négative indique que l'objet est sur le côté gauche. De même, les valeurs positives et négatives de y indiquent si l'objet est en haut ou en bas de l'écran.
Graphiques WebGL
Après avoir obtenu le contexte WebGL de l'objet canevas, vous pouvez commencer à dessiner des éléments graphiques à l'aide de l'API WebGL en JavaScript.
Voici quelques termes fondamentaux que vous devez connaître avant de commencer avec WebGL.
Sommets
Généralement, pour dessiner des objets tels qu'un polygone, nous marquons les points sur le plan et les joignons pour former un polygone souhaité. UNEvertexest un point qui définit la conjonction des bords d'un objet 3D. Il est représenté par trois valeurs à virgule flottante représentant chacune respectivement les axes x, y, z.
Exemple
Dans l'exemple suivant, nous dessinons un triangle avec les sommets suivants - (0,5, 0,5), (-0,5, 0,5), (-0,5, -0,5).
Note - Nous devons stocker ces sommets manuellement à l'aide de tableaux JavaScript et les transmettre au pipeline de rendu WebGL à l'aide du tampon de vertex.
Les indices
Dans WebGL, des valeurs numériques sont utilisées pour identifier les sommets. Ces valeurs numériques sont appelées indices. Ces indices sont utilisés pour dessiner des maillages dans WebGL.
Note - Tout comme les sommets, nous stockons les index à l'aide de tableaux JavaScript et les passons au pipeline de rendu WebGL à l'aide du tampon d'index.
Tableaux
Contrairement à OpenGL et JoGL, il n'y a pas de méthodes prédéfinies dans WebGL pour rendre directement les sommets. Nous devons les stocker manuellement à l'aide de tableaux JavaScript.
Exemple
var vertices = [ 0.5, 0.5, 0.1,-0.5, 0.5,-0.5]
Tampons
Les tampons sont les zones de mémoire de WebGL qui contiennent les données. Il existe différents tampons, à savoir le tampon de dessin, le tampon de trame, le tampon vetex et le tampon d'index. levertex buffer et index buffer sont utilisés pour décrire et traiter la géométrie du modèle.
Les objets de tampon de sommet stockent des données sur les sommets, tandis que les objets de tampon d'index stockent des données sur les index. Après avoir stocké les sommets dans des tableaux, nous les transmettons au pipeline graphique WegGL à l'aide de ces objets Buffer.
Frame bufferest une partie de la mémoire graphique qui contient les données de scène. Ce tampon contient des détails tels que la largeur et la hauteur de la surface (en pixels), la couleur de chaque pixel, la profondeur et les tampons de gabarit.
Engrener
Pour dessiner des objets 2D ou 3D, l'API WebGL propose deux méthodes à savoir, drawArrays() et drawElements(). Ces deux méthodes acceptent un paramètre appelémodeà l'aide duquel vous pouvez sélectionner l'objet que vous souhaitez dessiner. Les options fournies par ce champ sont limitées aux points, lignes et triangles.
Pour dessiner un objet 3D en utilisant ces deux méthodes, nous devons construire un ou plusieurs polygones primitifs à l'aide de points, de lignes ou de triangles. Par la suite, en utilisant ces polygones primitifs, nous pouvons former un maillage.
Un objet 3D dessiné à l'aide de polygones primitifs est appelé un mesh. WebGL propose plusieurs façons de dessiner des objets graphiques 3D, mais les utilisateurs préfèrent généralement dessiner un maillage.
Exemple
Dans l'exemple suivant, vous pouvez observer que nous avons dessiné un carré en utilisant deux triangles → {1, 2, 3} et {4, 1, 3}.
Programmes Shader
Nous utilisons normalement des triangles pour construire des maillages. Étant donné que WebGL utilise le calcul accéléré par GPU, les informations sur ces triangles doivent être transférées du CPU au GPU, ce qui prend beaucoup de temps de communication.
WebGL fournit une solution pour réduire la surcharge de communication. Puisqu'il utilise ES SL (Embedded System Shader Language) qui s'exécute sur GPU, nous écrivons tous les programmes nécessaires pour dessiner des éléments graphiques sur le système client en utilisantshader programs (les programmes que nous écrivons en utilisant OpenGL ES Shading Language / GLSL).
Ces shaders sont les programmes pour GPU et le langage utilisé pour écrire les programmes de shaders est GLSL. Dans ces shaders, nous définissons exactement comment les sommets, les transformations, les matériaux, les lumières et la caméra interagissent les uns avec les autres pour créer une image particulière.
En bref, c'est un extrait de code qui implémente des algorithmes pour obtenir des pixels pour un maillage. Nous discuterons plus en détail des shaders dans les chapitres suivants. Il existe deux types de shaders: Vertex Shader et Fragment Shader.
Vertex Shader
Vertext shader est le code du programme appelé sur chaque sommet. Il est utilisé pour transformer (déplacer) la géométrie (ex: triangle) d'un endroit à un autre. Il gère les données de chaque sommet (données par sommet) telles que les coordonnées de sommet, les normales, les couleurs et les coordonnées de texture.
dans le ES GLcode du vertex shader, les programmeurs doivent définir des attributs pour gérer les données. Ces attributs pointent vers unVertex Buffer Object écrit en JavaScript.
Les tâches suivantes peuvent être effectuées à l'aide de vertex shaders -
- Transformation de sommet
- Transformation et normalisation normales
- Génération de coordonnées de texture
- Transformation des coordonnées de texture
- Lighting
- Application du matériau de couleur
Fragment Shader (Pixel Shader)
Un maillage est formé de plusieurs triangles et la surface de chacun des triangles est connue sous le nom de fragment. Fragment shader est le code qui s'exécute sur tous les pixels de chaque fragment. Il est écrit pour calculer et remplir la couleur sur des pixels individuels .
Les tâches suivantes peuvent être effectuées à l'aide des shaders Fragment -
- Opérations sur les valeurs interpolées
- Accès à la texture
- Application de texture
- Fog
- Somme des couleurs
Variables OpenGL ES SL
La forme complète de OpenGL ES SLest OpenGL Embedded System Shading Language. Pour gérer les données dans les programmes de shader, ES SL fournit trois types de variables. Ils sont les suivants -
Attributes- Ces variables contiennent les valeurs d'entrée du programme vertex shader. Les attributs pointent vers les objets de tampon de sommet qui contiennent des données par sommet. Chaque fois que le vertex shader est appelé, les attributs pointent vers le VBO de différents sommets.
Uniforms - Ces variables contiennent les données d'entrée communes aux ombrages de sommets et de fragments, telles que la position de la lumière, les coordonnées de texture et la couleur.
Varyings - Ces variables sont utilisées pour transmettre les données du vertex shader au fragment shader.
Avec autant de bases, nous allons maintenant passer à la discussion du pipeline graphique.
Pour rendre des graphiques 3D, nous devons suivre une séquence d'étapes. Ces étapes sont appeléesgraphics pipeline ou rendering pipeline. Le diagramme suivant illustre le pipeline graphique WebGL.
Dans les sections suivantes, nous aborderons une par une le rôle de chaque étape du pipeline.
JavaScript
Lors du développement d'applications WebGL, nous écrivons du code de langage Shader pour communiquer avec le GPU. JavaScript est utilisé pour écrire le code de contrôle du programme, qui comprend les actions suivantes -
Initialize WebGL - JavaScript est utilisé pour initialiser le contexte WebGL.
Create arrays - Nous créons des tableaux JavaScript pour contenir les données de la géométrie.
Buffer objects - Nous créons des objets tampons (sommet et index) en passant les tableaux comme paramètres.
Shaders - Nous créons, compilons et lions les shaders en utilisant JavaScript.
Attributes - Nous pouvons créer des attributs, les activer et les associer à des objets tampons en utilisant JavaScript.
Uniforms - On peut également associer les uniformes en utilisant JavaScript.
Transformation matrix - En utilisant JavaScript, nous pouvons créer une matrice de transformation.
Au départ, nous créons les données pour la géométrie requise et les transmettons aux shaders sous forme de tampons. La variable d'attribut du langage shader pointe vers les objets buffer, qui sont passés en tant qu'entrées au vertex shader.
Vertex Shader
Lorsque nous démarrons le processus de rendu en invoquant les méthodes drawElements() et drawArray(), le shader de sommet est exécuté pour chaque sommet fourni dans l'objet tampon de sommet. Il calcule la position de chaque sommet d'un polygone primitif et le stocke dans la variablegl_position. Il calcule également les autres attributs tels quecolor, texture coordinates, et vertices qui sont normalement associés à un sommet.
Assemblée primitive
Après avoir calculé la position et les autres détails de chaque sommet, la phase suivante est la primitive assembly stage. Ici, les triangles sont assemblés et transmis au rastériseur.
Rastérisation
Lors de l'étape de tramage, les pixels de l'image finale de la primitive sont déterminés. Il comporte deux étapes -
Culling- Dans un premier temps, l'orientation (est-elle orientée vers l'avant ou vers l'arrière?) Du polygone est déterminée. Tous les triangles avec une orientation incorrecte qui ne sont pas visibles dans la zone de visualisation sont supprimés. Ce processus s'appelle l'abattage.
Clipping- Si un triangle est partiellement en dehors de la zone de vue, alors la partie en dehors de la zone de vue est supprimée. Ce processus est connu sous le nom de découpage.
Fragment Shader
Le fragment shader obtient
- les données du vertex shader dans différentes variables,
- primitives de l'étape de rastérisation, puis
- calcule les valeurs de couleur pour chaque pixel entre les sommets.
Le shader de fragment stocke les valeurs de couleur de chaque pixel de chaque fragment. Ces valeurs de couleur peuvent être consultées pendant les opérations de fragment, dont nous allons discuter ensuite.
Opérations sur les fragments
Les opérations de fragment sont effectuées après avoir déterminé la couleur de chaque pixel de la primitive. Ces opérations de fragment peuvent inclure les éléments suivants:
- Depth
- Mélange de tampon de couleur
- Dithering
Une fois tous les fragments traités, une image 2D est formée et affichée à l'écran. leframe buffer est la destination finale du pipeline de rendu.
Tampon de trame
Le tampon de trame est une partie de la mémoire graphique qui contient les données de scène. Ce tampon contient des détails tels que la largeur et la hauteur de la surface (en pixels), la couleur de chaque pixel et les tampons de profondeur et de gabarit.
Nous avons discuté des bases de WebGL et du pipeline WebGL (une procédure suivie pour rendre les applications graphiques). Dans ce chapitre, nous allons prendre un exemple d'application pour créer un triangle à l'aide de WebGL et observer les étapes suivies dans l'application.
Structure de l'application WebGL
Le code d'application WebGL est une combinaison de JavaScript et d'OpenGL Shader Language.
- JavaScript est nécessaire pour communiquer avec le processeur
- Le langage OpenGL Shader est requis pour communiquer avec le GPU.
Exemple d'application
Prenons maintenant un exemple simple pour apprendre à utiliser WebGL pour dessiner un triangle simple avec des coordonnées 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>
Cela produira le résultat suivant -
Si vous observez attentivement le programme ci-dessus, nous avons suivi cinq étapes séquentielles pour dessiner un triangle simple en utilisant WebGL. Les étapes sont les suivantes -
Step 1 − Prepare the canvas and get WebGL rendering context
Nous obtenons l'objet canevas HTML actuel et obtenons son contexte de rendu WebGL.
Step 2 − Define the geometry and store it in buffer objects
Nous définissons les attributs de la géométrie tels que les sommets, les indices, la couleur, etc., et les stockons dans les tableaux JavaScript. Ensuite, nous créons un ou plusieurs objets tampons et passons les tableaux contenant les données à l'objet tampon respectif. Dans l'exemple, nous stockons les sommets du triangle dans un tableau JavaScript et passons ce tableau à un objet tampon de sommet.
Step 3 − Create and compile Shader programs
Nous écrivons des programmes vertex shader et fragment shader, les compilons et créons un programme combiné en liant ces deux programmes.
Step 4 − Associate the shader programs with buffer objects
Nous associons les objets tampons et le programme de shader combiné.
Step 5 − Drawing the required object (triangle)
Cette étape comprend des opérations telles que l'effacement de la couleur, l'effacement du bit de tampon, l'activation du test de profondeur, la définition du port d'affichage, etc. Enfin, vous devez dessiner les primitives requises en utilisant l'une des méthodes - drawArrays() ou drawElements().
Toutes ces étapes sont expliquées plus en détail dans ce tutoriel.
Pour écrire une application WebGL, la première étape consiste à obtenir l'objet de contexte de rendu WebGL. Cet objet interagit avec le tampon de dessin WebGL et peut appeler toutes les méthodes WebGL. Les opérations suivantes sont effectuées pour obtenir le contexte WebGL -
- Créer un canevas HTML-5
- Obtenez l'ID du canevas
- Obtenir WebGL
Création d'un élément de canevas HTML-5
Dans le chapitre 5, nous avons expliqué comment créer un élément de canevas HTML-5. Dans le corps du document HTML-5, écrivez un canevas, donnez-lui un nom et passez-le comme paramètre à l'ID d'attribut. Vous pouvez définir les dimensions du canevas à l'aide des attributs largeur et hauteur (facultatif).
Exemple
L'exemple suivant montre comment créer un élément de canevas avec les dimensions 500 × 500. Nous avons créé une bordure sur le canevas en utilisant CSS pour la visibilité. Copiez et collez le code suivant dans un fichier avec le nommy_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>
Cela produira le résultat suivant -
Obtenez l'identifiant du canevas
Après avoir créé le canevas, vous devez obtenir le contexte WebGL. La première chose à faire pour obtenir un contexte de dessin WebGL est d'obtenir l'id de l'élément de canevas courant.
L'ID de toile est acquis en appelant la méthode DOM (Document Object Model) getElementById(). Cette méthode accepte une valeur de chaîne comme paramètre, nous lui transmettons donc le nom du canevas actuel.
Par exemple, si le nom du canevas est my_canvas, alors l'ID du canevas est obtenu comme indiqué ci-dessous -
var canvas = document.getElementById('my_Canvas');
Obtenir le contexte de dessin WebGL
Pour obtenir l'objet WebGLRenderingContext (ou l'objet de contexte de dessin WebGL ou simplement le contexte WebGL), appelez le getContext() méthode du courant HTMLCanvasElement. La syntaxe de getContext () est la suivante -
canvas.getContext(contextType, contextAttributes);
Passer les ficelles webgl ou experimental-webgl comme le contentType. lecontextAttributesle paramètre est facultatif. (Tout en poursuivant cette étape, assurez-vous que votre navigateur implémente WebGL version 1 (OpenGL ES 2.0)).
L'extrait de code suivant montre comment obtenir le contexte de rendu WebGL. Icigl est la variable de référence à l'objet de contexte obtenu.
var canvas = document.getElementById('my_Canvas');
var gl = canvas.getContext('experimental-webgl');
WebGLContextAttributes
Le paramètre WebGLContextAttributesn'est pas obligatoire. Ce paramètre fournit diverses options qui acceptent les valeurs booléennes comme indiqué ci-dessous -
Sr.No. | Attributs et description |
---|---|
1 | Alpha Si sa valeur est true, il fournit un tampon alpha au canevas. Par défaut, sa valeur est true. |
2 | depth Si sa valeur est true, vous obtiendrez un tampon de dessin contenant un tampon de profondeur d'au moins 16 bits. Par défaut, sa valeur est true. |
3 | stencil Si sa valeur est true, vous obtiendrez un tampon de dessin contenant un tampon de gabarit d'au moins 8 bits. Par défaut, sa valeur est false. |
4 | antialias Si sa valeur est true, vous obtiendrez un tampon de dessin qui effectue l'anti-aliasing. Par défaut, sa valeur est true. |
5 | premultipliedAlpha Si sa valeur est true, vous obtiendrez un tampon de dessin contenant des couleurs avec alpha pré-multiplié. Par défaut, sa valeur est true. |
6 | preserveDrawingBuffer Si sa valeur est true, les tampons ne seront pas effacés et conserveront leurs valeurs jusqu'à ce qu'ils soient effacés ou écrasés par l'auteur. Par défaut, sa valeur est false. |
L'extrait de code suivant montre comment créer un contexte WebGL avec un tampon de gabarit, qui ne fonctionnera pas anti-aliasing.
var canvas = document.getElementById('canvas1');
var context = canvas.getContext('webgl', { antialias: false, stencil: true });
Au moment de la création du WebGLRenderingContext, un tampon de dessin est créé. L'objet Context gère l'état OpenGL et effectue le rendu dans le tampon de dessin.
WebGLRenderingContext
C'est la principale interface de WebGL. Il représente le contexte de dessin WebGL. Cette interface contient toutes les méthodes utilisées pour effectuer diverses tâches sur le tampon de dessin. Les attributs de cette interface sont donnés dans le tableau suivant.
Sr.No. | Attributs et description |
---|---|
1 | Canvas Il s'agit d'une référence à l'élément canvas qui a créé ce contexte. |
2 | drawingBufferWidth Cet attribut représente la largeur réelle du tampon de dessin. Il peut différer de l'attribut width de HTMLCanvasElement. |
3 | drawingBufferHeight Cet attribut représente la hauteur réelle du tampon de dessin. Il peut différer de l'attribut de hauteur de HTMLCanvasElement. |
Après avoir obtenu le contexte WebGL, vous devez définir la géométrie de la primitive (objet que vous souhaitez dessiner) et la stocker. Dans WebGL, nous définissons les détails d'une géométrie - par exemple, les sommets, les indices, la couleur de la primitive - à l'aide de tableaux JavaScript. Pour transmettre ces détails aux programmes de shader, nous devons créer les objets tampons et stocker (attacher) les tableaux JavaScript contenant les données dans les tampons respectifs.
Note: Plus tard, ces objets tampons seront associés aux attributs du programme shader (vertex shader).
Définition de la géométrie requise
Un modèle 2D ou 3D dessiné à l'aide de sommets est appelé mesh. Chaque facette d'un maillage est appelée unpolygon et un polygone est composé de 3 sommets ou plus.
Pour dessiner des modèles dans le contexte de rendu WebGL, vous devez définir les sommets et les index à l'aide de tableaux JavaScript. Par exemple, si nous voulons créer un triangle qui repose sur les coordonnées {(5,5), (-5,5), (-5, -5)} comme indiqué dans le diagramme, vous pouvez créer un tableau pour les sommets comme -
var vertices = [
0.5,0.5, //Vertex 1
0.5,-0.5, //Vertex 2
-0.5,-0.5, //Vertex 3
];
De même, vous pouvez créer un tableau pour les index. Les indices pour les indices triangulaires ci-dessus seront [0, 1, 2] et peuvent être définis comme -
var indices = [ 0,1,2 ]
Pour une meilleure compréhension des indices, envisagez des modèles plus complexes comme le carré. Nous pouvons représenter un carré comme un ensemble de deux triangles. Si (0,3,1) et (3,1,2) sont les deux triangles avec lesquels nous voulons dessiner un carré, alors les indices seront définis comme -
var indices = [0,3,1,3,1,2];
Note -
Pour dessiner des primitives, WebGL fournit les deux méthodes suivantes -
drawArrays() - En utilisant cette méthode, nous passons les sommets de la primitive à l'aide de tableaux JavaScript.
drawElements() - En utilisant cette méthode, nous transmettons à la fois les sommets et les indices de la primitive à l'aide d'un tableau JavaScript.
Objets tampon
Un objet tampon est un mécanisme fourni par WebGL qui indique une zone mémoire allouée dans le système. Dans ces objets tampons, vous pouvez stocker les données du modèle que vous souhaitez dessiner, correspondant aux sommets, aux indices, à la couleur, etc.
En utilisant ces objets tampons, vous pouvez transmettre plusieurs données au programme de shader (vertex shader) via l'une de ses variables d'attribut. Étant donné que ces objets tampons résident dans la mémoire du GPU, ils peuvent être rendus directement, ce qui améliore les performances.
Pour traiter la géométrie, il existe deux types d'objets tampons. Ils sont -
Vertex buffer object (VBO)- Il contient les données par sommet du modèle graphique qui va être rendu. Nous utilisons des objets tampon de sommet dans WebGL pour stocker et traiter les données concernant les sommets tels que les coordonnées de sommet, les normales, les couleurs et les coordonnées de texture.
Index buffer objects (IBO) - Il contient les indices (données d'index) du modèle graphique qui va être rendu.
Après avoir défini la géométrie requise et les avoir stockées dans des tableaux JavaScript, vous devez transmettre ces tableaux aux objets tampons, d'où les données seront transmises aux programmes de shader. Les étapes suivantes doivent être suivies pour stocker les données dans les tampons.
Créez un tampon vide.
Liez un objet tableau approprié au tampon vide.
Passez les données (sommets / indices) au tampon en utilisant l'un des typed arrays.
Dissociez le tampon (facultatif).
Créer un tampon
Pour créer un objet tampon vide, WebGL fournit une méthode appelée createBuffer(). Cette méthode renvoie un objet tampon nouvellement créé, si la création a réussi; sinon, il renvoie une valeur nulle en cas d'échec.
WebGL fonctionne comme une machine d'état. Une fois qu'un tampon est créé, toute opération ultérieure de tampon sera exécutée sur le tampon actuel jusqu'à ce que nous le déliions. Utilisez le code suivant pour créer un tampon -
var vertex_buffer = gl.createBuffer();
Note - gl est la variable de référence au contexte WebGL actuel.
Lier le tampon
Après avoir créé un objet tampon vide, vous devez lui lier un tampon de tableau approprié (cible). WebGL fournit une méthode appeléebindBuffer() dans ce but.
Syntaxe
La syntaxe de bindBuffer() la méthode est la suivante -
void bindBuffer (enum target, Object buffer)
Cette méthode accepte deux paramètres et ils sont décrits ci-dessous.
target- La première variable est une valeur d'énumération représentant le type de tampon que nous voulons lier au tampon vide. Vous avez deux valeurs d'énumération prédéfinies comme options pour ce paramètre. Ils sont -
ARRAY_BUFFER qui représente les données de sommet.
ELEMENT_ARRAY_BUFFER qui représente les données d'index.
Object buffer- La seconde est la variable de référence de l'objet tampon créé à l'étape précédente. La variable de référence peut être un objet tampon de sommet ou un objet tampon d'index.
Exemple
L'extrait de code suivant montre comment utiliser la méthode 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);
Passer des données dans le tampon
L'étape suivante consiste à transmettre les données (sommets / indices) au tampon. Jusqu'à présent, les données se présentent sous la forme d'un tableau et avant de les transmettre au tampon, nous devons les envelopper dans l'un des tableaux typés WebGL. WebGL fournit une méthode nomméebufferData() dans ce but.
Syntaxe
La syntaxe de la méthode bufferData () est la suivante -
void bufferData (enum target, Object data, enum usage)
Cette méthode accepte trois paramètres et ils sont discutés ci-dessous -
target - Le premier paramètre est une valeur d'énumération représentant le type de tampon de tableau que nous avons utilisé.Les options pour ce paramètre sont -
ARRAY_BUFFER qui représente vertex data.
ELEMENT_ARRAY_BUFFER qui représente index data.
Object data- Le deuxième paramètre est la valeur de l'objet qui contient les données à écrire dans l'objet tampon. Ici, nous devons transmettre les données en utilisanttyped arrays.
Usage- Le troisième paramètre de cette méthode est une variable enum qui spécifie comment utiliser les données de l'objet tampon (données stockées) pour dessiner des formes. Il existe trois options pour ce paramètre, comme indiqué ci-dessous.
gl.STATIC_DRAW - Les données seront spécifiées une fois et utilisées plusieurs fois.
gl.STREAM_DRAW - Les données seront spécifiées une fois et utilisées plusieurs fois.
gl.DYNAMIC_DRAW - Les données seront spécifiées à plusieurs reprises et utilisées plusieurs fois.
Exemple
L'extrait de code suivant montre comment utiliser le bufferData()méthode. Supposons que les sommets et les indices sont les tableaux contenant respectivement les données de sommets et d'index.
//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);
Tableaux typés
WebGL fournit un type spécial de tableau appelé typed arrayspour transférer les éléments de données tels que le sommet d'index et la texture. Ces tableaux typés stockent de grandes quantités de données et les traitent au format binaire natif, ce qui se traduit par de meilleures performances. Les tableaux typés utilisés par WebGL sont Int8Array, Uint8Array, Int16Array, Uint16Array, Int32Array, UInt32Array, Float32Array et Float64Array.
Note
Généralement, pour stocker les données de sommet, nous utilisons Float32Array; et pour stocker les données d'index, nous utilisonsUint16Array.
Vous pouvez créer des tableaux typés comme des tableaux JavaScript en utilisant new mot-clé.
Dissocier les tampons
Il est recommandé de dissocier les tampons après les avoir utilisés. Cela peut être fait en passant une valeur nulle à la place de l'objet tampon, comme indiqué ci-dessous.
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, null);
WebGL fournit les méthodes suivantes pour effectuer des opérations de tampon -
Sr.No. | Méthodes et description |
---|---|
1 | néant bindBuffer( cible enum , tampon d' objet ) cible - ARRAY_BUFFER, ELEMENT_ARRAY_BUFFER |
2 | néant bufferData( cible enum , taille longue , utilisation enum ) cible - ARRAY_BUFFER, ELEMENT_ARRAY_BUFFER utilisation - STATIC_DRAW, STREAM_DRAW, DYNAMIC_DRAW |
3 | néant bufferData( cible enum , données d' objet , utilisation enum ) cible et utilisation - Idem que pourbufferData au dessus de |
4 | néant bufferSubData( cible enum , décalage long , données d' objet ) cible - ARRAY_BUFFER, ELEMENT_ARRAY_BUFFER |
5 | Objet createBuffer() |
6 | néant deleteBuffer( Tampon d' objets ) |
sept | tout getBufferParameter(enum target , enum pname ) cible - ARRAY_BUFFER, ELEMENT_ ARRAY_BUFFER pname - BUFFER_SIZE, BUFFER_USAGE |
8 | booléen isBuffer( Tampon d' objets ) |
Les shaders sont les programmes qui s'exécutent sur GPU. Les shaders sont écrits en OpenGL ES Shader Language (connu sous le nom de ES SL). ES SL a ses propres variables, types de données, qualificatifs, entrées et sorties intégrées.
Types de données
Le tableau suivant répertorie les types de données de base fournis par OpenGL ES SL.
Sr.No. | Type et description |
---|---|
1 | void Représente une valeur vide. |
2 | bool Accepte vrai ou faux. |
3 | int Il s'agit d'un type de données entier signé. |
4 | float Il s'agit d'un type de données scalaire flottant. |
5 | vec2, vec3, vec4 vecteur à virgule flottante à n composants |
6 | bvec2, bvec3, bvec4 Vecteur booléen |
sept | ivec2, ivec3, ivec4 vecteur entier signé |
8 | mat2, mat3, mat4 Matrice de flotteurs 2x2, 3x3, 4x4 |
9 | sampler2D Accéder à une texture 2D |
dix | samplerCube Accéder à la texture mappée par cube |
Qualificatifs
Il existe trois principaux qualificatifs dans OpenGL ES SL -
Sr.No. | Qualificatif et description |
---|---|
1 | attribute Ce qualificatif agit comme un lien entre un shader de vertex et OpenGL ES pour les données par sommet. La valeur de cet attribut change à chaque exécution du vertex shader. |
2 | uniform Ce qualificatif relie les programmes de shader et l'application WebGL. Contrairement au qualificatif d'attribut, les valeurs des uniformes ne changent pas. Les uniformes sont en lecture seule; vous pouvez les utiliser avec n'importe quel type de données de base, pour déclarer une variable. Example - uniforme vec4 lightPosition; |
3 | varying Ce qualificatif forme un lien entre un vertex shader et un fragment shader pour les données interpolées. Il peut être utilisé avec les types de données suivants: float, vec2, vec3, vec4, mat2, mat3, mat4 ou arrays. Example - variant vec3 Ordinaire; |
Vertex Shader
Vertex shader est un code de programme, qui est appelé sur chaque sommet. Il transforme (déplace) la géométrie (ex: triangle) d'un endroit à un autre. Il gère les données de chaque sommet (données par sommet) telles que les coordonnées de sommet, les normales, les couleurs et les coordonnées de texture.
Dans le code ES GL du vertex shader, les programmeurs doivent définir des attributs pour gérer les données. Ces attributs pointent vers un objet Vertex Buffer écrit en JavaScript. Les tâches suivantes peuvent être effectuées à l'aide de vertex shaders avec transformation de vertex -
- Transformation de sommet
- Transformation et normalisation normales
- Génération de coordonnées de texture
- Transformation des coordonnées de texture
- Lighting
- Application du matériau de couleur
Variables prédéfinies
OpenGL ES SL fournit les variables prédéfinies suivantes pour le vertex shader -
Sr.No. | Variables et description |
---|---|
1 | highp vec4 gl_Position; Contient la position du sommet. |
2 | mediump float gl_PointSize; Contient la taille de point transformée. Les unités de cette variable sont les pixels. |
Exemple de code
Jetez un œil à l'exemple de code suivant d'un shader de vertex. Il traite les sommets d'un triangle.
attribute vec2 coordinates;
void main(void) {
gl_Position = vec4(coordinates, 0.0, 1.0);
};
Si vous observez attentivement le code ci-dessus, nous avons déclaré une variable d'attribut avec le nom coordinates. (Cette variable sera associée à l'objet Vertex Buffer en utilisant la méthodegetAttribLocation(). L'attributcoordinates est passé en paramètre à cette méthode avec l'objet programme shader.)
Dans la deuxième étape du programme de vertex shader donné, le gl_position la variable est définie.
gl_Position
gl_Position est la variable prédéfinie qui n'est disponible que dans le programme vertex shader. Il contient la position du sommet. Dans le code ci-dessus, lecoordinatesl'attribut est passé sous la forme d'un vecteur. Comme vertex shader est une opération par sommet, la valeur gl_position est calculée pour chaque sommet.
Plus tard, la valeur gl_position est utilisée par l'assemblage primitif, le découpage, le tri et d'autres opérations de fonctionnalité fixe qui opèrent sur les primitives une fois le traitement des sommets terminé.
Nous pouvons écrire des programmes de vertex shader pour toutes les opérations possibles de vertex shader, que nous discuterons individuellement dans ce tutoriel.
Fragment Shader
UNE mesh est formé par plusieurs triangles, et la surface de chaque triangle est connue sous le nom de fragment. Un shader de fragment est le code qui s'exécute sur chaque pixel de chaque fragment. Ceci est écrit pour calculer et remplir la couleur sur des pixels individuels. Les tâches suivantes peuvent être effectuées à l'aide des shaders de fragments -
- Opérations sur les valeurs interpolées
- Accès à la texture
- Application de texture
- Fog
- Somme des couleurs
Variables prédéfinies
OpenGL ES SL fournit les variables prédéfinies suivantes pour le shader de fragment -
Sr.No. | Variables et description |
---|---|
1 | mediump vec4 gl_FragCoord; Contient la position du fragment dans le tampon de trame. |
2 | bool gl_FrontFacing; Contient le fragment qui appartient à une primitive faisant face à l'avant. |
3 | mediump vec2 gl_PointCoord; Contient la position du fragment dans un point (pixellisation de points uniquement). |
4 | mediump vec4 gl_FragColor; Contient la valeur de couleur du fragment de sortie du shader |
5 | mediump vec4 gl_FragData[n] Contient la couleur du fragment pour l'attachement de couleur n. |
Exemple de code
L'exemple de code suivant d'un shader de fragment montre comment appliquer une couleur à chaque pixel d'un triangle.
void main(void) {
gl_FragColor = vec4(0, 0.8, 0, 1);
}
Dans le code ci-dessus, le colorLa valeur est stockée dans la variable gl.FragColor
. Le programme fragment shader transmet la sortie au pipeline en utilisant des variables de fonction fixes; FragColor est l'un d'entre eux. Cette variable contient la valeur de couleur des pixels du modèle.
Stockage et compilation des programmes Shader
Les shaders étant des programmes indépendants, nous pouvons les écrire sous forme de script séparé et les utiliser dans l'application. Ou, vous pouvez les stocker directement dansstring format, comme indiqué ci-dessous.
var vertCode =
'attribute vec2 coordinates;' +
'void main(void) {' +
' gl_Position = vec4(coordinates, 0.0, 1.0);' +
'}';
Compilation du shader
La compilation consiste à suivre trois étapes -
- Création de l'objet shader
- Attacher le code source à l'objet shader créé
- Compiler le programme
Création du Vertex Shader
Pour créer un shader vide, WebGL fournit une méthode appelée createShader(). Il crée et renvoie l'objet shader. Sa syntaxe est la suivante -
Object createShader (enum type)
Comme observé dans la syntaxe, cette méthode accepte une valeur d'énumération prédéfinie comme paramètre. Nous avons deux options pour cela -
gl.VERTEX_SHADER pour créer un shader de vertex
gl.FRAGMENT_SHADER pour créer un shader de fragment.
Attacher la source au shader
Vous pouvez attacher le code source à l'objet shader créé à l'aide de la méthode shaderSource(). Sa syntaxe est la suivante -
void shaderSource(Object shader, string source)
Cette méthode accepte deux paramètres -
shader - Vous devez passer l'objet shader créé comme un paramètre.
Source - Vous devez passer le code du programme shader au format chaîne.
Compilation du programme
Pour compiler le programme, vous devez utiliser la méthode compileShader(). Sa syntaxe est la suivante -
compileShader(Object shader)
Cette méthode accepte l'objet programme shader comme paramètre. Après avoir créé un objet programme shader, attachez-lui le code source et transmettez cet objet à cette méthode.
L'extrait de code suivant montre comment créer et compiler un vertex shader ainsi qu'un fragment shader pour créer un triangle.
// 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);
Programme combiné
Après avoir créé et compilé les deux programmes de shaders, vous devez créer un programme combiné contenant les deux shaders (vertex et fragment). Les étapes suivantes doivent être suivies -
- Créer un objet programme
- Attachez les deux shaders
- Lier les deux shaders
- Utilisez le programme
Créer un objet programme
Créer un objet programme à l'aide de la méthode createProgram(). Il renverra un objet programme vide. Voici sa syntaxe -
createProgram();
Attachez les shaders
Attachez les shaders à l'objet programme créé à l'aide de la méthode attachShader(). Sa syntaxe est la suivante -
attachShader(Object program, Object shader);
Cette méthode accepte deux paramètres -
Program - Passez l'objet programme vide créé en tant que paramètre.
Shader - Passez l'un des programmes de shaders compilés (vertex shader, fragment shader)
Note - Vous devez attacher les deux shaders en utilisant cette méthode.
Lier les shaders
Liez les shaders en utilisant la méthode linkProgram(), en passant l'objet programme auquel vous avez attaché les shaders. Sa syntaxe est la suivante -
linkProgram(shaderProgram);
Utilisez le programme
WebGL fournit une méthode appelée useProgram(). Vous devez lui transmettre le programme lié. Sa syntaxe est la suivante -
useProgram(shaderProgram);
L'extrait de code suivant montre comment créer, lier et utiliser un programme de shader combiné.
var shaderProgram = gl.createProgram();
gl.attachShader(shaderProgram, vertShader);
gl.attachShader(shaderProgram, fragShader);
gl.linkProgram(shaderProgram);
gl.useProgram(shaderProgram);
Chaque attribut du programme vertex shader pointe vers un objet tampon de sommet. Après avoir créé les objets de tampon de vertex, les programmeurs doivent les associer aux attributs du programme vertex shader. Chaque attribut pointe vers un seul objet tampon de sommet à partir duquel ils extraient les valeurs de données, puis ces attributs sont transmis au programme de shader.
Pour associer les objets Vertex Buffer aux attributs du programme vertex shader, vous devez suivre les étapes ci-dessous -
- Obtenez l'emplacement de l'attribut
- Pointez l'attribut vers un objet tampon de sommet
- Activer l'attribut
Obtenir l'emplacement de l'attribut
WebGL fournit une méthode appelée getAttribLocation()qui renvoie l'emplacement de l'attribut. Sa syntaxe est la suivante -
ulong getAttribLocation(Object program, string name)
Cette méthode accepte l'objet programme vertex shader et les valeurs d'attribut du programme vertex shader.
L'extrait de code suivant montre comment utiliser cette méthode.
var coordinatesVar = gl.getAttribLocation(shader_program, "coordinates");
Ici, shader_program est l'objet du programme shader et coordinates est l'attribut du programme vertex shader.
Pointez l'attribut vers un VBO
Pour affecter l'objet tampon à la variable d'attribut, WebGL fournit une méthode appelée vertexAttribPointer(). Voici la syntaxe de cette méthode -
void vertexAttribPointer(location, int size, enum type, bool normalized, long stride, long offset)
Cette méthode accepte six paramètres et ils sont décrits ci-dessous.
Location- Il spécifie l'emplacement de stockage d'une variable d'attribut. Sous cette option, vous devez transmettre la valeur renvoyée par legetAttribLocation() méthode.
Size - Il spécifie le nombre de composants par sommet dans l'objet tampon.
Type - Il spécifie le type de données.
Normalized- Il s'agit d'une valeur booléenne. Si vrai, les données non flottantes sont normalisées à [0, 1]; sinon, il est normalisé à [-1, 1].
Stride - Il spécifie le nombre d'octets entre les différents éléments de données de sommet, ou zéro pour la foulée par défaut.
Offset- Il spécifie le décalage (en octets) dans un objet tampon pour indiquer de quel octet les données de sommet sont stockées. Si les données sont stockées depuis le début, le décalage est 0.
L'extrait suivant montre comment utiliser vertexAttribPointer() dans un programme -
gl.vertexAttribPointer(coordinatesVar, 3, gl.FLOAT, false, 0, 0);
Activation de l'attribut
Activez l'attribut vertex shader pour accéder à l'objet tampon dans un vertex shader. Pour cette opération, WebGL fournitenableVertexAttribArray()méthode. Cette méthode accepte l'emplacement de l'attribut comme paramètre. Voici comment utiliser cette méthode dans un programme -
gl.enableVertexAttribArray(coordinatesVar);
Après avoir associé les tampons aux shaders, la dernière étape consiste à dessiner les primitives requises. WebGL propose deux méthodes à savoir,drawArrays() et drawElements() pour dessiner des modèles.
drawArrays ()
drawArrays()est la méthode utilisée pour dessiner des modèles à l'aide de sommets. Voici sa syntaxe -
void drawArrays(enum mode, int first, long count)
Cette méthode prend les trois paramètres suivants -
mode- Dans WebGL, les modèles sont dessinés à l'aide de types primitifs. En utilisant le mode, les programmeurs doivent choisir l'un des types primitifs fournis par WebGL. Les valeurs possibles pour cette option sont - gl.POINTS, gl.LINE_STRIP, gl.LINE_LOOP, gl.LINES, gl.TRIANGLE_STRIP, gl.TRIANGLE_FAN et gl.TRIANGLES.
first- Cette option spécifie l'élément de départ dans les tableaux activés. Cela ne peut pas être une valeur négative.
count - Cette option spécifie le nombre d'éléments à rendre.
Si vous dessinez un modèle en utilisant drawArrays() , puis WebGL, lors du rendu des formes, crée la géométrie dans l'ordre dans lequel les coordonnées des sommets sont définies.
Exemple
Si vous souhaitez dessiner un seul triangle en utilisant drawArray() méthode, alors vous devez passer trois sommets et appeler la drawArrays() méthode, comme indiqué ci-dessous.
var vertices = [-0.5,-0.5, -0.25,0.5, 0.0,-0.5,];
gl.drawArrays(gl.TRIANGLES, 0, 3);
Il produira un triangle comme indiqué ci-dessous.
Supposons que vous vouliez dessiner des triangles contigus, alors vous devez passer les trois sommets suivants dans l'ordre dans le tampon de sommets et mentionner le nombre d'éléments à rendre comme 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);
Il produira un triangle contigu comme indiqué ci-dessous.
drawElements ()
drawElements()est la méthode utilisée pour dessiner des modèles à l'aide de sommets et d'indices. Sa syntaxe est la suivante -
void drawElements(enum mode, long count, enum type, long offset)
Cette méthode prend les quatre paramètres suivants -
mode- Les modèles WebGL sont dessinés à l'aide de types primitifs. En utilisant le mode, les programmeurs doivent choisir l'un des types primitifs fournis par WebGL. La liste des valeurs possibles pour cette option est - gl.POINTS, gl.LINE_STRIP, gl.LINE_LOOP, gl.LINES, gl.TRIANGLE_STRIP, gl.TRIANGLE_FAN et gl.TRIANGLES.
count - Cette option spécifie le nombre d'éléments à rendre.
type - Cette option spécifie le type de données des index qui doivent être UNSIGNED_BYTE ou UNSIGNED_SHORT.
offset- Cette option spécifie le point de départ du rendu. C'est généralement le premier élément (0).
Si vous dessinez un modèle en utilisant drawElements(), alors l'objet tampon d'index doit également être créé avec l'objet tampon de sommet. Si vous utilisez cette méthode, les données de sommet seront traitées une fois et utilisées autant de fois que mentionné dans les indices.
Exemple
Si vous souhaitez dessiner un seul triangle à l'aide d'indices, vous devez passer les indices avec les sommets et appeler le drawElements() méthode comme indiqué ci-dessous.
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);
Il produira la sortie suivante -
Si vous souhaitez dessiner des triangles contagieux en utilisant drawElements() méthode, ajoutez simplement les autres sommets et mentionnez les indices des sommets restants.
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);
Il produira la sortie suivante -
Opérations requises
Avant de dessiner une primitive, vous devez effectuer quelques opérations, qui sont expliquées ci-dessous.
Effacer la toile
Tout d'abord, vous devez effacer le canevas en utilisant clearColor()méthode. Vous pouvez transmettre les valeurs RGBA d'une couleur souhaitée en tant que paramètre à cette méthode. Ensuite, WebGL efface le canevas et le remplit avec la couleur spécifiée. Par conséquent, vous pouvez utiliser cette méthode pour définir la couleur d'arrière-plan.
Jetez un œil à l'exemple suivant. Ici, nous transmettons la valeur RGBA de la couleur grise.
gl.clearColor(0.5, 0.5, .5, 1);
Activer le test de profondeur
Activez le test de profondeur à l'aide du enable() méthode, comme indiqué ci-dessous.
gl.enable(gl.DEPTH_TEST);
Effacer le bit de tampon de couleur
Effacez la couleur ainsi que le tampon de profondeur en utilisant le clear() méthode, comme indiqué ci-dessous.
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
Définir le port de vue
Le port de vue représente une zone visible rectangulaire qui contient les résultats de rendu du tampon de dessin. Vous pouvez définir les dimensions du port de vue en utilisantviewport()méthode. Dans le code suivant, les dimensions du port de vue sont définies sur les dimensions du canevas.
gl.viewport(0,0,canvas.width,canvas.height);
Nous avons discuté plus tôt (au chapitre 5) de la façon de suivre un processus étape par étape pour dessiner une primitive. Nous avons expliqué le processus en cinq étapes. Vous devez répéter ces étapes chaque fois que vous dessinez une nouvelle forme. Ce chapitre explique comment dessiner des points avec des coordonnées 3D dans WebGL. Avant d'aller plus loin, relookons les cinq étapes.
Étapes requises
Les étapes suivantes sont nécessaires pour créer une application WebGL pour dessiner des points.
Step 1 − Prepare the Canvas and Get the WebGL Rendering Context
Dans cette étape, nous obtenons l'objet de contexte de rendu WebGL à l'aide de la méthode getContext().
Step 2 − Define the Geometry and Store it in the Buffer Objects
Puisque nous dessinons trois points, nous définissons trois sommets avec des coordonnées 3D et les stockons dans des tampons.
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
Dans cette étape, vous devez écrire des programmes vertex shader et fragment shader, les compiler et créer un programme combiné en liant ces deux programmes.
Vertex Shader - Dans le vertex shader de l'exemple donné, nous définissons un attribut vectoriel pour stocker les coordonnées 3D, et l'affectons au gl_position variable.
gl_pointsizeest la variable utilisée pour attribuer une taille au point. Nous attribuons la taille de point à 10.
var vertCode = 'attribute vec3 coordinates;' +
'void main(void) {' +
' gl_Position = vec4(coordinates, 1.0);' +
'gl_PointSize = 10.0;'+
'}';
Fragment Shader - Dans le shader de fragment, nous attribuons simplement la couleur du fragment au gl_FragColor variable
var fragCode = 'void main(void) {' +' gl_FragColor = vec4(1, 0.5, 0.0, 1);' +'}';
Step 4 − Associate the Shader Programs to Buffer Objects
Dans cette étape, nous associons les objets tampons au programme shader.
Step 5 − Drawing the Required Object
Nous utilisons la méthode drawArrays()pour dessiner des points. Puisque le nombre de points que nous voulons dessiner est de trois, la valeur de comptage est de 3.
gl.drawArrays(gl.POINTS, 0, 3)
Exemple - Dessiner trois points à l'aide de WebGL
Voici le programme WebGL complet pour dessiner trois points -
<!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>
Cela produira le résultat suivant -
Dans le chapitre précédent (chapitre 11), nous avons expliqué comment dessiner trois points à l'aide de WebGL. Dans le chapitre 5, nous avons pris un exemple d'application pour montrer comment dessiner un triangle. Dans les deux exemples, nous avons dessiné les primitives en utilisant uniquement des sommets.
Pour dessiner des formes / maillages plus complexes, nous transmettons également les indices d'une géométrie, ainsi que les sommets, aux shaders. Dans ce chapitre, nous verrons comment dessiner un triangle à l'aide d'indices.
Étapes requises pour dessiner un triangle
Les étapes suivantes sont nécessaires pour créer une application WebGL pour dessiner un triangle.
Step 1 − Prepare the Canvas and Get WebGL Rendering Context
Dans cette étape, nous obtenons l'objet de contexte de rendu WebGL en utilisant getContext().
Step 2 − Define the Geometry and Store it in Buffer Objects
Puisque nous dessinons un triangle à l'aide d'indices, nous devons passer les trois sommets du triangle, y compris les indices, et les stocker dans les tampons.
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
Dans cette étape, vous devez écrire des programmes vertex shader et fragment shader, les compiler et créer un programme combiné en liant ces deux programmes.
Vertex Shader - Dans le vertex shader du programme, nous définissons l'attribut vectoriel pour stocker les coordonnées 3D et l'attribuons à gl_position.
var vertCode =
'attribute vec3 coordinates;' +
'void main(void) {' +
' gl_Position = vec4(coordinates, 1.0);' +
'}';
Fragment Shader - Dans le shader de fragment, nous attribuons simplement la couleur du fragment au gl_FragColor variable.
var fragCode = 'void main(void) {' +
' gl_FragColor = vec4(1, 0.5, 0.0, 1);' +
'}';
Step 4 − Associate the Shader Programs to the Buffer Objects
Dans cette étape, nous associons les objets tampons et le programme shader.
Step 5 − Drawing the Required Object
Puisque nous dessinons un triangle à l'aide d'indices, nous utiliserons drawElements()
. A cette méthode, il faut passer le nombre d'indices. La valeur duindices.length signifie le nombre d'indices.
gl.drawElements(gl.TRIANGLES, indices.length, gl.UNSIGNED_SHORT,0);
Exemple - Dessiner un triangle
Le code de programme suivant montre comment dessiner un triangle dans WebGL à l'aide d'indices -
<!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>
Si vous exécutez cet exemple, il produira la sortie suivante -
Dans le chapitre précédent (chapitre 12), nous avons expliqué comment dessiner un triangle à l'aide de WebGL. En plus des triangles, WebGL prend en charge divers autres modes de dessin. Ce chapitre explique les modes de dessin pris en charge par WebGL.
Le paramètre de mode
Jetons un œil à la syntaxe des méthodes - drawElements() et dessiner Arrays().
void drawElements(enum mode, long count, enum type, long offset);
void drawArrays(enum mode, int first, long count);
Si vous observez clairement, les deux méthodes acceptent un paramètre mode. En utilisant ce paramètre, les programmeurs peuvent sélectionner le mode de dessin dans WebGL.
Les modes de dessin fournis par WebGL sont répertoriés dans le tableau suivant.
Sr.No. | Mode et description |
---|---|
1 | gl.POINTS Pour dessiner une série de points. |
2 | gl.LINES Pour dessiner une série de segments de ligne non connectés (lignes individuelles). |
3 | gl.LINE_STRIP Pour dessiner une série de segments de ligne connectés. |
4 | gl.LINE_LOOP Pour dessiner une série de segments de ligne connectés. Il joint également les premier et dernier sommets pour former une boucle. |
5 | gl.TRIANGLES Pour dessiner une série de triangles séparés. |
6 | gl.TRIANGLE_STRIP Pour dessiner une série de triangles connectés en bande. |
sept | gl.TRIANGLE_FAN Pour dessiner une série de triangles connectés partageant le premier sommet en éventail. |
Exemple - Dessinez trois lignes parallèles
L'exemple suivant montre comment dessiner trois lignes parallèles à l'aide de 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>
Si vous exécutez cet exemple, il produira la sortie suivante -
Modes de dessin
Dans le programme ci-dessus, si vous remplacez le mode de drawArrays() avec l'un des modes de dessin suivants, il produira des sorties différentes à chaque fois.
Modes de dessin | Les sorties |
---|---|
LINE_STRIP |
|
LINE_LOOP |
|
TRIANGLE_STRIP |
|
TRIANGLE_FAN |
|
TRIANGLES |
|
Dans le chapitre précédent, nous avons abordé les différents modes de dessin fournis par WebGL. Nous pouvons également utiliser des indices pour dessiner des primitives en utilisant l'un de ces modes. Pour dessiner des modèles dans WebGL, nous devons choisir l'une de ces primitives et dessiner le maillage requis (c'est-à-dire un modèle formé à l'aide d'une ou plusieurs primitives).
Dans ce chapitre, nous prendrons un exemple pour montrer comment dessiner un quadrilatère en utilisant WebGL.
Étapes pour dessiner un quadrilatère
Les étapes suivantes sont nécessaires pour créer une application WebGL pour dessiner un quadrilatère.
Step 1 − Prepare the Canvas and Get the WebGL Rendering Context
Dans cette étape, nous obtenons l'objet de contexte de rendu WebGL en utilisant getContext().
Step 2 − Define the Geometry and Store it in the Buffer Objects
Un carré peut être dessiné à l'aide de deux triangles. Dans cet exemple, nous fournissons les sommets de deux triangles (avec un bord commun) et des indices.
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
Dans cette étape, vous devez écrire les programmes vertex shader et fragment shader, les compiler et créer un programme combiné en liant ces deux programmes.
Vertex Shader - Dans le vertex shader du programme, nous définissons l'attribut vectoriel pour stocker les coordonnées 3D et l'attribuons à gl_position.
var vertCode =
'attribute vec3 coordinates;' +
'void main(void) {' +
' gl_Position = vec4(coordinates, 1.0);' +
'}';
Fragment Shader - Dans le shader de fragment, nous attribuons simplement la couleur du fragment au gl_FragColor variable.
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
Dans cette étape, nous associons les objets tampons au programme shader.
Step 5 − Drawing the Required Object
Puisque nous dessinons deux triangles pour former un quad, en utilisant des indices, nous utiliserons la méthode drawElements(). A cette méthode, il faut passer le nombre d'indices. La valeur deindices.length donne le nombre d'indices.
gl.drawElements(gl.TRIANGLES, indices.length, gl.UNSIGNED_SHORT,0);
Exemple - Dessinez un quadrilatère
Le programme suivant montre comment créer une application WebGL pour dessiner un quadrilatère.
<!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>
Si vous exécutez cet exemple, il produira la sortie suivante -
Dans tous nos exemples précédents, nous avons appliqué une couleur à l'objet en attribuant une valeur de couleur souhaitée au gl_FragColorvariable. En plus de cela, nous pouvons définir des couleurs pour chaque sommet - tout comme les coordonnées et les indices de sommet. Ce chapitre prend un exemple pour montrer comment appliquer des couleurs à un quadrilatère à l'aide de WebGL.
Application de couleurs
Pour appliquer des couleurs, vous devez définir les couleurs de chaque sommet à l'aide des valeurs RVB, dans un tableau JavaScript. Vous pouvez attribuer les mêmes valeurs à tous les sommets pour avoir une couleur unique à l'objet. Après avoir défini les couleurs, vous devez créer un tampon de couleur et y stocker ces valeurs, puis l'associer aux attributs de vertex shader.
Dans le vertex shader, avec l'attribut de coordonnées (qui contient la position des sommets), nous définissons un attribute et un varying pour gérer les couleurs.
le color l'attribut contient la valeur de couleur par sommet, et varyingest la variable qui est transmise comme entrée au shader de fragment. Par conséquent, nous devons attribuer lecolor valeur à varying.
Dans le fragment shader, le varying qui contient la valeur de couleur est assignée à gl_FragColor, qui contient la couleur finale de l'objet.
Étapes pour appliquer les couleurs
Les étapes suivantes sont nécessaires pour créer une application WebGL pour dessiner un Quad et lui appliquer des couleurs.
Step 1 − Prepare the Canvas and Get the WebGL Rendering Context
Dans cette étape, nous obtenons l'objet de contexte de rendu WebGL en utilisant getContext().
Step 2 − Define the Geometry and Store it in the Buffer Objects
Un carré peut être dessiné à l'aide de deux triangles. Par conséquent, dans cet exemple, nous fournissons les sommets de deux triangles (avec une arête commune) et des indices. Puisque nous voulons lui appliquer des couleurs, une variable contenant les valeurs de couleur est également définie et les valeurs de couleur pour chacune (rouge, bleu, vert et rose) lui sont affectées.
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
Dans cette étape, vous devez écrire les programmes vertex shader et fragment shader, les compiler et créer un programme combiné en liant ces deux programmes.
Vertex Shader- Dans le vertex shader du programme, nous définissons des attributs vectoriels pour stocker les coordonnées 3D (position), et la couleur de chaque sommet. UNEvaringest déclarée pour transmettre les valeurs de couleur du vertex shader au fragment shader. Et enfin, la valeur stockée dans l'attribut de couleur est affectée àvarying.
var vertCode = 'attribute vec3 coordinates;'+
'attribute vec3 color;'+
'varying vec3 vColor;'+
'void main(void) {' +
' gl_Position = vec4(coordinates, 1.0);' +
'vColor = color;'+
'}';
Fragment Shader - Dans le fragment shader, nous attribuons le varying à la gl_FragColor variable.
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
Dans cette étape, nous associons les objets tampons et le programme shader.
Step 5 − Drawing the Required Object
Puisque nous dessinons deux triangles qui formeront un quad, à l'aide d'indices, nous utiliserons la méthode drawElements(). A cette méthode, il faut passer le nombre d'indices. La valeur deindices.length indique le nombre d'indices.
gl.drawElements(gl.TRIANGLES, indices.length, gl.UNSIGNED_SHORT,0);
Exemple - Application de la couleur
Le programme suivant montre comment dessiner un quad à l'aide de l'application WebGL et lui appliquer des couleurs.
<!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>
Si vous exécutez cet exemple, il produira la sortie suivante -
Jusqu'à présent, nous avons expliqué comment dessiner différentes formes et leur appliquer des couleurs à l'aide de WebGL. Ici, dans ce chapitre, nous allons prendre un exemple pour montrer comment traduire un triangle.
Traduction
La traduction est l'une des affine transformationsfourni par WebGL. En utilisant la translation, nous pouvons déplacer un triangle (n'importe quel objet) sur le plan xyz. Supposons que nous ayons un triangle [a, b, c] et que nous voulions déplacer le triangle vers une position qui est de 5 unités vers l'axe X positif et de 3 unités vers l'axe Y positif. Alors les nouveaux sommets seraient [a + 5, b + 3, c + 0]. Cela signifie que pour traduire le triangle, nous devons ajouter les distances de translation, disons, tx, ty, tz à chaque sommet.
Puisqu'il s'agit d'un per-vertex operation, nous pouvons le transporter dans le programme vertex shader.
Dans le vertex shader, avec l'attribut, coordinates(qui détiennent les positions des sommets), nous définissons une variable uniforme qui contient les distances de translation (x, y, z). Plus tard, nous ajoutons cette variable uniforme à la variable de coordonnées et affectons le résultat à lagl_Position variable.
Note - Puisque le vertex shader sera exécuté sur chaque sommet, tous les sommets du triangle seront traduits.
Étapes pour traduire un triangle
Les étapes suivantes sont nécessaires pour créer une application WebGL afin de dessiner un triangle, puis de le traduire vers une nouvelle position.
Step 1 − Prepare the Canvas and Get the WebGL Rendering Context
Dans cette étape, nous obtenons l'objet de contexte de rendu WebGL en utilisant getContext().
Step 2 − Define the Geometry and Store it in the Buffer Objects
Puisque nous dessinons un triangle, nous devons passer trois sommets du triangle et les stocker dans des tampons.
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
Dans cette étape, vous devez écrire les programmes vertex shader et fragment shader, les compiler et créer un programme combiné en liant ces deux programmes.
Vertex Shader- Dans le vertex shader du programme, nous définissons un attribut vectoriel pour stocker les coordonnées 3D. Parallèlement, nous définissons une variable uniforme pour stocker les distances de translation, et enfin, nous ajoutons ces deux valeurs et les affectons àgl_position qui contient la position finale des sommets.
var vertCode =
'attribute vec4 coordinates;' +
'uniform vec4 translation;'+
'void main(void) {' +
' gl_Position = coordinates + translation;' +
'}';
Fragment Shader - Dans le shader de fragment, nous attribuons simplement la couleur du fragment à la variable 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
Dans cette étape, nous associons les objets tampons au programme shader.
Step 5 − Drawing the Required Object
Puisque nous dessinons le triangle à l'aide d'indices, nous utiliserons la méthode drawArrays(). A cette méthode, il faut passer le nombre de sommets / éléments à considérer. Puisque nous dessinons un triangle, nous passerons 3 comme paramètre.
gl.drawArrays(gl.TRIANGLES, 0, 3);
Exemple - Traduire un triangle
L'exemple suivant montre comment traduire un triangle sur le plan 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>
Si vous exécutez cet exemple, il produira la sortie suivante -
Dans ce chapitre, nous prendrons un exemple pour montrer comment modifier l'échelle d'un triangle à l'aide de WebGL.
Mise à l'échelle
La mise à l'échelle n'est rien d'autre que l'augmentation ou la diminution de la taille d'un objet. Par exemple, si un triangle a des sommets de la taille [a, b, c], alors le triangle avec les sommets [2a, 2b, 2c] sera le double de sa taille. Par conséquent, pour mettre à l'échelle un triangle, vous devez multiplier chaque sommet avec le facteur de mise à l'échelle. Vous pouvez également mettre à l'échelle un sommet particulier.
Pour mettre à l'échelle un triangle, dans le vertex shader du programme, nous créons une matrice uniforme et multiplions les valeurs de coordonnées avec cette matrice. Plus tard, nous passons une matrice diagonale 4 × 4 ayant les facteurs d'échelle des coordonnées x, y, z dans les positions diagonales (dernière position diagonale 1).
Étapes requises
Les étapes suivantes sont nécessaires pour créer une application WebGL pour mettre à l'échelle un triangle.
Step 1 − Prepare the Canvas and Get the WebGL Rendering Context
Dans cette étape, nous obtenons l'objet de contexte de rendu WebGL en utilisant getContext().
Step 2 − Define the Geometry and Store it in the Buffer Objects
Puisque nous dessinons un triangle, nous devons passer trois sommets du triangle et les stocker dans des tampons.
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
Dans cette étape, vous devez écrire les programmes vertex shader et fragment shader, les compiler et créer un programme combiné en liant ces deux programmes.
Vertex Shader- Dans le vertex shader du programme, nous définissons un attribut vectoriel pour stocker les coordonnées 3D. Parallèlement, nous définissons une matrice uniforme pour stocker les facteurs de mise à l'échelle, et enfin, nous multiplions ces deux valeurs et l'attribuons àgl_position qui contient la position finale des sommets.
var vertCode =
'attribute vec4 coordinates;' +
'uniform mat4 u_xformMatrix;' +
'void main(void) {' +
' gl_Position = u_xformMatrix * coordinates;' +
'}';
Fragment Shader - Dans le shader de fragment, nous attribuons simplement la couleur du fragment au gl_FragColor variable.
var fragCode = 'void main(void) {' +' gl_FragColor = vec4(1, 0.5, 0.0, 1);' +'}';
Step 4 − Associate the Shader Programs with the Buffer Objects
Dans cette étape, nous associons les objets tampons au programme shader.
Step 5 − Drawing the Required Object
Puisque nous dessinons le triangle à l'aide d'indices, nous utilisons le drawArrays()méthode. A cette méthode, il faut passer le nombre de sommets / éléments à considérer. Puisque nous dessinons un triangle, nous passerons 3 comme paramètre.
gl.drawArrays(gl.TRIANGLES, 0, 3);
Exemple - Mettre à l'échelle un triangle
L'exemple suivant montre comment mettre à l'échelle un triangle -
<!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>
Si vous exécutez cet exemple, il produira la sortie suivante -
Dans ce chapitre, nous prendrons un exemple pour montrer comment faire pivoter un triangle à l'aide de WebGL.
Exemple - Faire pivoter un triangle
Le programme suivant montre comment faire pivoter un triangle à l'aide de 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>
Si vous exécutez cet exemple, il produira la sortie suivante -
Dans ce chapitre, nous prendrons un exemple pour montrer comment dessiner un cube 3D rotatif à l'aide de WebGL.
Exemple - Dessiner un cube 3D rotatif
Le programme suivant montre comment dessiner un cube 3D rotatif -
<!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>
Si vous exécutez cet exemple, il produira la sortie suivante -
Dans ce chapitre, nous prendrons un exemple pour montrer comment dessiner un cube 3D qui peut être tourné à l'aide des commandes de la souris.
Exemple - Dessiner un cube interactif
Le programme suivant montre comment faire pivoter un cube à l'aide des commandes de la souris -
<!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>
Si vous exécutez cet exemple, il produira la sortie suivante -