[WebGL Primer] 14, drawing polygons

Source: Internet
Author: User

Note: The article is translated from http://wgld.org/, the original author Sambonja 広 (doxas), the article if there is my additional instructions, I will add [Lufy:], in addition, The WEBGL research is not deep enough, some professional words, if the translation is wrong, you are welcome to correct.



This is the running result of this demo.

Drawing Process

It's time to draw a polygon, the HTML, vertex shader, and fragment shader introduced in the previous article (11, shader compilation and connection), this time looking at JavaScript from the beginning to the final processing.
If the contents of the first two articles are fully understood, this should not be difficult. There may be places that are not easy to understand, don't worry.
First, I post all the code and then I'm going to explain it slowly.

>script.js all the Code

onload = function () {//Canvas object gets var c = document.getElementById (' canvas ');    C.width = 300;    C.height = 300; WebGL context gets var gl = c.getcontext (' WebGL ') | |        C.getcontext (' Experimental-webgl ');        Sets the color of the canvas initialization gl.clearcolor (0.0, 0.0, 0.0, 1.0);        Sets the depth gl.cleardepth (1.0) when the canvas is initialized; The initialization of the canvas gl.clear (GL. Color_buffer_bit | Gl.        Depth_buffer_bit);    Generation of vertex shader and fragment shader var v_shader = Create_shader (' vs ');        var f_shader = Create_shader (' FS ');        Program object generation and connection var PRG = Create_program (V_shader, F_shader);        Attributelocation gain var attlocation = gl.getattriblocation (PRG, ' position ');        The number of elements in the attribute (this time only uses XYZ, so it is 3) var attstride = 3;        Model (vertex) data var vertex_position = [0.0, 1.0, 0.0, 1.0, 0.0, 0.0,-1.0, 0.0, 0.0];        Generate VBO var Vbo = Create_vbo (vertex_position); Bind Vbo Gl.bindbuffer (GL.        Array_buffer, VBO); Set the attribute property to have validity GL.Enablevertexattribarray (attlocation); Add attribute Properties Gl.vertexattribpointer (attlocation, Attstride, GL.        FLOAT, False, 0, 0);        Generate var m = new Mativ () using minmatrix.js to the related processing//Mativ object of the matrix;    Generation and initialization of various matrices var Mmatrix = m.identity (M.create ());    var Vmatrix = m.identity (M.create ());    var PMatrix = m.identity (M.create ());        var Mvpmatrix = m.identity (M.create ());        View transformation coordinate matrix M.lookat ([0.0, 1.0, 3.0], [0, 0, 0], [0, 1, 0], Vmatrix);        Projective coordinate transformation matrix m.perspective (C.width/c.height, 0.1, PMatrix);    Each matrix is formed to obtain the final coordinate transformation matrix m.multiply (PMatrix, Vmatrix, Mvpmatrix);        M.multiply (Mvpmatrix, Mmatrix, Mvpmatrix);        Uniformlocation gain var unilocation = gl.getuniformlocation (PRG, ' Mvpmatrix ');        The Coordinate transformation matrix GL.UNIFORMMATRIX4FV (Unilocation, False, Mvpmatrix) is passed into the uniformlocation; Draw Model Gl.drawarrays (GL.        Triangles, 0, 3);        Context refresh Gl.flush (); Generate Shader function Create_shader (ID) {//ToSave the shader variable var shader;        Gets the specified script tag from HTML based on id var scriptelement = document.getElementById (ID);        If the specified script tag does not exist, returns if (!scriptelement) {return;}            Case ' X-shader/x-vertex ' when judging the type attribute of the script tag switch (scriptelement.type) {//vertex shader): Shader = Gl.createshader (gl.            Vertex_shader);                    Break Fragment shader when case ' x-shader/x-fragment ': shader = Gl.createshader (gl.            Fragment_shader);        Break    Default:return;        }//Assign the code in the tag to the generated shader Gl.shadersource (shader, Scriptelement.text);        Compiler shader Gl.compileshader (shader); Determine if the shader compiles successfully if (Gl.getshaderparameter (shader, GL.    Compile_status)) {//compile successfully, return the shader return shader;    }else{//compilation failed, pop-up error message alert (Gl.getshaderinfolog (shader));   }}///program object generation and shader connection functions function Create_program (VS, FS) {//Program object generation var programs = Gl.createprogram ();     Assigns shader Gl.attachshader (program, VS) to the Application object;        Gl.attachshader (program, FS);        Connect the shader to the Gl.linkprogram (program); Determines if the connection to the shader is successful if (Gl.getprogramparameter (program, GL).                Link_status)) {//successfully set the program object to a valid Gl.useprogram (Programs);    Returns the program object return to Programs;    }else{//If failed, pop-up error message alert (Gl.getprograminfolog (program));        }}//Generate VBO function Create_vbo (data) {//Generate cache object var Vbo = Gl.createbuffer (); Bind Cache Gl.bindbuffer (GL.        Array_buffer, VBO); Writes data to the cache Gl.bufferdata (GL. Array_buffer, new Float32array (data), GL.        Static_draw); Set the bound cache to an invalid Gl.bindbuffer (GL.        Array_buffer, NULL); Returns the generated VBO return VBO;};

Initialization Processing

So, from top to bottom, take a look at it in order.
First, if all the code in Script.js is executed while the page is loaded, the code is all written into the onload function. After that, get the canvas object to begin processing.

>canvas is obtained and initialized as follows

    The canvas object gets    var c = document.getElementById (' canvas ');    C.width = +;    C.height = +;    WebGL context gets    var gl = c.getcontext (' WebGL ') | | | c.getcontext (' EXPERIMENTAL-WEBGL ');        Sets the color of the canvas initialization    gl.clearcolor (0.0, 0.0, 0.0, 1.0);        Sets the depth    gl.cleardepth (1.0) when the canvas is initialized;        The initialization of the canvas    gl.clear (GL. Color_buffer_bit | Gl. Depth_buffer_bit);
The first thing to do is get the canvas object and set the canvas size to 300px wide and 300px high. Then get the context of the WEBGL and set the color used to clear the screen.
The depth of the purge is then set. Using the Cleardepth function can be set to clear the depth of the screen, the previous example is only the color initialization, so only use the Clearcolor function, in fact, when dealing with three-dimensional space, the depth of the relevant information needs to be cleared, so the use of the Cleardepth function.
Similarly, the parameters in the clear function are changed accordingly, not only the color, but also the depth, so the GL is added. The Depth_buffer_bit constant.


generation of shaders and program objects

Generates a vertex shader and fragment shader, and connects using program objects. In the previous article (Shader compilation and connection) in the detailed description, you can refer to.

> Shader and Program Object-related processing

    Generation of vertex shader and fragment shader    var v_shader = create_shader (' vs ');    var f_shader = Create_shader (' fs ');        Program object generation and connection    var PRG = Create_program (V_shader, f_shader);        Attributelocation gain    var attlocation = gl.getattriblocation (PRG, ' position ');        The number of elements in the attribute (this time only uses XYZ, so it is 3)    var attstride = 3;
Note that the functions that appear here are not functions built into WebGL, but are written by ourselves. The specific point is that Create_shader and Create_program are all functions written by themselves.
The arguments to the Create_shader function are the ID strings in the HTML, get the shader code from the script tag, generate the shader object, and return. In the example above, the vertex shader and fragment shader are generated based on the contents of these two script tags, which are vs and FS.
After the shader is generated, it is passed as a parameter to the Create_program function, and the return value is the program object, which is then saved with a variable. In the Create_program function, the program object is generated and the shader is connected.
Next, you define two variables, attlocation and attstride, that are used to hold the necessary content when the data is passed back to the vertex shader.
Again, take a look at how the generated shader is used in the code in the previous article, and then understand why you define the two variables.

> code that uses vertex shaders

Attribute vec3 position;uniform   mat4 mvpmatrix;void Main (void) {    gl_position = Mvpmatrix * VEC4 (position, 1.0);}
This time using the shader, only a attribute variable is used, of course, is position, the position variable is defined as VEC3, indicating that it has 3 elements of the vector.
The point here is [using a attribute variable called position] and [this variable is VEC3 type] This two-point content. In fact, when using the attribute variable to pass data to the shader, the necessary two intelligence is that the data is the first attribute variable, and the variable is made up of several elements.
That is, the variable attlocation is to save this data is the first few, variable attstride is to save this data is composed of several elements.
The two parameters of the Getattriblocation function in the context of WebGL, the first parameter is the program object, and the second parameter is the variable name of the attribute variable you want to get. The return value is numeric, which is the ordinal of the data being passed to the vertex shader. is to tell us the number of variables. This value will be used later.
The variable attstride represents the attribute variable in the vertex shader position is a variable of type VEC3 with three elements. It's going to be used later.


generation and notification of vertex caches

Go ahead, define the model data, generate the VBO, and then bind and pass in the data in order to pass the VBO to the vertex shader.

Related processing of >VBO generation

    Model (vertex) data    var vertex_position = [         0.0, 1.0, 0.0,         1.0, 0.0, 0.0,        -1.0, 0.0, 0.0    ];        Generate Vbo    var vbo = Create_vbo (vertex_position);        Bind Vbo    gl.bindbuffer (GL. Array_buffer, VBO);        Set attribute attribute has validity    Gl.enablevertexattribarray (attlocation);        Add attribute Properties    gl.vertexattribpointer (Attlocation, Attstride, GL. FLOAT, False, 0, 0);
The previous article (12, model data and vertex attributes) has been described in detail, defining the vertex data as a simple array, and then using the Custom function Create_vbo to generate the vertex cache (VBO) based on the array data.
In order to associate the vertex cache with the attribute variable in the vertex shader, you first bind the VBO to WebGL. Then use the ordinal of the attribute attribute you just acquired to set the attribute property to valid. Using WebGL's function Enablevertexattribarray allows the specified property to become valid.
Next, use the WebGL function Vertexattribpointer to write data to the shader. The two variables attlocation and attstride that you just defined are also used here. The first parameter of the Vertexattribpointer function is the ordinal of the attribute variable, the second argument is the number of elements, and the third parameter is a built-in constant specifying the data type. Gl. Float is a constant that represents a floating-point type. The sixth parameter is basically not how to change, according to memory sometimes will pass other content.
It is important to note that when executing Vertexattribpointer, the Vbo object must be bound first, which VBO and the attribute attribute associated with it, so do not forget to bind Vbo with WebGL first.


generation and notification of coordinate transformation matrices

Next, a coordinate transformation matrix is prepared for rendering. Here, the basic usage of the library minmatrix.js,minmatrix.js for matrix calculations made by this site has been introduced in the previous article (minmatrix.js and coordinate transformation matrices).
Generation of > Coordinate transformation matrices and related processing

        Generate    var m = new Mativ () using minmatrix.js to the related processing//Mativ object of the matrix;        Generation and initialization of various matrices    var Mmatrix = m.identity (M.create ());    var Vmatrix = m.identity (M.create ());    var PMatrix = m.identity (M.create ());    var Mvpmatrix = m.identity (M.create ());        View transformation Coordinate matrix    m.lookat ([0.0, 1.0, 3.0], [0, 0, 0], [0, 1, 0], Vmatrix);        Projective coordinate transformation matrix    m.perspective (C.width/c.height, 0.1, PMatrix);        Each matrix is formed to obtain the final coordinate transformation matrix    m.multiply (PMatrix, Vmatrix, Mvpmatrix);    M.multiply (Mvpmatrix, Mmatrix, Mvpmatrix);        Uniformlocation gain    var unilocation = gl.getuniformlocation (PRG, ' Mvpmatrix ');        The coordinate transformation matrix    GL.UNIFORMMATRIX4FV (Unilocation, False, Mvpmatrix) is passed into the uniformlocation;
This time, the model transformation matrix has not done any processing after initialization of the direct use, of course, not to say that the model transformation matrix can not be manipulated, it is used first.
The view transformation matrix can be generated using the Mativ.lookat function defined in minmatrix.js, so that the lens in the three-dimensional space is placed at the beginning of the original point moving up 1.0, moving backwards 3.0, the origin is the reference point, the direction of the lens pointing to the y-axis direction.
The projection transformation matrix is generated using mativ.perspective, with a viewing angle of 90 degrees, a ratio of the screen to the size of the canvas, and then specifying the near and far sections respectively.
Then the model, the view, the projection of each transformation matrix is multiplied to obtain the final coordinate transformation matrix Mvpmatrix, and then notify the WEBGL can be.
When you pass in the uniform variable to WebGL, like the attribute variable, you get the ordinal of the variable first, using the WebGL getuniformlocation function, passing in the name of the program object and the variable, you can get the sequence number of the uniform variable.
After getting the ordinal, passing the data to the vertex shader, this time using WebGL's UNIFORMMATRIX4FV function, the first parameter is the ordinal of the uniform variable, the second parameter is whether the matrix is transpose (true, sometimes the program crashes), The third parameter is the actual coordinate transformation matrix.

>>uniform Series Function Correlation
The appearance of the UNIFORMMATRIX4FV is just a uniform series function, uniform series functions are many kinds, mainly divided into the following categories.


Uniform series
The Uniform series has Uniform1 ~ uniform4, which are used when passing one to four elements into a vertex shader. Depending on the type of data passed to the vertex shader is an integer or floating-point type, the number is followed by a lowercase letter such as I (int) or F (float). For example, when the data passed to the shader is floating-point data with two elements, use uniform2f.
Example: gl.uniform2f (Uniformlocation, date1, data2);


Uniform V Series
This series, basically and the above uniform series is not much different, the incoming data is used when the array. As with the uniform series, there are 1 to 4, and the data type is also added after I or F.
Example: Gl.uniform3iv (Uniformlocation, Array);


Uniformmatrix Series
Look at the name should know, this series is used in the matrix. Of course, the matrix cannot appear 1, so only 2 ~ 4. Moreover, the matrix basically only uses the floating-point decimal, therefore, the data type also does not exist I, the data is to use the array as the premise, so there is no difference after the addition of V.
Example: GL.UNIFORMMATRIX4FV (Uniformlocation, False, Matrix);


drawing of the model and refresh of the context

Shader, vertex data, coordinate transformation matrix, and so on, all kinds of preparation work is finished, and finally it is time to write a drawing command.

> Drawing Commands and refreshes

Draw Model Gl.drawarrays (GL. Triangles, 0, 3);//Context Refresh Gl.flush ();
The Drawarrays function of WebGL is executed, and the model is drawn to the cache, which is said to be [cached] because the polygon is not drawn to the screen when the Drawarrays function is executed.
To draw the model onto the screen, you must perform the WEBGL flush function so that the results can be reflected on the screen.

The Drawarrays function that appears here, the first parameter is a constant that specifies how to draw with vertices, the second parameter is used from the first vertex, and the third parameter is to draw several vertices.

This time, the use of GL. Traiangles, so the vertices are treated as pure triangular polygons, drawn with three vertices .


Summary

This article is a bit too long, posted a bit more code, maybe someone will take a surprise.

In fact, this time the code is just a simple triangle. Just like this, but write so long code, so just say 3D development is more difficult.

However, personally, even so, compared to DirectX, it is quite simple and concise.

In the development environment alone, there is no need for a special development environment, and WEBGL is a breeze. Understand the content of this, just a little slowly adjust, you can achieve a lot of results. After this content, all is based on this content, so must have a good understanding.

At the end of this article, the link to the demo is given, if the browser supports it, it is more intuitive to see the demo directly.


So, next time you want to color the polygon, please look forward to it.

Rendering the Triangle Demo

http://wgld.org/s/sample_002/


reprint Please specify: transfer from Lufy_legend's blog Http://blog.csdn.net/lufy_legend

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.