在 webgl 中画圆看起来像椭圆

Drawing circle in webgl looks like ellipse

我是 webgl 的新手,正在尝试画圆,但它看起来像一个椭圆,而不是我想要的精确形状。我哪里出错了(或代码中的其他问题)?

index.html 文件仅包含 canvas 元素,宽度 = 900 高度 = 600。所以这里就没有加了。

var vertexShader=['precision mediump float;','attribute vec2 vPosition;','attribute vec3 vColor;','varying vec3 fragColor;','void main()','{','fragColor=vColor;','gl_Position=vec4(vPosition,0.0,1.0);','}'].join('\n');
var fragmentShader=['precision mediump float;','varying vec3 fragColor;','void main(){','gl_FragColor=vec4(fragColor,1.0);','}'].join('\n');


function init(){
console.log('running');
var canvas=document.getElementById('canvas');
var gl=canvas.getContext('webgl');

//CLEAR
gl.clearColor(1.0,0.0,0.0,1.0);//R,G,B,Alfa
gl.clear(gl.COLOR_BUFFER_BIT);//gl.DEPTH_BUFFER_BIT

//SHADERS
var vertShader=gl.createShader(gl.VERTEX_SHADER);
gl.shaderSource(vertShader,vertexShader);
var fragShader=gl.createShader(gl.FRAGMENT_SHADER);
gl.shaderSource(fragShader,fragmentShader);
gl.compileShader(vertShader);
gl.compileShader(fragShader);

//PROGRAM
var program=gl.createProgram();
gl.attachShader(program,vertShader);
gl.attachShader(program,fragShader);
gl.linkProgram(program);
gl.useProgram(program);

var numberofsides=360;
var triangleVertices=yuvarlakCiz(-0.19,0,0,0.35,numberofsides);
var triangleVertices2=yuvarlakCiz(-0.1,0,0,0.29,numberofsides); 
triangleVertices=renkAyarla(1.0,1.0,1.0,triangleVertices);
triangleVertices2=renkAyarla(1.0,0.0,0.0,triangleVertices2);
console.log(triangleVertices);
//BUFFER
var triangleBuffer=gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER,triangleBuffer);
gl.bufferData(gl.ARRAY_BUFFER,new Float32Array(triangleVertices),gl.STATIC_DRAW);
//LOCATION ALMA
var attloc=gl.getAttribLocation(program,'vPosition');
var attcolor=gl.getAttribLocation(program,'vColor');
//ATTRIBUTE AYARLAMA
gl.vertexAttribPointer(
    attloc,
    2,
    gl.FLOAT,
    gl.FALSE,
    5*Float32Array.BYTES_PER_ELEMENT,
    0
);
gl.vertexAttribPointer(
    attcolor,
    3,
    gl.FLOAT,
    gl.FALSE,
    5*Float32Array.BYTES_PER_ELEMENT,
    2*Float32Array.BYTES_PER_ELEMENT
);
//İLK CIRCLE ÇİZME
gl.enableVertexAttribArray(attloc); 
gl.enableVertexAttribArray(attcolor);
gl.drawArrays(gl.TRIANGLE_FAN, 0,numberofsides+2);  
//2.CIRCLE BUFFER
var circle2=gl.createBuffer(); 
gl.bindBuffer(gl.ARRAY_BUFFER,circle2);
gl.bufferData(gl.ARRAY_BUFFER,new Float32Array(triangleVertices2),gl.STATIC_DRAW);

var attloc1=gl.getAttribLocation(program,'vPosition');
var attcolor1=gl.getAttribLocation(program,'vColor');
gl.vertexAttribPointer(
    attloc1,
    2,
    gl.FLOAT,
    gl.FALSE,
    5*Float32Array.BYTES_PER_ELEMENT,
    0
);
gl.vertexAttribPointer(
    attcolor1,
    3,
    gl.FLOAT,
    gl.FALSE,
    5*Float32Array.BYTES_PER_ELEMENT,
    2*Float32Array.BYTES_PER_ELEMENT
);
gl.enableVertexAttribArray(attloc1);
gl.enableVertexAttribArray(attcolor1);
//gl.drawArrays(gl.TRIANGLE_FAN, 0,numberofsides+2);


}

function yuvarlakCiz(x,y,z,radius,numberofsides){
var numberofVertices=numberofsides+2;
var doublepi=2*Math.PI;

var verticesX=[];
var verticesY=[];
var verticesZ=[];
verticesX[0]=x;
verticesY[0]=y;
verticesZ[0]=z;
for (var i = 1 ;i<numberofVertices; i++) {
 verticesX[i]=x+(radius * Math.cos(i*doublepi/numberofsides));      
 verticesY[i]=y+(radius * Math.sin(i*doublepi/numberofsides));
 verticesZ[i]=z;
}
var mergeVertices=[];
for (var i = 0 ;i<numberofVertices; i++) {
 mergeVertices[i*5]=verticesX[i];
 mergeVertices[i*5+1]=verticesY[i];
 mergeVertices[i*5+2]=0.0;
 mergeVertices[i*5+3]=0.0;
 mergeVertices[i*5+4]=0.0;
// mergeVertices[i*3+2]=verticesZ[i];
}
return mergeVertices;
}

function renkAyarla(r,g,b,dizi){ //SETTING COLORS
for (var i =0; i <dizi.length/5; i++) {
    dizi[i*5+2]=r;
    dizi[i*5+3]=g;
    dizi[i*5+4]=b;
}
return dizi;
}

Circle Example

缺少的是补偿您的视口不是正方形的事实。如果你通过做这样的事情把它变成一个正方形:

gl.viewport(0, 0, 600, 600);

你会得到正确的圈子。

要支持任何视口大小,您必须使用投影变换之类的东西。你可以查一下 orthographic projection。你基本上会用这样的东西乘以你的所有坐标:

 ( 600 / gl.drawingBufferWidth, 600 / gl.drawingBufferHeight )

缺少的是 WebGL 总是采用剪辑 space 坐标从 -1 到 +1 跨越 canvas 而不管尺寸,所以如果你的 canvas 不是正方形你需要找一些数学来补偿。

因为这只是数学,所以有 1000 种方法可以更改代码。

一种方法是将您的位置乘以 canvas 的方面。

您目前拥有这个

gl_Position=vec4(vPosition,0.0,1.0);

你可以改成这样

gl_Position=vec4(vPosition * vec2(600.0/900.0, 1),0.0,1.0);

您可以对其进行更改,以便您可以传入比例

uniform vec2 scale;
...
gl_Position=vec4(vPosition * scale,0.0,1.0);

然后通过查找其位置并设置

,将scale设置为600.0 / 900.0, 1

一种更常见的方式是使用一个或多个矩阵

uniform mat4 matrix;
...
gl_Position = matrix * vec4(vPosition, 0.0, 1.0);

在这种情况下,您可以应用与上面相同的比例,但您还可以做很多其他事情。

This series of articles 涵盖所有这些解决方案以及更多