我正在寻找一个与libGDX一起使用的最小扫描线着色器,最好选择改变效果的强度。
这里有一个libGDX示例(缺少vert和frag文件):
Shaders in libgdx have no effect [Desktop]
但是,这需要使用FrameBuffer。有没有更优雅的解决方案,我可以将vert和frag文件放入我的着色器文件夹,然后在我的代码中设置如下:
private String vertexShader;
private String fragmentShader;
private ShaderProgram shaderProgram;
@Override
public void create()
{
vertexShader = Gdx.files.internal("shaders/vertex.glsl").readString();
fragmentShader = Gdx.files.internal("shaders/fragment.glsl").readString();
shaderProgram = new ShaderProgram(vertexShader, fragmentShader);
spriteBatch.setShader(shaderProgram);
}
我的游戏针对的是低端Android手机。我目前得到一个相当稳定的60fps,并希望保持这种表现。
编辑1: 在Tenfour04的片段之后,我的顶点文件目前看起来像这样:
attribute vec4 a_position;
attribute vec4 a_color;
attribute vec2 a_texCoord0;
uniform mat4 u_projTrans;
uniform float u_screenHeight;
varying vec4 v_color;
varying vec2 v_texCoords;
void main()
{
v_color = a_color;
v_texCoords = a_texCoord0;
gl_Position = u_projTrans * a_position;
}
编辑2: 新的,可能更简单的方法,但渲染失去透明度:
#ifdef GL_ES
precision mediump float;
#endif
varying vec4 v_color;
varying vec2 v_texCoords;
uniform sampler2D u_sampler2D;
uniform mat4 u_projTrans;
void main(void)
{
vec2 p = vec2(floor(gl_FragCoord.x), floor(gl_FragCoord.y));
if (mod(p.y, 2.0)==0.0)
gl_FragColor = vec4(texture2D(u_sampler2D,v_texCoords).xyz ,1.0);
else
gl_FragColor = vec4(0.0,0.0,0.0 ,1.0);
}
答案 0 :(得分:1)
您可以保持方法不变,仍然保持透明。
这是片段着色器中的main():
string filePath = @"C:\Folder\file.txt";
StreamReader sr = new StreamReader(filePath);
string s = sr.ReadToEndAsync().GetAwaiter().GetResult();
Console.WriteLine(s);
有了这个,我有了透明的纹理显示便宜的扫描线。请注意,我使用4.0作为除数,只是个人喜好。
无论如何,关键是只能修改gl_FragColor = texture2D(u_TextureUnit, v_TextureCoordinates);
if (mod(floor(gl_FragCoord.y),4.0) == 0.0)
gl_FragColor.rgb *= 0.5;
并保留'gl_FragColor.a`(alpha通道)。
我也正在研究快速而肮脏的扫描线效果,并在搜索gl_FragColor.rgb
和gl_FragCoord.y
之后到达了这个问题。您问题中的mod
解决了我的问题。
答案 1 :(得分:0)
这是我认为可行的着色器。我没有测试它,所以你可能需要调试它。您可以自定义线数和强度常数以获得所需的外观。这非常简单地基于正弦曲线,并且它仅导致变暗。通过使用正弦波使颜色变亮和变暗,您可以做更精细的效果。您还可以使用步进函数截断正弦函数,以增加其真实性。
std::rotate
//Vertex shader (same as SpriteBatch's default)
attribute vec4 a_position;
attribute vec4 a_color;
attribute vec2 a_texCoord0;
varying vec2 v_texCoords;
varying vec4 v_color;
uniform mat4 u_projTrans;
void main()
{
v_texCoords = a_texCoord0;
v_color = a_color;
v_color.a = v_color.a * (255.0/254.0);
gl_Position = u_projTrans * a_position;
}
它使用屏幕高度作为参数,因此您必须在调整屏幕大小时设置屏幕高度:
//Fragment shader
#ifdef GL_ES
precision mediump float;
#endif
const float LINE_COUNT = 90.0;
const float FREQ = LINE_COUNT * 2.0 * 3.14159;
const float INTENSITY = 0.4;
varying vec2 v_texCoords;
varying vec3 v_color;
uniform sampler2D u_texture;
uniform float u_screenHeight;
void main()
{
vec4 texture = texture2D(u_texture, v_texCoords);
float screenV = gl_FragCoord.y / u_screenHeight;
float scanLine = 1.0 - INTENSITY * (sin(FREQ * screenV) * 0.5 + 0.5);
//Possibly cheaper methods, in increasing realism / performance hit
//float scanLine = 1.0 - INTENSITY * mod(screenV * LINE_COUNT, 1.0);
//float scanLine = 1.0 - INTENSITY * step(0.5, mod(screenV * LINE_COUNT, 1.0));
//float scanLine = 1.0 - INTENSITY * abs(mod(screenV * LINE_COUNT, 1.0) - 0.5);
gl_FragColor = v_color * vec4(texture.rgb * scanLine, texture.a);
}
如果您使用我上面注释的public void resize (int width, int height){
//...
shader.begin();
shader.setUniformf("u_screenHeight", height);
shader.end();
}
扫描线计算而不是基于mod()
的计算,您可以通过将其更改为:
sin()
并将着色器的shader.setUniformf("u_screenHeight", LINE_COUNT / (float)height);
行screenV
更改为/
,然后从scanLine计算中删除*
。这样可以节省操作,而且我认为*比/稍快一些。 (如果这样做,您可以考虑将u_screenHeight变量重命名为有意义的变量。)