Hi everyone, I’m Fly brother, it’s been a long time since I wrote an article with my heart, but I still need to remember my original intention and strive to help you get started with WebGL. Then, I will also study deeply myself, and I don’t want to be an API caller of Three. js. What can you learn from this article, or look it up later when you check it out

  1. What exactly is a buffer in Webgl?
  2. Why is there such a thing as buffer?
  3. How to use buffer in WebGL?

Math??

“I’m not good at math, I can’t learn it well.” Don’t panic, can not think more, don’t be a giant of speech, action.

Mathematics is poor

This time or hand in hand to explain the simple concept clearly, unfamiliar students can review this article first.

This article: A few simple examples to get you started with WebGL

What is a buffer

Buffer, what is this thing, or why there is such a thing for WebGL. Let’s start with the official definition:

The WebGLBuffer interface is part of the WebGL API and represents an opaque buffer object that stores data such as vertices or shaders.

The official explanation, as a white person, what, are you giving me a hard time??

Embarrass me, Fat tiger

The first sentence is a nonsense, part of the WebGL API, which I know 🐴 wow, let’s focus on this sentence, is an opaque buffer object,

What is a buffer object

Webgl provides a convenient mechanism for passing data from multiple vertices to shaders at once, called buffer objects. A buffer object is an area of memory in a WebGL system that can be filled with a large amount of vertex data at once, and then stored there for use by vertex shaders.

It’s a very convenient mechanism. Why do I say that? I’m just going to draw three dots here, and I’m going to write pseudo-code, okay

Useless buffer

I want to draw 3 points in WebGL. It’s easy, no fancy stuff, just 3 simple points:

// Clear the color buffer gl.clear(gl.color_buffer_bit); const len = g_poiont.length; for(var i = 0; i<len; I ++){// loop to add point // pass point position to variable a_position gl.vertexatTriB3f (a_position,g_poiont[I].x, g_Poiont [I].y,0.0); // draw gl.drawArrays(gl.POINTS,0,1); }Copy the code

So here I’m going to make a very simple illustration of this code

  1. Clear color buffer
  2. Then loop through the arraylist
  3. The position is passed to the vertex shader, which then goes to draw the vertex

If you can’t understand it, it doesn’t matter. I will explain it step by step in the later WebGL series. The focus of this article is still on the understanding of buffer.

The gl.drawArrays API is very important to understand, so I suggest you think about it.

This is a powerful API for drawing all kinds of graphs. Let’s take a look at the following diagram:

The API show figure

  1. The first parameter is actually the way webGL draws dots, lines, triangles…. This is the way we’re drawing points
  2. The second argument is the vertex from which to draw the argument
  3. Third parameter: how many vertices are required for the current drawing

Because we’re in a loop, so every time we loop, we draw one vertex. So the vertex shader runs once while the program is running, because we’re only drawing one point, right? Looks pretty good, makes sense.

Take a look at the picture below:

image-20220115141239602

The image above is Duo Lai Dream’s 3D grid model, which has A lot of vertices. Do we have to do A loop to draw vertices one at A time, so gpu rendering is faster? Certainly not. It can pass data for multiple vertices to the shader at once

We use the buffer method to draw three more vertices:

Use buffer

Let’s take a look at the pseudocode:

// Set the vertex position initVertexBuffers(gl); Gl. drawArrays(gl.POINTS,0,3); // draw three POINTS gl.drawArrays(gl.POINTS,0,3);Copy the code
  1. The first function uses buffer and does data binding
  2. We then tell WebGL that we are currently drawing three vertices and that the data is already bound in the buffer

In this way, we can easily handle all kinds of complex models, which is really cool. We can process many vertices at one time, giving full play to the ability of GPU parallel rendering.

I drew a comparison diagram of the process for you to understand

A buffer object is used

Vertex shaders that do not use buffer objects may execute multiple times depending on the number of vertices

No vertex shader object is used

Good to the following a problem in the end how to use the buffer ????

How to use buffers

That’s what the initVertexBuffers function did above

  1. Step 1: Create the buffer object (gl.createBuffer())
  2. Step 2: Bind the buffer object (gl.bindBuffer())
  3. Step 3: Write data to the buffer object (gl.bufferData())
  4. Step 4: Assign the buffer object to an attribute variable (gl.vertexattribPointer ())
  5. Step 5: open the attribute variables (gl. EnableVertexAttribArray ())

Follow my steps step by step:

Creating a buffer object

The code is simple:

const buffer = gl.createBuffer()
Copy the code

But what does he actually post, as shown here:

show

In fact, in memory will be allocated a buffer object, there is actually a corresponding deletion buffer object

const buffer =  gl.createBuffer()
gl.deleteBuffer(buffer)
Copy the code

Bind buffer object

Gl.array_buffer and gl.element_array_buffer are the same as gl.element_array_buffer. When will it be used

Because buffer types are variable, you must manually bind them to represent the current buffer

Let me introduce the differences between the two buffers:

  1. Gl.array_buffer: A Buffer that contains vertex attributes, such as vertex coordinates, texture coordinate data, or vertex color data.

  2. Gl.element_array_buffer: Buffer used for element indexes.

  3. When using WebGL 2 Context

    , the following values can be used:

    • gl.COPY_READ_BUFFER: Copies from one Buffer object to another.
    • gl.COPY_WRITE_BUFFER: Copies from one Buffer object to another.
    • gl.TRANSFORM_FEEDBACK_BUFFER: Buffer for transform feedback operations.
    • gl.UNIFORM_BUFFER: Buffer used to store unified blocks.
    • gl.PIXEL_PACK_BUFFER: Buffer for pixel transfer operations.
    • gl.PIXEL_UNPACK_BUFFER: Buffer for pixel transfer operations.

It doesn’t matter if you don’t understand this, but you should know that buffers have many types, and since we are vertices, we must bind to the first type

The code is as follows:

const canvas = document.getElementById('canvas');
const gl = canvas.getContext('webgl');
const buffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
Copy the code

And then look at the picture below,

Bind buffer object

Notice the small arrows, which are the process of binding buffers

Write data to buffer object

At this point we are all ready to do the pre-work, so how to write data into it, before that I will briefly talk about a data type – type array

Type array:

A JavaScript typed array is an array-like object that provides a mechanism for accessing raw binary data. As you probably already know, Array stores objects that can grow and decrease dynamically, and can store any JavaScript value. The JavaScript engine does some internal optimization so that operations on arrays can be done quickly. However, as Web applications become more powerful, especially with new additions such as audio and video editing, accessing WebSockets raw data, and so on, it becomes clear that sometimes it would be helpful to use JavaScript code to quickly and easily manipulate raw binary data through typed arrays.

However, don’t confuse typed arrays with normal arrays, because a call to array.isarray () on a typed Array returns false. In addition, not all methods available for normal arrays are supported by typed arrays (such as push and POP).

To optimize performance, WebGL needs to process a large number of the same types of data simultaneously, such as vertex coordinates and vertex colors. The browser knows the type of the array in advance, which makes it more efficient and gives it a strongly typed feel.

Type array

So the code looks like this:

// Const vertices = new Float32Array([0.0,0.5,-0.5,-0.5, -0.5,-0.5, -0.5]); Const vertexBuffer = gl.createBuffer(); if(! VertexBuffer){console.log(" failed to create buffer object "); return -1; } // Bind the buffer object to the target gl.bindBuffer(gl.array_buffer,vertexBuffer); / / to write data in the buffer object gl bufferData (gl. ARRAY_BUFFER, are drawn, gl. STATIC_DRAW);Copy the code

The last step is our binding data, let’s read the API to bind the second parameter data to the first parameter buffer object, what does the third parameter represent? , means that data is written to a buffer object once, but drawn many times

As shown in figure:

Write data

Distribution of variables

Now that the data is also written to the buffer, it’s time to allocate variables. There’s really only two steps here

  1. The first step is actually to find the position of the property from the shader
  2. The buffer object is then assigned to this variable

Let’s look at the code first:

Const a_Position = gl.getattribLocation (gl.program, "a_Position"); If (a_Position < 0){console.log(" can't get variable location "); return; } / / the buffer objects assigned to gl a_Position variables. VertexAttribPointer (a_Position, 2, gl. FLOAT, false, 0, 0).Copy the code

The first half of this is actually going to be a little bit of pre-knowledge, which WE’ll talk about later in this article, is basically creating the WebGL program, and then initializing the shader program, and inside the vertex shader which is essentially a string, it’s going to have a_Position, I then use gl.getattribLocation to find the location of the variable.

The second part of the statement is: assign the buffer object to this variable. Let’s look at the API gl.vertexattribPointer

  1. The first parameter specifies the index of the vertex property to be modified, which is found in the vertex shader above
  2. The representation of the second argument specifies the number of components of each vertex attribute, which must be 1,2,3, or 4. Why is that? Because the default vertex coordinates are (x,y,z,w) and if you choose 1 then the program will fill in the rest of the parameters for you. 2. Set 3 to 0. 4 to 1. Because we’re dealing with two dimensional coordinates, we’re only using x and y coordinates so it’s two
  3. The third one represents the data type, which in our case is floating point
  4. The fourth is normalization, which means that non-floating-point data is normalized to the range [0,1] or [-1,1]
  5. The fifth represents the number of bytes between adjacent vertices
  6. The last one tells us where in the buffer we started storing this vertex index, and our buffer object is all vertex data, so this is 0

For detailed documentation, go to MDN. Six parameters to one parameter, so learning WebGL is really challenging, but again, people find it difficult, you learn your market value. Still a word!!

rod

Look at the pictures

The scene at this time

The activation

Some people look at the above picture and say, the data has been written, and the variable has been allocated, why is there a broken line in the middle?? Webgl is a real dog, and it’s really complicated, so I just want to draw three dots and take several steps. So I have to say that the framework design of Three. js is awesome, but in order to learn, I still need to learn the principle, so that you can easily handle three.js

Let’s see how it activates one line of code, okay

/ / link a_Position variables and gl buffer object assigned to it. The enableVertexAttribArray (a_Position);Copy the code

This is a simple line of code that opens a variable and establishes a link between the buffer object and the attribute

Take a look at the pictures:

link

conclusion

This is the first article of Webgl series, which mainly explains buffer from the three aspects of what, how and why. This year’s articles are presented to everyone in a series mode. If you don’t want to miss my first release, please set the official number as the star symbol, so that you can see it at the first time. Finally, I summarize the knowledge points with words

  1. Step 1: Create the buffer object (gl.createBuffer())
  2. Step 2: Bind the buffer object (gl.bindBuffer())
  3. Step 3: Write data to the buffer object (gl.bufferData())
  4. Step 4: Assign the buffer object to an attribute variable (gl.vertexattribPointer ())
  5. Step 5: open the attribute variables (gl. EnableVertexAttribArray ())

Finally, let’s take another picture to deepen the students’ memory. The serial numbers are all well marked.

The serial number figure

Finally click “like” and “Watch”, let more see, also welcome to add my wechat and COMMUNICATE with me, watch fly brother funny ratio every day!! We’ll see you next time 👋🏻