Triangle with Gradient Shading

Having covered static, uniformly coloured shapes we now move on to a triangle with gradient shading. This is the start of a few pages in which we simplify for students the HelloWebGL demo supplied with Smart Mobile Studio. We use clipspace coordinates, and you should be able to convert them to use pixel coordinates if you prefer.

This example introduces gradient shading. Each vertex has its own colour, stored in a colour buffer in the same order as the coordinates of the corresponding vertices. A "varying" quantity is passed from the vertex shader to the fragment shader and the hardware interpolates values for each pixel to give it a colour dependant on its position. We obtain the location of aVertexColor in the vertex shader with the code
FVertexColorAttrib := FShaderProgram.AttribLocation("aVertexColor");
and supply it with data from the colour buffer with the line
FColorBuffer.VertexAttribPointer(FVertexColorAttrib, 3, False, 0, 0);.
We have added some comments to the originals in our demos and stripped out unnecessary code such as error trapping to try to make it slightly easier to follow.
unit Form1;

interface

uses
  System.Types, W3C.TypedArray, SmartCL.System, SmartCL.Graphics,
  SmartCL.Controls, SmartCL.Components, SmartCL.Forms, SmartCL.Fonts,
  SmartCL.Borders, SmartCL.Application, Khronos.WebGl, GLS.Base;

type
  TForm1 = class(TW3form)
  protected
    FCanvas: TW3GraphicContext;
    gl: JWebGLRenderingContext;
    rc: TGLRenderingContext;
    FTriangleBuffer, FColorBuffer : TGLArrayBuffer;
    FFragmentShader: TGLFragmentShader;
    FVertexShader: TGLVertexShader;
    FShaderProgram: TGLShaderProgram;
    FVertexPosAttrib, FVertexColorAttrib : Integer;
    procedure InitializeObject; override;
    procedure SetupScene;
    procedure Render;
  end;

implementation

procedure TForm1.InitializeObject;
begin
  inherited;
  FCanvas := TW3GraphicContext.Create(Self.Handle);
  gl := JWebGLRenderingContext(FCanvas.Handle.getContext('experimental-webgl'));
  rc := TGLRenderingContext.Create;
  rc.GL := gl;
  gl.canvas.width := 300;
  gl.canvas.height := 300;
  SetupScene;
  Render;
end;

procedure TForm1.SetupScene;
begin
  gl.clearColor(0.0, 0.0, 0.25, 1.0); // Set clear color to blue, fully opaque
  gl.clearDepth(1.0);                 // Clear everything
  gl.enable(gl.DEPTH_TEST);           // Enable depth testing
  gl.depthFunc(gl.LEQUAL);            // Near things obscure far things

  FColorBuffer := TGLArrayBuffer.Create(rc);
  FColorBuffer.SetData([
     1.0, 0.0, 0.0, //red
     0.0, 1.0, 0.0, //green
     0.0, 0.0, 1.0  //blue
    ], abuStatic);

  FTriangleBuffer := TGLArrayBuffer.Create(rc);
  FTriangleBuffer.SetData([
     0.0,  1.0,  0.0,
    -1.0, -1.0,  0.0,
     1.0, -1.0,  0.0
    ], abuStatic);

  // create vertex shader
  FVertexShader := TGLVertexShader.Create(rc);
  FVertexShader.Compile(#"
    attribute vec3 aVertexPosition;
    attribute vec3 aVertexColor;

    varying vec4 vColor;

    void main(void) {
       gl_Position = vec4(aVertexPosition, 1.0);
       vColor = vec4(aVertexColor, 1.0);
    }");

  // create fragment shader
  FFragmentShader := TGLFragmentShader.Create(rc);
  FFragmentShader.Compile(#"
    precision mediump float;
    varying vec4 vColor;
    void main(void) {
       gl_FragColor = vColor;
    }");

  // create shader program and link shaders
  FShaderProgram := TGLShaderProgram.Create(rc);
  FShaderProgram.Link(FVertexShader, FFragmentShader);

  FVertexPosAttrib := FShaderProgram.AttribLocation("aVertexPosition");
  FVertexColorAttrib := FShaderProgram.AttribLocation("aVertexColor");
end;

procedure TForm1.Render;
begin
  gl.ViewportSet(0, 0, FCanvas.Handle.width, FCanvas.Handle.height);
  gl.clear(gl.COLOR_BUFFER_BIT);  // clears background

  FShaderProgram.Use;

  gl.enableVertexAttribArray(FVertexPosAttrib);
  gl.enableVertexAttribArray(FVertexColorAttrib);

  FTriangleBuffer.VertexAttribPointer(FVertexPosAttrib, 3, False, 0, 0);
  FColorBuffer.VertexAttribPointer(FVertexColorAttrib, 3, False, 0, 0);
  gl.drawArrays(gl.TRIANGLES, 0, 3);
end;
 
initialization
  Forms.RegisterForm({$I %FILE%}, TForm1);

end. 
   
Programming - a skill for life!

Using WebGL for advanced graphics in Smart Mobile Studio