WebGL vertex Shader (1)Copy the code

Over the next few sessions, we’ll familiarize ourselves with the various uses of Vertex Shader through several examples.

  1. We’re going to draw our graph with 1,000 points.
  2. Our code template looks like this:
<! doctype html> <html> <head> <style> canvas { border: 1px solid #000000; </style> </head> <body> <input ID ="slider" type="range" min="0" Max ="100" value="50" step="1" οnchange=" sliderFunc ()" /> <canvas id="point" style="width:300px; height:300px"> </canvas> <script id="vertex_shader" type="myshader"> // Vertex Shader precision mediump int; precision mediump float; uniform float u_x_offset; attribute vec2 a_PointVertex; Void main() {gl_Position = vec4(a_PointVertex, 0.0, 1.0); Y = sin(gl_position. x * 3.14); If (fract(gl_position. x * 100.0) < 0.5) {gl_position. y = gl_position. x; } gl_Position.x = gl_Position.x + u_x_offset; Gl_PointSize = 3.0; } </script> <script id="fragment_shader" type="myshader"> // Fragment shader precision mediump int; precision mediump float; Void main() {gl_FragColor = vec4(0.0, 0.0, 0.0, 1.0); } </script> <script type="text/javascript"> var pointCanvas = document.getElementById('point'); Var gl = pointCanvas. GetContext ('webgl', {preserveDrawingBuffer: true}); Var pointCount = 0; var pointData = []; for (var idx = -500; idx <= 500; idx++) { pointCount++; pointData.push(idx / 500); pointData.push(0); } // var pointArray = new Float32Array(pointData); var buffer_id; buffer_id = gl.createBuffer(); gl.bindBuffer(gl.ARRAY_BUFFER, buffer_id); gl.bufferData(gl.ARRAY_BUFFER, pointArray, gl.STATIC_DRAW); // var vertex_shader_code = document.getElementById('vertex_shader').textContent; console.log(vertex_shader_code); var vertex_shader = gl.createShader(gl.VERTEX_SHADER); gl.shaderSource(vertex_shader, vertex_shader_code); gl.compileShader(vertex_shader); // var fragment_shader_code = document.getElementById('fragment_shader').textContent; var fragment_shader = gl.createShader(gl.FRAGMENT_SHADER); gl.shaderSource(fragment_shader, fragment_shader_code); gl.compileShader(fragment_shader); // var program = gl.createProgram(); gl.attachShader(program, vertex_shader); gl.attachShader(program, fragment_shader); gl.linkProgram(program); gl.useProgram(program); // var a_PointVertex = gl.getAttribLocation(program, 'a_PointVertex'); gl.vertexAttribPointer(a_PointVertex, 2, gl.FLOAT, false, 0, 0); gl.enableVertexAttribArray(a_PointVertex); // // gl.drawArrays(gl.POINTS, 0, pointCount); </script> <script> var u_x_offset_loc = gl.getUniformLocation(program, "u_x_offset"); var sliderDom = document.getElementById("slider"); function sliderfunc() { console.log("___________________", u_x_offset_loc, typeof sliderDom.value, sliderDom.value); gl.uniform1f(u_x_offset_loc, parseFloat(sliderDom.value) / 100); gl.clearColor(0, 0, 0, 0); gl.clear(gl.COLOR_BUFFER_BIT); gl.drawArrays(gl.POINTS, 0, pointCount); } sliderDom.addEventListener("change", sliderfunc); </script> </script> </body> </html>Copy the code
  1. Our focus is on this part of the above code, i.evertex shaderParts:
<script id="vertex_shader" type="myshader"> // Vertex Shader precision mediump int; precision mediump float; attribute vec2 a_PointVertex; Void main() {gl_Position = vec4(a_PointVertex, 0.0, 1.0); Gl_PointSize = 3.0; } </script>Copy the code
The first example: drawing the sine of a sin
  • We have 1,000 data points, and the abscissa of these points goes from negative 1 to 1
  • The y-coordinate is 0

So if I go inside, it’s a horizontal line in the middle of the screen and we open it up in a browser, and it does:



According to the sine function:

y = sin (x)

We changed our Vertex shader as follows:

<script id="vertex_shader" type="myshader"> // Vertex Shader precision mediump int; precision mediump float; attribute vec2 a_PointVertex; Void main() {gl_Position = vec4(a_PointVertex, 0.0, 1.0); gl_Position.y = sin(gl_Position.x); Gl_PointSize = 3.0; } </script>Copy the code

Refresh the page, and the result is as follows:

And the reason why we find that the figure above is not perfect, because it doesn’t show the whole sine over a period is because we have x in the range of minus one minus one, that’s not enough for one period and one period would be between minus PI and plus PI. Let’s change the code like this:

<script id="vertex_shader" type="myshader"> // Vertex Shader precision mediump int; precision mediump float; attribute vec2 a_PointVertex; Void main() {gl_Position = vec4(a_PointVertex, 0.0, 1.0); Y = sin(gl_position. x * 3.14); Gl_PointSize = 3.0; } </script>Copy the code

Refresh the page and the result looks much better:



Great, we can use itwebglTo draw the graph of the function, how fun ~

I’m going to draw the sine graph for two periods:

<script id="vertex_shader" type="myshader"> // Vertex Shader precision mediump int; precision mediump float; attribute vec2 a_PointVertex; Void main() {gl_Position = vec4(a_PointVertex, 0.0, 1.0); Y = sin(gl_position. x * 3.14 * 2.0); Gl_PointSize = 3.0; } </script>Copy the code

Yes, we did:

Next, let’s do something weird. For example, how can our code be changed to draw the following diagram:

We find that on the left half of the graph, it looks like the graph has been compressed half way to the center. Clues:

  1. The left half of the picture 🙁x<0)
  2. Compress by half 🙁Y = y * 0.5)

We will change the above clues into the corresponding code as follows:

<script id="vertex_shader" type="myshader"> // Vertex Shader precision mediump int; precision mediump float; attribute vec2 a_PointVertex; Void main() {gl_Position = vec4(a_PointVertex, 0.0, 1.0); Y = sin(gl_position. x * 3.14 * 2.0); If (gl_position. x < 0.0) {gl_position. y = gl_position. y * 0.5; } gl_PointSize = 3.0; } </script>Copy the code

It’s still two cycles, but it says in the code, if x is less than 0, y is halved, so it’s easy to understand!

Second example: Draw simultaneouslyA straight linesinimage

It looks like this:



A reader’s mind is thinking, simple:

I drew it outside twice, just to usegl.drawArrays, draw the image twice, prepare two in advancevertex shader.

It turns out: Ok, you can do that, and I’m not going to say anything against it, but I’m going to add one restriction,

  1. There must be only one Vertex Shader,

  2. Gl. drawArrays are only allowed once.

  3. And do not change the outside generated data code, we can only change vertex shader code!!

Idea: we have 1000 points, let’s cross draw the above two graphics!! So, for example, if I draw the sine graph with odd indices, if I draw the line with even indices.

The question is, can we get the subscript in the Vertex Shader ????? Obviously not. We can only work on the x itself. Let’s list the leftmost x’s: -1.000, -0.998, -0.996, -0.994, -0.992, -0.990… We multiply all of the top numbers by 100 to get the following numbers: -100.0, -99.8, -99.6, -99.4, -99.2, -99 we keep the decimals and get rid of the integers: 0, 0.8, 0.6, 0.4, 0.2, 0 We find that, in addition to 0, two less than 0.5, two more than 0.5 so we cross this, the code is as follows:

<script id="vertex_shader" type="myshader"> // Vertex Shader precision mediump int; precision mediump float; attribute vec2 a_PointVertex; Void main() {gl_Position = vec4(a_PointVertex, 0.0, 1.0); Y = sin(gl_position. x * 3.14); If (fract(gl_position. x * 100.0) < 0.5) {gl_position. y = gl_position. x; } gl_PointSize = 3.0; } </script>Copy the code

Refresh the page, the image is out!! Success!!!!!




At the end of the text, questions are answeredCopy the code
Small guagua said: the day is hot, the melon is really delicious, but the graphics are really good-looking……