The webGL API addresses are as follows:

www.khronos.org/registry/we… www.khronos.org/registry/we…

Shader language in a web page in several ways

1. Write the shader language in a separate file, such as vtrtex.bns. Get text content by getting files.

There is no official extension in the shader language specification. OpenGL can’t handle loading shaders from files; You just pass the shader code as a string, so there is no specific file format. However, Khronos’ reference GLSL compiler/validator GLSLANG uses the following extension to determine the type of shader this file is used for: Tesc – Mosaic control shader. Tese – Mosaic evaluation shader. Geom – geometry shader. Frag – fragment shader

2. Write the shader language as a string and assign it to the js variable.

// Vertex shader program
var VSHADER_SOURCE = 
  'void main() {\n' +
  'gl_Position = vec4(0.0, 0.0, 0.0, 1.0); \n' + // Set the vertex coordinates of the point
  'gl_PointSize = 10.0; \n' +                    // Set the point size
  '}\n';
Copy the code

3. Insert HTML through the script tag, and then get the text inside the tag by id.

<script id="shader-vs" type="x-shader/x-vertex">
    attribute vec3 v3Position;  // Vertex coordinates
    attribute vec3 av3Color;    // Vertex color attribute
    varying vec3 vv3Color;      // The vertex shader and fragment shader communicate with each other. Note that the vertex and fragment shader define variables with the same name
    void main(void){
	 vv3Color = av3Color;
	 gl_Position = vec4(v3Position, 1.0);
    }
</script>
Copy the code

The general flow of a WebGL application

We say it takes three steps to put an elephant in a fridge, so writing a WebGL application should only take three steps:

  • 1. Put the data into the buffer
  • 2. Pass the buffer data to the shader
  • 3. Shaders feed data to the GPU.

Here is a rough flow chart of a WebGL application:

demo1

<! DOCTYPE html><html>
	<head>
		<meta charset="utf-8">
		<title></title>
		<script>
			var webgl = null;
			function Init(){
				var canvas = document.getElementById('myCanvas');
				webgl = canvas.getContext("webgl");// Similar to create draw engine or initialization
				// Set the render area of WebGL (viewarea)
				webgl.viewport(0.0,canvas.clientWidth,canvas.clientHeight) 
				The // method is used to set the color value when the color buffer is cleared
				webgl.clearColor(0.0.0.0.0.0.1.0);
				The // method uses default values to clear the buffer
				// gl.color_buffer_bit // color buffer
				// gl.depth_buffer_bit // depth buffer
				// gl.stencil_buffer_bit // template buffer
				webgl.clear(webgl.COLOR_BUFFER_BIT);
				// It must be emphasized
				// 1. GlClearColor is Set and does not Clear anything! Don't confuse ~
				// 2. GlClearColor specifies the color to use when flushing the color buffer.
				// So, to complete a refresh process, use glClearColor(COLOR) in conjunction with glClear(GL_COLOR_BUFFER_BIT). GlClearColor (0.0, 0.0, 1.0, 1.0); / / blue
				// glClear(GL_COLOR_BUFFER_BIT);
				// The purpose of clearing the color buffer is to prevent the color information in the buffer from affecting the drawing. When the drawing area is the entire window, as is usually seen, the clear value of the color buffer is the background color of the window. Therefore, these two clear instructions are not necessary: for static images only need to be set once, for example, the background color is not required/the background color is white.
				// glClear is more efficient and less effort than manually painting a background canvas, so this method is usually used.
			}
			
			// Frame buffer (more than one) two-dimensional image color buffer, depth buffer, template buffer
		</script>
	</head>
	<body onload='Init()'>
		<canvas id="myCanvas" style="border:1px solid red;" width="600" height="450"></canvas>
	</body>
</html>
Copy the code

demo2

WebGL is designed to interact directly with the graphics card, first by compiling the shader code:

function initShaders(webgl, vertexShaderId, framentShaderId, bindVariableData) {
	/ / generated shaderobject
	var vertexShaderObject = webgl.createShader(webgl.VERTEX_SHADER);
	var fragmentShaderObject = webgl.createShader(webgl.FRAGMENT_SHADER);
	/ / compile a shader
	compileShader(webgl, shaderSourceFromScript(vertexShaderId), shaderSourceFromScript(framentShaderId), vertexShaderObject, fragmentShaderObject);
	/ / links shader
	// Create a program object
	programObject = webgl.createProgram();
	// Associate the shader variable to an attribute index. This operation must be performed before linking
	if(! bindVariableDatainstanceof Array) {
		alert("Incorrect input parameter");
		return;
	}
	for(var i = 0; i < bindVariableData.length; i++) {
		// Bind the generic vertex index to the property variable
		webgl.bindAttribLocation(programObject, bindVariableData[i][0], bindVariableData[i][1]);
	}
	programObject = linkShader(webgl, programObject, vertexShaderObject, fragmentShaderObject);
	return programObject;
}

/ / compile a shader
ShaderVectexCode shaderFramentCode GLSL string
function compileShader(webgl, shaderVectexCode, shaderFramentCode, vertexShaderObj, fragmentShaderObj) {
	// Load the shader code into the Shader Object
	webgl.shaderSource(vertexShaderObj, shaderVectexCode);
	webgl.shaderSource(fragmentShaderObj, shaderFramentCode);
	// Compile the shader code
	webgl.compileShader(vertexShaderObj);
	webgl.compileShader(fragmentShaderObj);
	// Check whether the compilation is successful
	if(! webgl.getShaderParameter(vertexShaderObj, webgl.COMPILE_STATUS)) { alert("error:vertexShaderObject");
		return;
	}
	if(! webgl.getShaderParameter(fragmentShaderObj, webgl.COMPILE_STATUS)) { alert("error:framentShaderObject");
		return; }}Copy the code

Compile two pieces of code, which act as library files, into binary code that can be executed on the video card, and then create a program, which acts as an exe, that links the two shader codes. Then perform the link operation to form a program that can be executed on the graphics card. Association via programObject handle.

Handle is a term often used in C++ programming. It is not a specific, fixed data type or entity, but represents a broad concept in programming. A handle generally refers to a method of obtaining another object — a generalized pointer, which may take the form of an integer, an object, or just a real pointer, and its purpose is to establish a unique connection to the object being accessed.

To run a program, input and output are vec3 v3Position and VEC3 vv3Color in the GLSL Vertex shader code

webgl.bindAttribLocation(programObject,v3PositionIndex,"v3Position")
Copy the code

Bind v3PositionIndex to v3Position, which is the input

Now it’s time to upload the vertex data to the video card. Create a buffer on the video card to store the data, declare the buffer storage type, and then pass the ArrayData data to the buffer.

triangleBuffer = webgl.createBuffer();// Create a buffer on the graphics card
webgl.bindBuffer(webgl.ARRAY_BUFFER,triangleBuffer);// declare that the storage type of the cache is ARRAY_BUFFER
webgl.bufferData(webgl.ARRAY_BUFFER,new Float32Array(ArrayData),webgl.STATIC_DRAW);// Assign a value to the cache
Copy the code

The next step is to run the above application on the graphics card, using a buffer (bufferData()), enabling v3PositionIndex, telling the graphics card application how to use the data in the graphics card buffer (vertexAttribPointer ()), and then drawing.

webgl.bindBuffer(webgl.ARRAY_BUFFER, triangleBuffer);
webgl.enableVertexAttribArray(v3PositionIndex);
webgl.vertexAttribPointer(v3PositionIndex, 3, webgl.FLOAT, false.0.0);
webgl.bindBuffer(webgl.ARRAY_BUFFER, triangleColorBuffer);
webgl.enableVertexAttribArray(v3ColorIndex);
webgl.vertexAttribPointer(v3ColorIndex, 3, webgl.FLOAT, false.0.0);
// Draw data
webgl.drawArrays(webgl.TRIANGLES, 0.3);
Copy the code

The complete code

<html>
	<head>
		<! Use GLSL ES language, write vertex shader and slice shader, and the corresponding shader program. 3. Prepare the vertex data of the image you want to draw. 4. Match the variables in the shader to the buffer containing the vertex data. 5.
		<script id="shader-vs" type="x-shader/x-vertex">
			attribute vec3 v3Position;  // Vertex coordinates
			attribute vec3 av3Color;    // Vertex color attribute
			varying vec3 vv3Color;      // The vertex shader and fragment shader communicate with each other. Note that the vertex and fragment shader define variables with the same name
			void main(void){
				vv3Color = av3Color;
				gl_Position = vec4(v3Position, 1.0);
			}
                </script>

		<script id="shader-fs" type="x-shader/x-fragment">
			#ifdef GL_FRAGMENT_PRECISION_HIGH
			precision highp float;
			#else
			precision mediump float;
                        #endif
                        varying vec3 vv3Color;
			void main(void){
				 gl_FragColor = vec4(vv3Color, 1.0);
			}
                </script>

		<script>
			
			var webgl = null;
			var vertexShaderObject = null;
			var fragmentShaderObject = null;
			var programObject = null;
			var triangleBuffer = null;
			var triangleColorBuffer = null;
			
			var v3PositionIndex = 0;
			var v3ColorIndex = 1;
			var r = 1.0;
			var g = 1.0;
			var b = 1.0;
			var isDesc = false;
			
			
			// Initialize the code
			function init() {
				// Initialize the WebGL render area
				webgl = initCanvas("webglCanvas");
				// Initialize the shader program
				var bind1 = [v3PositionIndex, "v3Position"];
				var bind2 = [v3ColorIndex, "av3Color"];  / / av3Color variable names
				var bindData = new Array(a); bindData.push(bind1); bindData.push(bind2);// Initializes the Shader program and returns the linked program object
				var programObject = initShaders(webgl, "shader-vs"."shader-fs", bindData);
				
				// Add the defined WebGLProgram object to the current render state.
				webgl.useProgram(programObject);    
				/ / discoloration
				window.setInterval("changeColor()".10);
				// Initialize vertex data
				triangleBuffer = initVextexData(webgl);
			}
			// Initializes the Shader program and returns the linked program object
			function initShaders(webgl, vertexShaderId, framentShaderId, bindVariableData) {
				/ / generated shaderobject
				var vertexShaderObject = webgl.createShader(webgl.VERTEX_SHADER);
				var fragmentShaderObject = webgl.createShader(webgl.FRAGMENT_SHADER);
				/ / compile a shader
				compileShader(webgl, shaderSourceFromScript(vertexShaderId), shaderSourceFromScript(framentShaderId),vertexShaderObject, fragmentShaderObject);
			
				/ / links shader
				// Create a program object
				programObject = webgl.createProgram();
				// Associate the shader variable to an attribute index. This operation must be performed before linking
				if(! bindVariableDatainstanceof Array) {
					alert("Incorrect input parameter");
					return;
				}
				for (var i = 0; i < bindVariableData.length; i++) {
					// Bind the generic vertex index to the property variable
					//console.log(programObject, bindVariableData[i][0], bindVariableData[i][1])
					webgl.bindAttribLocation(programObject, bindVariableData[i][0], bindVariableData[i][1]);
				}
				programObject = linkShader(webgl, programObject, vertexShaderObject, fragmentShaderObject);
				return programObject;
			}
			
			/ / compile a shader
			ShaderVectexCode shaderFramentCode GLSL string
			function compileShader(webgl, shaderVectexCode, shaderFramentCode, vertexShaderObj, fragmentShaderObj) {
				// Load the shader code into the Shader Object
				webgl.shaderSource(vertexShaderObj, shaderVectexCode);
				webgl.shaderSource(fragmentShaderObj, shaderFramentCode);
				// Compile the shader code
				webgl.compileShader(vertexShaderObj);
				webgl.compileShader(fragmentShaderObj);
				// Check whether the compilation is successful
				if(! webgl.getShaderParameter(vertexShaderObj, webgl.COMPILE_STATUS)) { alert("error:vertexShaderObject");
					return;
				}
				if(! webgl.getShaderParameter(fragmentShaderObj, webgl.COMPILE_STATUS)) { alert("error:framentShaderObject");
					return; }}// Vertex data
			function initVextexData(webgl) {
				// Vertex coordinates
				var jsArrayData = [
					0.0.1.0.0.0,
					-1.0.0.0, -1.0.1.0.0.0.0.0
				]
				// Create a buffer that webGL can access
				var triangleBuffer = webgl.createBuffer();
				/ / binding buffer
				webgl.bindBuffer(webgl.ARRAY_BUFFER, triangleBuffer);
				// Copy the js data to buffer
				webgl.bufferData(webgl.ARRAY_BUFFER, new Float32Array(jsArrayData), webgl.STATIC_DRAW);
				// Color data
				var jsArrayColor = [
					1.0.0.0.0.0./ / on the vertex
					0.0.1.0.0.0./ / left vertex
					0.0.0.0.1.0 / / right vertex
				];
				// Create a color buffer and copy the color data into the color buffer
				triangleColorBuffer = webgl.createBuffer();
				webgl.bindBuffer(webgl.ARRAY_BUFFER, triangleColorBuffer);
				webgl.bufferData(webgl.ARRAY_BUFFER, new Float32Array(jsArrayColor), webgl.STATIC_DRAW);
				return triangleBuffer;
			}
			// Render the scene
			function renderScene() {
				// Start drawing
				// Clear the screen
				webgl.clearColor(0.0.0.0.0.0.1.0);
				webgl.clear(webgl.COLOR_BUFFER_BIT);
				// WebGL can have N vertex arrays, we need to tell WebGL which one we use,
				
				// Use a buffer
				// Bind an array of vertex data
				webgl.bindBuffer(webgl.ARRAY_BUFFER, triangleBuffer);
				
				// To illustrate how enableVertexArray() activates vertex properties and transfers vertex data to shader.
				// Start data on an associative index // Open a generic vertex property array at the specified index in the property array list
				webgl.enableVertexAttribArray(v3PositionIndex);
				// Specify the data element on the associated index or the correct information variable interval for the element data
				webgl.vertexAttribPointer(v3PositionIndex, 3, webgl.FLOAT, false.0.0);

				// Bind the color buffer
				webgl.bindBuffer(webgl.ARRAY_BUFFER, triangleColorBuffer);
				webgl.enableVertexAttribArray(v3ColorIndex);
				webgl.vertexAttribPointer(v3ColorIndex, 3, webgl.FLOAT, false.0.0);
				
		
				//https://blog.csdn.net/ithanmang/article/details/89520623
				// Draw data
				webgl.drawArrays(webgl.TRIANGLES, 0.3);
			}

	
			// Change the RGB value continuously to achieve color changing animation
			function changeColor() {  / / isDesc false by default
				if (isDesc && r <= 0.1){
					isDesc = false;
				}
				if(! isDesc && r >=1.0){
					isDesc = true;
				}
				!isDesc ? r += 0.01 : r -= 0.01; ! isDesc ? g +=0.01 : g -= 0.01; ! isDesc ? b +=0.01 : b -= 0.01;
				var jsArrayColor = [// Data -- graphics card
					r, 0.0.0.0./ / on the vertex
					0.0, g, 0.0./ / left vertex
					0.0.0.0, b / / right vertex
				];
				// Memory graphics card
				triangleColorBuffer = webgl.createBuffer();  // A WebGLBuffer object used to store vertex data or coloring data
				webgl.bindBuffer(webgl.ARRAY_BUFFER, triangleColorBuffer);// Bind the given WebGLBuffer to the target store's type, the vertex type
				// assign //webgl.STATIC_DRAW
				webgl.bufferData(webgl.ARRAY_BUFFER, new Float32Array(jsArrayColor), webgl.STATIC_DRAW);
				renderScene();
			}

			// Initialize canvas
			function initCanvas(canvasId) {
				// Get the drawing context
				var myCanvasObject = document.getElementById(canvasId);
				var context = null;
				try {
					context = myCanvasObject.getContext("experimental-webgl");
					// Set the viewport
					context.viewport(0.0, myCanvasObject.width, myCanvasObject.height);
				} catch (ex) {
					alert(ex.toString());
				}
				if(! context) { alert("Holy crap, your browser doesn't support WebGL, switch to another browser.");
					return null;
				}
				return context;
			}
			// Parse the Shader code
			function shaderSourceFromScript(scriptID) {
				var shaderScript = document.getElementById(scriptID);
				if (shaderScript == null) return "";
				var sourceCode = "";
				var child = shaderScript.firstChild;
				while (child) {
					if (child.nodeType == child.TEXT_NODE) sourceCode += child.textContent;
					child = child.nextSibling;
				}
				return sourceCode;
			}

			// Link the Shader program
			function linkShader(webgl, programObj, vertexShaderObj, fragmentShaderObj) {
				// A program object can and must have one vertex shader and one fragment shader
				webgl.attachShader(programObj, vertexShaderObj);
				webgl.attachShader(programObj, fragmentShaderObj);
				// Associate the shader variable with an attribute index
				// webgl.bindAttribLocation(programObj, v3PositionIndex, "v3Position");
				webgl.linkProgram(programObj);
				// Check whether the link is successful
				if(! webgl.getProgramParameter(programObj, webgl.LINK_STATUS)) { alert("error:ProgramObject");
					return;
				}
				return programObj;
			}
			
		</script>
	</head>


	<body onload="init()">
		<canvas id="webglCanvas" style="border:1px solid red" width="600" height="600"></canvas>
	</body>
</html>

Copy the code