我在Java中使用OpenGL构建了一个很好的音乐可视化工具。它已经看起来非常整洁,但我已经考虑过为它添加一些后期处理。当时,它看起来像这样:
已经有一个用于记录输出的帧缓冲,因此我已经可以使用纹理。现在我想知道是否有人对某些效果有所了解。当前的Fragment着色器如下所示:
#version 440
in vec3 position_FS_in;
in vec2 texCoords_FS_in;
out vec4 out_Color;
//the texture of the last Frame by now exactly the same as the output
uniform sampler2D textureSampler;
//available data:
//the average height of the lines seen in the screenshot, ranging from 0 to 1
uniform float mean;
//the array of heights of the lines seen in the screenshot
uniform float music[512];
void main()
{
vec4 texColor = texture(textureSampler, texCoords_FS_in);
//insert post processing here
out_Color = texColor;
}
答案 0 :(得分:3)
大多数后期处理效果随时间而变化,因此通常有一个随时间变化的制服。例如,"波浪"可以使用sin(elapsedSec * wavyRadsPerSec + (PI * gl_FragCoord.y * 0.5 + 0.5) * wavyCyclesInFrame)
偏移纹理坐标来创建效果。
一些"后处理"效果可以非常简单地完成,例如,不是用glClear
清除后缓冲区,而是可以在整个屏幕上混合近乎黑色的透明四边形。这将创建一个持久效果,其中过去的帧在当前帧之后渐渐变为黑色。
可以通过从每个点以不同距离拍摄多个样本来实现定向模糊,并且更强地对更近的样本进行加权并求和。如果您跟踪相对于摄像机位置和方向的点的运动,则可以将其设置为运动模糊实现。
颜色转换也非常简单,只需将RGB视为矢量的XYZ,并对其进行有趣的转换。棕褐色和迷幻"迷幻"颜色可以这样生产。
您可能会发现将颜色转换为类似HSV的内容,对该表示进行转换以及将其转换回RGB以进行帧缓冲写入会很有帮助。您可能会影响色调,饱和度,例如,淡化为黑白,或平滑地增强色彩饱和度。
A"涂抹在远处"效果可以通过将帧缓冲区混合到帧缓冲区来完成,方法是读取从gl_FragCoord稍微扩展的texcoord,如texture(textureSampler, (gl_FragCoord * 1.01).xy)
。
在该注释中,您不需要这些纹理坐标属性,您可以使用gl_FragCoord找出您在屏幕上的位置,并使用(调整后的副本)来进行texture
调用。
在GLSLSandbox上查看一些着色器以获取灵感。
我在GLSLSandbox上完成了a simple emulation of the trail effect。在实际的循环中,循环将不存在,它将从一个小偏移量中获取一个样本。 "循环"效果会自行发生,因为它的输入包括最后一帧的输出。为了模拟最后一帧的纹理,我简单地做了它,这样我就可以计算出其他像素是什么。你可以读取最后一帧纹理,而不是在做尾迹效果时调用pixelAt之类的东西。
你可以用波而不是我假的正弦波。使用uv.x
选择适当缩放的索引。
<强> GLSL 强>
#ifdef GL_ES
precision mediump float;
#endif
uniform float time;
uniform vec2 mouse;
uniform vec2 resolution;
const float PI = 3.14159265358979323;// lol ya right, but hey, I memorized it
vec4 pixelAt(vec2 uv)
{
vec4 result;
float thickness = 0.05;
float movementSpeed = 0.4;
float wavesInFrame = 5.0;
float waveHeight = 0.3;
float point = (sin(time * movementSpeed +
uv.x * wavesInFrame * 2.0 * PI) *
waveHeight);
const float sharpness = 1.40;
float dist = 1.0 - abs(clamp((point - uv.y) / thickness, -1.0, 1.0));
float val;
float brightness = 0.8;
// All of the threads go the same way so this if is easy
if (sharpness != 1.0)
dist = pow(dist, sharpness);
dist *= brightness;
result = vec4(vec3(0.3, 0.6, 0.3) * dist, 1.0);
return result;
}
void main( void ) {
vec2 fc = gl_FragCoord.xy;
vec2 uv = fc / resolution - 0.5;
vec4 pixel;
pixel = pixelAt(uv);
// I can't really do postprocessing in this shader, so instead of
// doing the texturelookup, I restructured it to be able to compute
// what the other pixel might be. The real code would lookup a texel
// and there would be one sample at a small offset, the feedback
// replaces the loop.
const float e = 64.0, s = 1.0 / e;
for (float i = 0.0; i < e; ++i) {
pixel += pixelAt(uv + (uv * (i*s))) * (0.3-i*s*0.325);
}
pixel /= 1.0;
gl_FragColor = pixel;
}