在webgl中绘制圆看起来像椭圆

时间:2019-03-26 11:52:03

标签: javascript webgl

我是webgl的新手,正在尝试绘制圆形,但是不知何故,它看起来像椭圆形但不是我想要的形状。我在哪里犯了错误(或代码中的其他问题)?

index.html文件仅包含width = 900 height = 600的canvas元素。所以我没有在这里添加它。

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

2 个答案:

答案 0 :(得分:2)

缺少的是WebGL始终在画布上采用从-1到+1的剪辑空间坐标,而与尺寸无关,因此,如果画布不是正方形,则需要寻找一些数学运算来补偿。

由于只是数学,所以有1000种更改代码的方法。

一种方法是将您的位置乘以画布的纵横比。

您当前有这个

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涵盖了所有这些解决方案以及更多

答案 1 :(得分:1)

缺少的是补偿视口不是正方形的事实。如果要通过以下操作将其变成正方形:

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

您会得到正确的圆圈。

要支持任何视口大小,必须使用诸如投影变换之类的方法。您可以查找orthographic projection。基本上,您将所有座标乘以这样的东西:

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