【问题标题】:Radial reveal of image in OpenGL shaderOpenGL着色器中图像的径向显示
【发布时间】:2015-07-14 23:29:02
【问题描述】:

我正在玩着色器概念,以使用 OpenGL ES 中的着色器径向显示图像。最终目标是通过在渲染完整圆形进度纹理的片段着色器中丢弃片段来创建圆形进度条。

我已将我的想法编码为here in ShaderToy,以便您可以使用它。我似乎无法让它工作,而且由于无法调试,我很难找出原因。

这是我的片段着色器的 glsl 代码:

float magnitude(vec2 vec)
{
    return sqrt((vec.x * vec.x) + (vec.y * vec.y));
}

float angleBetween(vec2 v1, vec2 v2)
{
    return acos(dot(v1, v2) / (magnitude(v1) * magnitude(v2)));
}

float getTargetAngle() 
{
    return clamp(iGlobalTime, 0.0, 360.0);
}

// OpenGL uses upper left as origin by default
bool shouldDrawFragment(vec2 fragCoord)
{
    float targetAngle = getTargetAngle();

    float centerX = iResolution.x / 2.0;
    float centerY = iResolution.y / 2.0;
    vec2 center = vec2(centerX, centerY);

    vec2 up = vec2(centerX, 0.0) - center;
    vec2 v2 = fragCoord - center;

    float angleBetween = angleBetween(up, v2);

    return (angleBetween >= 0.0) && (angleBetween <= targetAngle);
}

void mainImage( out vec4 fragColor, in vec2 fragCoord )
{
  vec2 uv = fragCoord.xy / iResolution.xy;
  if (shouldDrawFragment(fragCoord)) {
    fragColor = texture2D(iChannel0, vec2(uv.x, -uv.y));
  } else {
    fragColor = texture2D(iChannel1, vec2(uv.x, -uv.y));
  }
}

它从两侧从底部扫出。我只是想让它从一个指向上方的向量中扫出,并以顺时针方向移动。

【问题讨论】:

  • 看起来不错。是安卓版还是IOS版?任何一个都有调试工具。
  • 这不好,所以我的问题在这里。我在着色器玩具上运行代码。平台无关紧要,这是一个通用的着色器问题。

标签: opengl-es opengl-es-2.0 fragment-shader


【解决方案1】:

试试这个代码:

const float PI     = 3.1415926;
const float TWO_PI = 6.2831852;

float magnitude(vec2 vec)
{
    return sqrt((vec.x * vec.x) + (vec.y * vec.y));
}

float angleBetween(vec2 v1, vec2 v2)
{
    return atan( v1.x - v2.x, v1.y - v2.y ) + PI;
}

float getTargetAngle() 
{
    return clamp( iGlobalTime, 0.0, TWO_PI );
}

// OpenGL uses upper left as origin by default
bool shouldDrawFragment(vec2 fragCoord)
{
    float targetAngle = getTargetAngle();

    float centerX = iResolution.x / 2.0;
    float centerY = iResolution.y / 2.0;
    vec2 center = vec2(centerX, centerY);

    float a = angleBetween(center, fragCoord );

    return a <= targetAngle;
}

void mainImage( out vec4 fragColor, in vec2 fragCoord )
{
  vec2 uv = fragCoord.xy / iResolution.xy;
  if (shouldDrawFragment(fragCoord)) {
    fragColor = texture2D(iChannel0, vec2(uv.x, -uv.y));
  } else {
    fragColor = texture2D(iChannel1, vec2(uv.x, -uv.y));
  }
}

说明:

我所做的主要更改是计算两个向量之间角度的方式:

return atan( v1.x - v2.x, v1.y - v2.y ) + PI;

这是 v1 和 v2 之间的差向量的角度。如果您交换 x 和 y 值,它将改变 0 角所在的方向,即如果您尝试以下操作:

return atan( v1.y - v2.y, v1.x - v2.x ) + PI;

圆圈从右侧而不是向上开始。您还可以反转 atan 的值来改变动画的方向。

在计算夹角时你也不必担心向上的向量,注意代码只取中心和当前片段坐标之间的夹角:

float a = angleBetween(center, fragCoord );

其他说明:

记住计算是以弧度为单位的,而不是度数,所以我及时更改了钳位(尽管这并不真正影响输出):

return clamp( iGlobalTime, 0.0, TWO_PI );

您有一个与您的某个函数同名的变量:

float angleBetween = angleBetween(up, v2);

应该避免这种情况,因为并非所有实现都对此感到满意,我无法在我当前的机器上编译你的着色器,直到我改变它。

【讨论】:

  • 这完全符合我的要求。更新了我在 ShaderToy 上保存的着色器。谢谢。
【解决方案2】:

只改下面两个函数

float getTargetAngle() 
{
    return clamp(iGlobalTime, 0.0, 6.14);
}

bool shouldDrawFragment(vec2 fragCoord)
{
    float targetAngle = getTargetAngle();

    float centerX = iResolution.x / 2.0;
    float centerY = iResolution.y / 2.0;
    vec2 center = vec2(centerX, centerY);

    vec2 up = vec2(centerX, 0.0) - center;
    vec2 v2 = fragCoord - center;


  if(fragCoord.x>320.0)// a half width
  {
    up += 2.0*vec2(up.x,-up.y);
    targetAngle *= 2.;
  }
  else  
  {
    up -= 2.0*vec2(up.x,-up.y);
    targetAngle -= 1.57;
  }
    float angleBetween = angleBetween(up, v2);

    return (angleBetween >= 0.0) && (angleBetween <= targetAngle);
}

【讨论】:

    猜你喜欢
    • 2023-03-13
    • 2014-03-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-09-08
    相关资源
    最近更新 更多