Dear Firend : I am new at WebGl. I have managed to draw and rotate a triangle -- but the problem is that the triangle 1, The triangle change size and shape while drawing. 2, I dont know how to rotate the triangle around one of its cornor.
Following is the code. I have written the code in a linear fashion with a utility class (GlUtil) that wraps up the boring tasks.
I am using a function called perc2glCoord that allow me to enter percentages and convert them into gl coordinates.
import GlUtil from "./glUtil/glUtil.js";
import perc2glCoord from "./functions/perc2glCoord.js";
const gl = GlUtil.getGl("bilza");
console.log(gl);
const vertices = [
perc2glCoord (50) ,perc2glCoord (50), 1,0,0,
perc2glCoord (50) ,perc2glCoord (75), 0,1,0,
perc2glCoord (75) ,perc2glCoord (50), 0,0,1,
// perc2glCoord (25) ,perc2glCoord (50), 1,0,0,
// perc2glCoord (75) ,perc2glCoord (50), 0,1,0,
// perc2glCoord (50) ,perc2glCoord (75), 0,0,1,
];
const vertexShaderSrc =
`
attribute highp vec2 a_pos;
attribute highp vec3 a_clr;
uniform float translateX;
uniform float translateY;
uniform float angle;
varying highp vec3 vColor;
void main(void) {
gl_Position = vec4(
translateX + (a_pos.x * cos(angle) - a_pos.y * sin(angle)),
translateY + (a_pos.x * sin(angle) + a_pos.y * cos(angle)),
1.0,
1.0 );
vColor = a_clr;
}
`;
const fragShaderSrc =
`
varying highp vec3 vColor;
void main(void) {
gl_FragColor = vec4 (vColor , 1.0);
}
`;
const vertexShader = GlUtil.createShader(gl,vertexShaderSrc,gl.VERTEX_SHADER);
const fragmentShader = GlUtil.createShader(gl,fragShaderSrc,gl.FRAGMENT_SHADER);
const programe = GlUtil.getProgram(gl,vertexShader,fragmentShader);
const VOB = GlUtil.getBuffer(gl);
GlUtil.bindBuffer(gl,VOB,vertices);
GlUtil.linkNuseProgram(gl,programe);
let angleValue = 0;
function draw(){
GlUtil.setAttribute(gl,"a_pos",programe, 2 ,4*5,0);
GlUtil.setAttribute(gl,"a_clr",programe, 3 , 4*5,2 * 4);
const translateXLoc = gl.getUniformLocation(programe, "translateX");
gl.uniform1f(translateXLoc,0.0);
const translateYLoc = gl.getUniformLocation(programe, "translateY");
gl.uniform1f(translateYLoc,0.0);
const angleLoc = gl.getUniformLocation(programe, "angle");
const rands = Math.PI * angleValue /180;
gl.uniform1f(angleLoc,rands);
angleValue+= 0.1;
/////////////////////---draw-----------------
GlUtil.clear(gl,0.1,0.1,0.2);
gl.drawArrays(gl.TRIANGLES , 0, 3);
requestAnimationFrame(draw);
}
draw();
---
Here is the GlUtil helper object
export default class GlUtil {
static getGl(canvasId :string ="bilza"):WebGLRenderingContext{
const canvas = document.getElementById(canvasId) as HTMLCanvasElement;
if (canvas == null){
throw new Error("canvas not found");
}
const gl = canvas.getContext("webgl");
if (gl == null) {
throw new Error("Unable to initialize WebGL. Your browser or machine may not support it.");
}
//---Got gl
return gl;
}
static getProgram(gl :WebGLRenderingContext,vshader:WebGLShader, fshader :WebGLShader) :WebGLProgram {
const pgm = gl.createProgram();
if (pgm == null){throw new Error("failed to create program");}
//-----------
gl.attachShader(pgm, vshader);
gl.attachShader(pgm, fshader);
//-------------
// pgm.vertexPosAttrib = gl.getAttribLocation( pgm , 'pos');
// this.gl.useProgram(this.program);
return pgm;
}
static getBuffer(gl :WebGLRenderingContext):WebGLBuffer{
let b = gl.createBuffer();
if (b == null){throw("failed to create buffer");}
return b;
}
static createShader(gl :WebGLRenderingContext, shaderSource :string, shaderType:number):WebGLShader {
var shader = gl.createShader(shaderType);
if (shader == null){
throw new Error("shaders could not be created");
}
gl.shaderSource(shader, shaderSource);
gl.compileShader(shader);
let compiled = gl.getShaderParameter(shader, gl.COMPILE_STATUS);
if (!compiled) {
// There are errors, so display them
var errors = gl.getShaderInfoLog(shader);
console.log('Failed to compile with these errors:' + "type:" + shaderType, errors );
}
return shader;
}
static bindBuffer(gl :WebGLRenderingContext,buff :WebGLBuffer,buffData :number[]){
gl.bindBuffer(gl.ARRAY_BUFFER, buff);
gl.bufferData( gl.ARRAY_BUFFER, new Float32Array(buffData),
gl.STATIC_DRAW);
}
static linkNuseProgram(gl :WebGLRenderingContext,prgrm :WebGLProgram){
gl.linkProgram(prgrm);
gl.useProgram(prgrm);
}
static clear(gl :WebGLRenderingContext,r:number=0,g:number=0,b:number=0,a:number=1){
gl.clearColor(r,g,b,a);
gl.clear(gl.COLOR_BUFFER_BIT);
}
////////////////////////////////////////////////////
static setAttribute(gl :WebGLRenderingContext,nameStr :string,programe :WebGLProgram,numberOfComps :number,stride:number, offset :number=0){
const vertexPosAttrib = gl.getAttribLocation( programe, `${nameStr}`);
gl.enableVertexAttribArray( vertexPosAttrib);
gl.vertexAttribPointer(
vertexPosAttrib, //index
numberOfComps, //number of components =2 x and y
gl.FLOAT, //data type
false, //normalized
stride , //stride - the comple vertex row bytes
offset //offset = 0
);
}
///////////////////////////////////////////////
}
Anf finally here is the picture of the triangle
Tried all the examples and help that I could find on the internet including re-learning the math
Since GL's drawing-area is stretched to fit the viewport
, you need to take into account aspect ratio
of the view in gl_Position
calculation.
For example, appending aspectRatio
parameter to the vertex shader,
uniform float aspectRatio;
:
gl_Position = vec4(
(translateX + (a_pos.x * cos(angle) - a_pos.y * sin(angle))) / aspectRatio,
translateY + (a_pos.x * sin(angle) + a_pos.y * cos(angle)),
1.0,
1.0 );
pass the viewport aspect-ratio as follows.
const viewport = gl.getParameter(gl.VIEWPORT); // [x, y, width, height]
const aspectRatioLoc = gl.getUniformLocation(programe, "aspectRatio");
gl.uniform1f(aspectRatioLoc, viewport[2] / viewport[3]);