这个神奇的值〜0.222在哪里来自此着色器中绘制一个圆圈的?

发布于 2025-01-20 09:03:10 字数 1523 浏览 0 评论 0原文

我正在开发一个在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;
}

我传递到着色器a u_proctivection矩阵,这只是我的相机。我还传递了u_transform向量,这只是我圆圈的世界坐标(和世界半径)。

因此,例如,u_transform可能是(200,300,25)用于在x上绘制一个圆圈的 :300 ,带有radius:25

哦,a_unit只是一个单位Quad:

[
  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

I'm developing a shader that draws a circle in WebGL, and it seems to work, but I'm not sure how. Here is the vertex shader:

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);
}

And here's the fragment shader:

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;
}

I pass in to the shader a u_projection matrix, which is just my camera. And I also pass in a u_transform vector, which is just the world coordinates (and world radius) of my circle.

So for example, u_transform might be something like (200, 300, 25) for drawing a circle at x: 200, y: 300, with radius: 25

Oh, and a_unit is just a unit quad:

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

The logic is that I just draw a rectangle and then clip out via discarding anything not within the radius. And thus a circle is drawn.

My confusion lies on this line:

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

I came up with the value 0.222 by just guessing and checking over and over. I don't understand how it works though. Why is this magical number able to draw a circle?

I thought I would need to convert the radius into texture coordinates, but it doesn't seem like that is required? But I'm not sure why..

Why does this work to draw a circle with an arbitrary radius? And what is the proper value, because 0.222, while being close, is not the exact value. What is the proper value I should be using instead of 0.222 here?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

李不 2025-01-27 09:03:10

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

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>

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

You can try this code : (This is a new code) :

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>

This code is a new code you can use ;)

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文