WebGL JavaScript

Drawing a Linear Spline Interpolation

This JavaScript program demonstrates how to draw a linear spline interpolation in WebGL.

LinearSplineInterpolation.html

<!DOCTYPE html>
<html>
  <head>
    <title>XoaX.net's WebGL</title>
    <script  id="idVertexShader" type="c">
      attribute vec2 av2Vertex;

      void main() {
        gl_Position = vec4(av2Vertex, 0.0, 1.0);
      }
    </script>
    <script  id="idFragmantShader" type="c">
      precision mediump float;

      // This will paint the portion of the grid line color over the previous color and return it
      vec4 DrawGraphLines(vec4 v4InitColor, float fCoord, float fPixelSize, float fGridSpace) {
      	vec4 v4GraphLineColor = vec4(0.85, 0.85, 0.85, 1.0);
      	// Find the closest line - constant time
      	float fSpaceMultiple = fCoord/fGridSpace;
      	float fNearest = floor(fSpaceMultiple+.5);
      	if (fNearest != 0.0) {
      		float fDistToLine = abs(fSpaceMultiple - fNearest);
      		if (fDistToLine < fPixelSize) {
      			float fFill = fDistToLine/fPixelSize;
      			return (1.0 - fFill)*v4GraphLineColor + fFill*v4InitColor;
        	}
        }
      	return v4InitColor;
      }
      
      vec4 DrawAxis(vec4 v4InitColor, float fCoord, float fPixelSize) {
      	vec4 v4AxisColor = vec4(0.5, 0.5, 0.5, 1.0);
      	float fDistToAxis = abs(fCoord);
      	if (fDistToAxis < fPixelSize) {
      		float fFill = fDistToAxis/fPixelSize;
      		return (1.0 - fFill)*v4AxisColor + fFill*v4InitColor;
        }
        return v4InitColor;
      }

      vec4 DrawLinearInterpolationGraph(vec4 v4InitColor, float fCoordX, float fCoordY, float fPixelHeight) {
      	vec4 v4GraphColor = vec4(1.0, 0.0, 0.0, 1.0);
      	float faPts[17];
      	faPts[0] = .3;
      	faPts[1] = .5;
      	faPts[2] = .2;
      	faPts[3] = .1;
      	faPts[4] = -.5;
      	faPts[5] = -.7;
      	faPts[6] = -1.0;
      	faPts[7] = -.9;
      	faPts[8] = -.5;
      	faPts[9] = -.3;
      	faPts[10] = .4;
      	faPts[11] = -.2;
      	faPts[12] = .3;
      	faPts[13] = .6;
      	faPts[14] = .8;
      	faPts[15] = 1.0;
      	faPts[16] = .5;
      	// Find the interval that the point is in.
      	// This would be ideal with non-constant indices, but we do not have that ability.
      	float fPointCount = 17.0;
      	float fInterval = 2.0*(fCoordX + 4.0);
      	int kiIndex = int(floor(fInterval));
      	float fOffset = (fInterval - float(kiIndex));
      	float fInterpolatedY = 0.0;
      	// This is an odd way to find the interval for interpolation, but non-constant indices are not allowed.
      	for(int i = 0; i < 17; ++i) {
      		if (i == kiIndex) {
      			float fInterpolatedY = faPts[i]*(1.0 - fOffset) + fOffset*faPts[i + 1];
      			float fDiffY = abs(fCoordY - fInterpolatedY);
      			if (fDiffY < fPixelHeight) {
          		// Anti-alias by square root of the distance on the other channels
          		float fFill = fDiffY/fPixelHeight;
          		v4InitColor = (1.0 - fFill)*v4GraphColor + fFill*v4InitColor;
          		return v4InitColor;
        		}
      		}
      	}
      	return v4InitColor;
      }

      uniform float ufCanvasWidth;
      uniform float ufCanvasHeight;
      float fScale = 4.0;
      float fPixelWidth = fScale*2.0/ufCanvasWidth;
      float fPixelHeight = fScale*2.0/ufCanvasHeight;
      void main() {
        // Scale and shift to the range [-fScale, fScale]
        // (gl_FragCoord.x, gl_FragCoord.y) is a position in canvas coordinates [0.5, width-.5] and [0.5, height-.5]
        float fX = fScale*(2.0*gl_FragCoord.x/ufCanvasWidth - 1.0);
        float fY = fScale*(2.0*gl_FragCoord.y/ufCanvasHeight - 1.0);
        // Distance from the sin graph in the y direction
        // Get the background color
        vec4 v4BackColor = vec4(1.0, 1.0, 1.0, 1.0);
        vec4 v4GraphColor = vec4(0.0, 1.0, 0.0, 1.0);
        gl_FragColor = v4BackColor;
        gl_FragColor = DrawGraphLines(gl_FragColor, fX, fPixelWidth, 1.0);
        gl_FragColor = DrawGraphLines(gl_FragColor, fY, fPixelHeight, 1.0);
        gl_FragColor = DrawAxis(gl_FragColor, fX, fPixelWidth);
        gl_FragColor = DrawAxis(gl_FragColor, fY, fPixelHeight);
        gl_FragColor = DrawLinearInterpolationGraph(gl_FragColor, fX, fY, 2.0*fPixelHeight);
      }
    </script>
    <script type="text/javascript" src="LinearSplineInterpolation.js"></script>
  </head>
  <body onload="Initialization();">
    <canvas id="idCanvasWebGL" width="800", height="800" style="border:4px ridge lightgray"></canvas>
  </body>
</html>

LinearSplineInterpolation.js

    var gqProgram = null;
    var gqGL = null;
    function CreateProgramAndContext() {
      // Get the WebGL Context
      var qCanvas = document.querySelector("#idCanvasWebGL");
      gqGL = qCanvas.getContext("webgl");

      // Compile the vertex shader
      var sVertexShaderCode = document.querySelector("#idVertexShader").text;
      var qVertexShader = gqGL.createShader(gqGL.VERTEX_SHADER);
      gqGL.shaderSource(qVertexShader, sVertexShaderCode);
      gqGL.compileShader(qVertexShader);

      // Compile the fragment shader
      var sFragmentShaderCode = document.querySelector("#idFragmantShader").text;
      var qFragmentShader = gqGL.createShader(gqGL.FRAGMENT_SHADER);
      gqGL.shaderSource(qFragmentShader, sFragmentShaderCode);
      gqGL.compileShader(qFragmentShader);

      // Compile and link the program
      gqProgram = gqGL.createProgram();
      gqGL.attachShader(gqProgram, qVertexShader);
      gqGL.attachShader(gqProgram, qFragmentShader);
      gqGL.linkProgram(gqProgram);
      gqGL.useProgram(gqProgram);
    }

    function CreateBuffers() {
    	// The vertex buffer for the graph range
      var faVertices = new Float32Array([1.0, 1.0,  -1.0, 1.0,  1.0, -1.0,  -1.0, -1.0]);
      var qVerticesBuffer = gqGL.createBuffer();
      gqGL.bindBuffer(gqGL.ARRAY_BUFFER, qVerticesBuffer);
      gqGL.bufferData(gqGL.ARRAY_BUFFER, faVertices, gqGL.STATIC_DRAW);

      var qVertexLoc = gqGL.getAttribLocation(gqProgram, 'av2Vertex');
      gqGL.vertexAttribPointer(qVertexLoc, 2, gqGL.FLOAT, false, 0, 0);
      gqGL.enableVertexAttribArray(qVertexLoc);

      // Unbind the buffer
      gqGL.bindBuffer(gqGL.ARRAY_BUFFER, null);
    }

    function Initialization() {
      CreateProgramAndContext();
      CreateBuffers();
      var fCanvasWidth = gqGL.getUniformLocation(gqProgram, 'ufCanvasWidth');
      var fCanvasHeight = gqGL.getUniformLocation(gqProgram, 'ufCanvasHeight');
      gqGL.uniform1f(fCanvasWidth, gqGL.drawingBufferWidth);
      gqGL.uniform1f(fCanvasHeight, gqGL.drawingBufferHeight);

      gqGL.clearColor(0.0, 0.0, 0.0, 1.0);
      gqGL.clear(gqGL.COLOR_BUFFER_BIT);
      gqGL.drawArrays(gqGL.TRIANGLE_STRIP, 0, 4);
    }
 

Output

 
 

© 2007–2025 XoaX.net LLC. All rights reserved.