在这个绘制圆的着色器中,约0.222的神奇值是从哪里来的



我正在开发一个在WebGL中绘制圆的着色器,它似乎可以工作,但我不确定如何工作。这是顶点着色器:

in vec2 a_unit;
uniform mat3 u_projection;
uniform vec3 u_transform;
out vec2 v_pos;
void main() {
v_pos = a_unit;
float r = u_transform.z;
float x = u_transform.x - r;
float y = u_transform.y - r;
float w = r * 2.0;
float h = r * 2.0;
mat3 world = mat3(
w, 0, 0, 
0, h, 0, 
x, y, 1
);
gl_Position = vec4(u_projection * world * vec3(a_unit, 1), 1);
}

这是碎片着色器:

in vec2 v_pos;
uniform vec4 u_color;
uniform vec3 u_transform;
uniform mat3 u_projection;
out vec4 outputColor;
void main() { 
vec2 dist = v_pos - 0.5;
if (dist.x * dist.x + dist.y * dist.y > .222) {
discard;
}
outputColor = u_color;
}

我向着色器传递一个u_projection矩阵,它只是我的相机。我还传递了一个u_transform向量,它就是我的圆的世界坐标(和世界半径(。

例如,u_transform可能类似于(200, 300, 25),用于用radius: 25x: 200y: 300处绘制圆

哦,a_unit只是一个四单元:

[
0, 0,
0, 1,
1, 0,
1, 0,
0, 1,
1, 1,
]

逻辑是,我只画一个矩形,然后通过丢弃不在半径内的任何东西来剪裁。于是画了一个圆。

我的困惑在于这一行:

if (dist.x * dist.x + dist.y * dist.y > .222) { discard; }

我通过反复猜测和检查得出了0.222的值。我不明白它是怎么工作的。为什么这个神奇的数字能画一个圆圈?

我想我需要将radius转换为纹理坐标,但这似乎不是必需的?但我不知道为什么。。

为什么这能画出一个任意半径的圆?什么是合适的值,因为0.222虽然很接近,但不是确切的值。我应该在这里使用什么值来代替0.222

您可以尝试以下代码:(这是一个新代码(:

onload = function(){
const canvas = document.querySelector("canvas")
var gl = canvas.getContext("webgl")

const vertexShaderCode = document.getElementById("vertexShaderCode").innerHTML
const fragmentShaderCode = document.getElementById("fragmentShaderCode").innerHTML
var vertices = []

var x , y , x1 , y1 , radius = 0.5 , startX = 0 , startY = 0
x1 = Math.cos(0) * radius
y1 = Math.sin(0) * radius
for(var degree=0; degree<=6.3; degree+=0.1){
x = Math.cos(degree) * radius
y = Math.sin(degree) * radius
vertices.push(startX + x1)
vertices.push(startY + y1)
vertices.push(startX)
vertices.push(startY)
vertices.push(startX + x)
vertices.push(startY + y)
x1 = x
y1 = y
}

var vertexShader = gl.createShader(gl.VERTEX_SHADER)
var fragmentShader = gl.createShader(gl.FRAGMENT_SHADER)
gl.shaderSource(vertexShader , vertexShaderCode)
gl.shaderSource(fragmentShader, fragmentShaderCode)
gl.compileShader(vertexShader)
gl.compileShader(fragmentShader)
if(!gl.getShaderParameter(vertexShader, gl.COMPILE_STATUS)){
console.error(`ERROR::Compiling vertex shader , n ${gl.getShaderInfoLog(vertexShader)}`)
}
if(!gl.getShaderParameter(fragmentShader, gl.COMPILE_STATUS)){
console.error(`ERROR::Compiling fragment shader , n ${gl.getShaderInfoLog(fragmentShader)}`)
}
var program = gl.createProgram()
gl.attachShader(program, vertexShader)
gl.attachShader(program, fragmentShader)
gl.linkProgram(program)
if(!gl.getProgramParameter(program, gl.LINK_STATUS)){
console.error(`ERROR::Linking current program , n ${gl.getProgramInfoLog(program)}`)
}
gl.validateProgram(program)
if(!gl.getProgramParameter(program, gl.VALIDATE_STATUS)){
console.error(`ERROR::validating current program , n ${gl.getProgramInfoLog(program)}`)
}
gl.useProgram(program)
var buffer = gl.createBuffer()
gl.bindBuffer(gl.ARRAY_BUFFER, buffer)
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertices), gl.STATIC_DRAW)
var positionAttribLocation = gl.getAttribLocation(program, "pos")
gl.vertexAttribPointer(
positionAttribLocation ,
2,
gl.FLOAT,
false,
2*Float32Array.BYTES_PER_ELEMENT,
0*Float32Array.BYTES_PER_ELEMENT
)
gl.enableVertexAttribArray(positionAttribLocation)

function loop(){
requestAnimationFrame(loop)
canvas.width = innerWidth
canvas.height = innerHeight
gl.viewport(0,0,canvas.width,canvas.height)
gl.clearColor(0,0,0,1)
gl.clear(gl.COLOR_BUFFER_BIT)

gl.drawArrays(gl.TRIANGLES, 0, vertices.length/2)
}
requestAnimationFrame(loop)
}
body {
margin:0;
width:100vw;
height:100vh;
overflow:hidden;
}
<!DOCTYPE html>
<html>
<head>
<title>Circle with WebGL</title>
</head>
<body>
<canvas>Your browser does not support HTML5 canvas !</canvas>
<script id="vertexShaderCode" type="x-shader/x-vertex">precision mediump float;

attribute vec2 pos;

void main(){
gl_Position = vec4(pos, 0.0, 1.0);
}
</script>
<script id="fragmentShaderCode" type="x-shader/x-fragment">precision mediump float;

void main(){
gl_FragColor = vec4(1.0 , 0.0 , 0.0 , 1.0);
}
</script>
</body>
</html>

此代码是您可以使用的新代码;(

最新更新