【问题标题】:Possible to set an initial value for a shader uniform? (Android, OpenGL ES 2.0)可以为着色器制服设置初始值吗? (安卓,OpenGL ES 2.0)
【发布时间】:2013-04-11 17:03:52
【问题描述】:

编辑:正如建议的那样,我试图在我的构造函数中为我的着色器制服设置一个“初始”值,我已经包含了一些代码,如果有人能解释我为什么会得到,我将不胜感激如果我通过构造函数传入值,则会出现空白屏幕 - 谢谢

加载纹理的方法

public void setTexture(GLSurfaceView view, Bitmap imgTexture) {
    this.imgTexture=imgTexture;
    iProgId = Utils.LoadProgram(strVShader, strFShader);
    iBaseMap = GLES20.glGetUniformLocation(iProgId, "u_baseMap");
    iPosition = GLES20.glGetAttribLocation(iProgId, "a_position");
    iTexCoords = GLES20.glGetAttribLocation(iProgId, "a_texCoords");
    texID = Utils.LoadTexture(view, imgTexture);

    //Everything is working if I include the lines as part of my setTexture() method
    GLES20.glUseProgram(iProgId);
    mOpacityHandle = GLES20.glGetUniformLocation(iProgId, "opValue");
    GLES20.glUniform1f(mOpacityHandle, 1.0f);
}

但是如果我把它们放在我的构造函数中,什么都没有......

public Quad() {
    //iProgId = Utils.LoadProgram(strVShader, strFShader); //I've tried with and without this line - I can confirm that loading / linking is working OK
    GLES20.glUseProgram(iProgId);
    mOpacityHandle = GLES20.glGetUniformLocation(iProgId, "opValue");          
    GLES20.glUniform1f(mOpacityHandle, 1.0f);           
}

我实际上已将整个纹理加载例程复制到我的构造函数中,并在创建四边形时将相关参数传递给它,但我仍然什么都没有,除非我在构造函数运行后的某个时间设置值!

我有一个片段着色器如下:

String strFShader =
    "precision mediump float;" +
    "uniform float opValue;"+
    "varying vec2 v_texCoords;" +
    "uniform sampler2D u_baseMap;" +
    "void main()" +
    "{" +
    "gl_FragColor = texture2D(u_baseMap, v_texCoords);" +
    "gl_FragColor *= opValue;"+
    "}";

当我创建我的对象(四边形)时,我有一个方法可以设置所述四边形的不透明度,如下所示:

public void setOpacity(float op) {  
    GLES20.glUseProgram(iProgId);       
    mOpacityHandle = GLES20.glGetUniformLocation(iProgId, "opValue");
    GLES20.glUniform1f(mOpacityHandle, op);
}

但是,如果我希望我的 sprite(quad) 具有一定程度的透明度,我只想运行我的 setOpacity 方法。如果我不指定不透明度级别(即,如果我不运行 setOpacity 方法),我希望它使用默认值或“初始”值(显然我希望它是 1.0 的浮点数)。

这可能吗?

【问题讨论】:

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


    【解决方案1】:

    如果这就是你的意思,你不能在着色器中使用某种uniform opValue = 1.0; 来初始化制服。即使可以,它也不会为您带来太多好处,因为统一的值在程序使用中是持久的。这意味着如果您激活另一个程序(使用glUseProgram)然后重新绑定该程序,则制服仍将具有您上次设置的值。因此,您可以在链接程序后立即将制服设置为某个初始值,但是一旦您将其更改为某些透明精灵,它就会永远失去该值。

    它甚至在单个程序使用期间都不起作用,因为除此之外,统一值在绘图调用中保持不变。想一想,如果你写了

    draw_opaque_sprite();
    
    setOpacity(0.5f);
    draw_transparent_sprite();
    
    draw_opaque_sprite();
    

    在绘制透明精灵后,程序应该如何知道您想要将不透明度重置为某个默认值。当然,要求应用程序为每个绘图调用设置所有制服是没有选择的。

    因此,您将无法为每个精灵正确设置制服。在这种情况下,通常的优化是按对象的渲染状态(在您的情况下是不透明度,但可能其他一些状态甚至更重,如纹理或类似的东西)以减少状态变化(如着色器变化、纹理绑定,或者在这种情况下统一更新)。

    【讨论】:

    • 感谢@ChristianRau,但我不想在每次绘制/渲染后重置不透明度,而是在创建对象时(例如quad1 = new Quad();)和我随后不要设置不透明度,我希望它假设标准不透明度为 1.0。
    • @Zippy 好吧,将其设置为默认值 1.0(像往常一样使用 glUniform),它会一直保持这种状态,直到您更改它,然后它将保持新值,直到您更改它,就像答案中解释的那样。您不能为每个 "object" 设置一个值,因为 OpenGL 绝对没有任何 "objects" 的概念。每个程序的每个制服都有一个值,并且该值仅在 调用glUniform 时更改。这就是 OpenGL 中一切工作的方式,它是一个状态机。
    • 再次感谢@ChristianRau,我必须承认我对 OGL 还很陌生,因此非常感谢您的解释。如果我从我的自定义类创建 2 个四边形,然后在每个四边形上设置不同级别的不透明度,如果它们共享相同的程序和着色器,它们如何以不同的不透明度级别显示每个?谢谢,我很难理解这一点。关于使用glUniform“最初”设置级别,我试图在构造函数中执行此操作,但它不起作用,我假设因为在构造函数处尚未创建/链接着色器程序.
    • @Ziggy 您可以随时更改统一值。当绘制某些东西(例如使用glDrawArraysglDrawElements)时,绘制的对象将通过图形管道和着色器发送,并且着色器将使用制服。如果你不绘制任何东西,那么着色器当然不会做任何事情。所以绑定程序(glUseProgram),设置第一个对象的状态(包括它的制服),绘制它,然后设置第二个对象的状态,然后绘制它......
    • ...这就是 OpenGL 的工作原理。它由一组状态组成,这些状态仅在 更改它们时更改,并且仅在您使用绘图命令实际渲染某些内容时生效。 OpenGL 没有任何抽象场景对象的概念。当您绘制某些东西时,它的顶点将通过图形管道传递并使用 OpenGL 的当前状态(活动纹理、活动程序、其制服、全局状态...)渲染到屏幕,并且在绘制顶点之后,OpenGL 完全忘记了它们并且下一帧一切重新开始。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多