GLSL изменить однородную текстуру для каждого объекта - PullRequest
1 голос
/ 27 июня 2011

В настоящее время я пытаюсь рисовать простые сетки, используя различные текстуры (используя C # и OpenTK).Я много читал о TextureUnit и привязках, и это моя текущая реализация (не работает должным образом):

private void ApplyOpaquePass()
{
    GL.UseProgram(this.shaderProgram);
    GL.CullFace(CullFaceMode.Back);

    while (this.opaqueNodes.Count > 0)
        Draw(this.opaqueNodes.Pop());

    GL.UseProgram(0);
}

И мой метод отрисовки:

private void Draw(Assets.Model.Geoset geoset)
{
    GL.ActiveTexture(TextureUnit.Texture1);
    GL.BindTexture(TextureTarget.Texture2D, geoset.TextureId /*buffer id returned by GL.GenTextures*/ );
    GL.Uniform1(GL.GetUniformLocation(this.shaderProgram, "Texture1"), 1 /*see note below*/ );

    //Note: if I'm correct, it should be 1 when using TextureUnit.Texture1
    //      (2 for Texture2...), note that doesn't seem to work since no
    //      texture texture at all is sent to the shader, however a texture
    //      is shown when specifying any other number (0, 2, 3...)

    // Draw vertices & indices buffers...
}

И мой код шейдера (этоне должно быть проблемой, так как с ультрафиолетовым отображением все в порядке):

uniform sampler2D Texture1;

void main(void)
{
    gl_FragColor = texture2D(Texture1, gl_TexCoord[0].st);
}

В чем проблема:

  • Поскольку geoset.TextureId может варьироваться от одного геосета к другому, я ожидаю, что в шейдер будет отправлена ​​другая текстура.

  • Вместо этого ко всем объектам (геосетям) всегда применяется одинаковая текстура.

Идеи:

  • Использование различных текстур для каждой текстуры (работает хорошо), но что произойдет, если у нас будет 2000 различных текстур?Если мое понимание верно, мы должны использовать несколько TextureUnit, только если мы хотим использовать несколько текстур одновременно в шейдере.

  • Сначала я подумал, что униформане может быть изменен после определения, но тест с логической формой сказал мне, что это действительно возможно.

    private void Draw(Assets.Model.Geoset geoset)
    {
        GL.ActiveTexture(TextureUnit.Texture1);
        GL.BindTexture(TextureTarget.Texture2D, geoset.TextureId);
        GL.Uniform1(GL.GetUniformLocation(this.shaderProgram, "Texture1"), 1 );
    
        //added line...
        GL.Uniform1(GL.GetUniformLocation(this.shaderProgram, "UseBaseColor"), (geoset.Material.FilterMode == Assets.Model.Material.FilterType.Blend) ? 1: 0);
    
        // Draw vertices & indices buffers...
    }
    

    Код шейдера:

    uniform sampler2D Texture1;
    uniform bool UseBaseColor;
    
    void main(void)
    {
        gl_FragColor = texture2D(Texture1, gl_TexCoord[0].st);
    
        if (UseBaseColor)
            gl_FragColor = mix(vec4(0,1,1,1), gl_FragColor , gl_FragColor .a);
    }
    

    Этот код прекрасно работает, рисуянекоторый геосет с базовым цветом вместо прозрачности, который (должен?) доказывает, что форму можно изменить здесь.Почему это не работает с моими текстурами?

  • Должен ли я использовать разные шейдерные программы для каждого геосета?

Заранее спасибо за ваши ответы:)

С уважением,Брюс

РЕДАКТИРОВАТЬ: вот как я генерирую текстуры в рендере:

override public uint GenTexture(Bitmap bmp)
{
    uint texture;
    GL.GenTextures(1, out texture);

        //I disabled this line because I now bind the texture before drawing a geoset
        //Anyway, uncommenting this line doesn't show a better result
        //GL.BindTexture(TextureTarget.Texture2D, texture);

    System.Drawing.Imaging.BitmapData data = bmp.LockBits(new Rectangle(0, 0, bmp.Width, bmp.Height), System.Drawing.Imaging.ImageLockMode.ReadOnly, System.Drawing.Imaging.PixelFormat.Format32bppArgb);
    GL.TexImage2D(TextureTarget.Texture2D, 0, PixelInternalFormat.Rgba, data.Width, data.Height, 0,
        OpenTK.Graphics.OpenGL.PixelFormat.Bgra, PixelType.UnsignedByte, data.Scan0);
    bmp.UnlockBits(data);

    //temp settings
    GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMinFilter, (int)TextureMinFilter.Linear);
    GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMagFilter, (int)TextureMagFilter.Linear);

    return texture;
}

Ответы [ 2 ]

2 голосов
/ 28 июня 2011

Я наконец решил свою проблему! Все ответы улучшили мое понимание и привели меня к решению, которое заключалось в двух основных проблемах:

1) как сказал Calvin1602, очень важно связать вновь созданную текстуру перед вызовом glTexImage2d.

2) Также UncleZeiv привлек мое внимание к последнему параметру GL.Uniform1. Учебник OpenTK очень вводит в заблуждение, потому что парень передает id объекта текстуры в функцию, которая здесь работает, потому что порядок генерации текстуры точно совпадает с идентификатором используемого TextureUnit. Поскольку я был не уверен, что мое понимание было точным, я ошибочно изменил этот параметр обратно на geoset.TextureId.

Спасибо!

0 голосов
/ 27 июня 2011

Вам не нужны несколько шейдерных программ, если единственное, что вы меняете, - это текстура.Кроме того, одинаковые местоположения постоянны на протяжении всего жизненного цикла шейдерной программы, поэтому нет необходимости извлекать их каждый кадр.Однако вам нужно перепривязывать текстуру каждый раз, когда вы ее изменяете, и вам нужно будет привязывать каждую отдельную текстуру к отдельному идентификатору текстуры.

В результате я бы пришел к выводу, что то, что вы опубликовали, должно работатьи поэтому проблема, вероятно, где-то еще в вашем коде.

РЕДАКТИРОВАТЬ: после обновленной версии он все еще должен работать.Однако меня беспокоит, почему закомментирована следующая строка:

 //GL.BindTexture(TextureTarget.Texture2D, texture);

Это должно быть там.В противном случае вы будете продолжать писать ту же текстуру (что смешно).Вам нужно связать текстуру перед инициализацией.Теперь вполне возможно, что что-то еще сломано, но, учитывая то, что я вижу сейчас, это единственная ошибка, которая выскакивает у меня.

...