gpt4 book ai didi

swift - 实时发光着色器混淆

转载 作者:搜寻专家 更新时间:2023-11-01 05:37:58 26 4
gpt4 key购买 nike

所以我有一个相当简单的实时 2d 游戏,我正在尝试为其添加一些漂亮的光晕。将其简化为最基本的形式,它只是在黑色表面上绘制的圆圈和谎言。如果您从 hsv 颜色空间的角度考虑场景,所有颜色(黑色除外)的“v”值为 100%。

目前我有一种“累积”缓冲区,当前帧与前一帧连接在一起。它通过使用两个离屏缓冲区和一个黑色纹理来工作。

  1. 缓冲区一激活----------------
  2. 画线和点
  3. 缓冲区一已停用
  4. 激活缓冲区二----------------
  5. 缓冲绘制为全屏四边形的两个内容
  6. 在全屏上绘制的黑色纹理略带透明度
  7. 缓冲区一内容绘制
  8. 缓冲区二已停用
  9. 屏幕缓冲区已激活--------
  10. 将两个缓冲区的内容绘制到屏幕上

目前所有“延迟”都来自 cpu 上的延迟。 GPU 可以很好地处理所有这些。

所以我在考虑通过给事物添加发光效果来尝试使事物变得有趣。我在想也许对于第 10 步而不是使用常规纹理着色器,我可以使用一个绘制纹理但不带发光的着色器!

不幸的是,我对如何做到这一点有点困惑。这里有一些原因

  • 模糊东西。大多数情况下,有些人声称高斯模糊可以实时完成,而其他人则认为不应该。人们还提到另一种称为“焦点”模糊的模糊,我不知道它是什么。
  • 我能找到的大多数示例都使用 XNA。我需要一个用类似于 OpenGL es 2.0 的着色器语言编写的。
  • 有些人称之为发光,有些人称之为绽放
  • 不同的混合模式?可用于为原始纹理添加光晕。
  • 如何结合垂直和水平模糊?也许在一次抽奖电话中?

反正我理解的渲染辉光的过程是这样的

  1. 从中剔除暗数据
  2. 模糊光数据(使用高斯?)
  3. 在原始数据之上混合光数据(屏幕混合?)

到目前为止,我已经有了一个可以绘制纹理的着色器。我的下一步是什么?

//Vertex
percision highp float;

attrivute vec2 positionCoords;
attribute vec2 textureCoords;
uniform mat4 matrix;
uniform float alpha;
varying vec2 v_texcoord;
varying float o_alpha;

void main()
{
gl_Position = matrix * vec4(positionCoords, 0.0, 1.0);
v_texcoord = textureCoords.xy;
o_alpha = alpha;
}



//Fragment
varying vec2 v_texcoord;
uniform sampler2D s_texture;
varying float o_alpha;

void main()
{
vec4 color = texture2D(s_texture, v_texcoord);
gl_FragColor = vec4(color.r, color.g, color.b, color.a - o_alpha);
}

这也是实时可行的事情吗?

编辑:我可能想做 5px 或更小的模糊

最佳答案

要解决您最初的困惑:

  • 任何一种模糊滤镜都会根据每个像素的原始位置有效地将每个像素扩散到一个 Blob 中,并为所有像素累加此结果。过滤器之间的区别在于 Blob 的形状。
    • 对于高斯模糊,这个 Blob 应该是一个平滑的渐变,在边缘周围逐渐羽化到零。您可能需要高斯模糊。
    • “焦点”模糊是一种模拟失焦相机的尝试:它的 Blob 不是逐渐淡化到零,而是将每个像素散布在一个棱角分明的圆圈上,从而产生微妙不同的效果。
  • 对于简单的一次性效果,计算成本与模糊宽度成正比。这意味着窄(例如 5px 或更小)模糊作为实时单 channel 效果可能是可行的。 (通过使用多 channel 和多分辨率金字塔可以实时实现广泛的高斯模糊,但我建议先尝试一些更简单的方法...)
  • 您可以合理地将这种效果称为“发光”或“绽放”。然而,对我来说,“发光”意味着狭窄的模糊导致类似 NEON 的效果,而“绽放”意味着使用宽模糊来模拟高动态范围视觉环境中明亮物体的视觉效果。
  • 混合模式决定了你绘制的内容如何与目标缓冲区中的现有颜色相结合。在 OpenGL 中,使用 glEnable(GL_BLEND) 激活混合并使用 glBlendFunc() 设置模式。
  • 对于狭窄的模糊,您应该能够一次性进行水平和垂直过滤。

要进行快速单 channel 全屏采样,您需要确定源纹理中的像素增量。静态确定它是最快的,这样您的片段着色器就不需要在运行时计算它:

float dx = 1.0 / x_resolution_drawn_over;
float dy = 1.0 / y_resolution_drawn_over;

通过将纹理采样模式设置为 GL_LINEAR,并从源纹理 t< 中获取 4 个样本,您可以一次完成 3 像素 (1,2,1) 高斯模糊如下:

float dx2 = 0.5*dx;  float dy2 = 0.5*dy;  // filter steps

[...]

vec2 a1 = vec2(x+dx2, y+dy2);
vec2 a2 = vec2(x+dx2, y-dy2);
vec2 b1 = vec2(x-dx2, y+dy2);
vec2 b2 = vec2(x-dx2, y-dy2);
result = 0.25*(texture(t,a1) + texture(t,a2) + texture(t,b1) + texture(t,b2));

通过将纹理采样模式设置为 GL_LINEAR,并从源纹理中获取 9 个样本,您可以一次完成 5 像素 (1,4,6,4,1) 高斯模糊 t如下:

float dx12 = 1.2*dx; float dy12 = 1.2*dy;  // filter steps
float k0 = 0.375; float k1 = 0.3125; // filter constants

vec4 filter(vec4 a, vec4 b, vec4 c) {
return k1*a + k0*b + k1*c;
}

[...]

vec2 a1 = vec2(x+dx12, y+dy12);
vec2 a2 = vec2(x, y+dy12);
vec2 a3 = vec2(x-dx12, y+dy12);
vec4 a = filter(sample(t,a1), sample(t,a2), sample(t,a3));

vec2 b1 = vec2(x+dx12, y );
vec2 b2 = vec2(x, y );
vec2 b3 = vec2(x-dx12, y );
vec4 b = filter(sample(t,b1), sample(t,b2), sample(t,b3));

vec2 c1 = vec2(x+dx12, y-dy12);
vec2 c2 = vec2(x, y-dy12);
vec2 c3 = vec2(x-dx12, y-dy12);
vec4 c = filter(sample(t,c1), sample(t,c2), sample(t,c3));

result = filter(a,b,c);

我无法告诉您这些过滤器在您的平台上是否实时可行;全分辨率下 9 个样本/像素可能会很慢。

任何更宽的高斯分布都会使水平和垂直 channel 分离变得有利;更宽的高斯分布需要多分辨率技术来实现实时性能。 (请注意,与高斯不同,诸如“焦点”模糊之类的过滤器是不可分离的,这意味着它们不能分为水平和垂直 channel ...)

关于swift - 实时发光着色器混淆,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34571606/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com