[C++] OpenGL: FrameBuffer geeft "corrupt" resultaat

Pagina: 1
Acties:

Onderwerpen


Acties:
  • 0 Henk 'm!

  • KompjoeFriek
  • Registratie: Maart 2001
  • Laatst online: 15-08 22:46
Hoi allemaal,

Ben bezig met video speler in SDL, en hiervoor maak ik nu gebruik van een fragment shader om de vertaling van ruwe video (YUV) naar RGB te doen.
Dit werkt allemaal mooi en aardig, maar zoals ik het nu werkend heb, zal de shader elke renderloop zijn werk doen, en helaas onnodig vaak hetzelfde video frame converteren.

Daar komt de FrameBuffer om de hoek.
De FrameBuffer wil ik gebruiken om de conversie éénmalig te doen, en het resultaat in een nieuwe texture op te slaan, zodat ik deze later zoals elke willekeurige andere texture kan renderen.
Als hier andere/betere alternatieven voor zijn, hoor ik dat natuurlijk graag :D
(Let wel op dat ik naast de video ook andere textures wil kunnen blijven renderen)

Alvast sorry voor de ENORME lap code...
Na twee dagen proberen, debuggen, specs lezen en voorbeelden doorspitten voor iets simpels als een framebuffertje verwacht ik dat ik toch nog iets simpels over het hoofd zie...


Voor de volledigheid zal laat ik eerst eens laten zien hoe ik het spul initialiseer:
C++:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
// Initialize SDL
SDL_Init( SDL_INIT_VIDEO );
// Set the default attributes
SDL_GL_SetAttribute( SDL_GL_DOUBLEBUFFER, 1 );
SDL_GL_SetAttribute( SDL_GL_DEPTH_SIZE, SCREEN_BPP );
SDL_GL_SetAttribute( SDL_GL_RED_SIZE, 8 );
SDL_GL_SetAttribute( SDL_GL_GREEN_SIZE, 8 );
SDL_GL_SetAttribute( SDL_GL_BLUE_SIZE, 8 );
SDL_GL_SetAttribute( SDL_GL_ALPHA_SIZE, 8 );
SDL_GL_SetAttribute( SDL_GL_SWAP_CONTROL, 1 );
pSurface = SDL_SetVideoMode( 480, 320, SCREEN_BPP, SDL_OPENGL );
// OpenGL settings
glEnable( GL_TEXTURE_2D );
glEnable( GL_LINES );
glClearColor( 0.0f, 0.0f, 0.0f, 0.0f );
glViewport( 0, 0, 480, 320 );
glClear( GL_COLOR_BUFFER_BIT );
glMatrixMode( GL_PROJECTION );
glLoadIdentity();
glOrtho( 0.0, 480, 320, 0.0, 0.0, 1.0 );
glMatrixMode( GL_MODELVIEW );
glLoadIdentity();
glEnable( GL_BLEND );
glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );


Hier de functie waarmee ik de Y, U en V data aan de fragment shader voer, die er vervolgens zijn kunstje mee doet:
C++:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
void RenderConverted()
{
    // Get Textures
    GLuint  textures[3] = { NULL };
    glGenTextures( 3, textures );
    if (!textures[0] || !textures[1] || !textures[2])   { return; } // Not all textures created!

    // Use the program.
    glUseProgram(pProgramHandle);

    int i = 0;
    const int videoWidth = 300;
    const int videoHeight = 225;

    // Set fragment shader variable
    GLint sampler1Uniform = glGetUniformLocation(pProgramHandle,"height");
    glUniform1f(sampler1Uniform, GLfloat(videoHeight));

    // Select texture unit 1 as the active unit and bind the U texture.
    glActiveTexture(GL_TEXTURE1);
    i=glGetUniformLocation(pProgramHandle,"Utex");
    glUniform1i(i,1);  // Bind Utex to texture unit 1
    glBindTexture(GL_TEXTURE_RECTANGLE_NV,textures[0]);
    glTexParameteri(GL_TEXTURE_RECTANGLE_NV,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
    glTexParameteri(GL_TEXTURE_RECTANGLE_NV,GL_TEXTURE_MIN_FILTER,GL_LINEAR);
    glTexEnvf(GL_TEXTURE_ENV,GL_TEXTURE_ENV_MODE,GL_DECAL);
    glTexImage2D(GL_TEXTURE_RECTANGLE_NV,0,GL_LUMINANCE,GetStride( Plane_U ),videoHeight /2,0,GL_LUMINANCE,GL_UNSIGNED_BYTE,GetPlane( Plane_U ));
    // Select texture unit 2 as the active unit and bind the V texture.
    glActiveTexture(GL_TEXTURE2);
    i=glGetUniformLocation(pProgramHandle,"Vtex");
    glBindTexture(GL_TEXTURE_RECTANGLE_NV,textures[1]);
    glUniform1i(i,2);  // Bind Vtext to texture unit 2
    glTexParameteri(GL_TEXTURE_RECTANGLE_NV,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
    glTexParameteri(GL_TEXTURE_RECTANGLE_NV,GL_TEXTURE_MIN_FILTER,GL_LINEAR);
    glTexEnvf(GL_TEXTURE_ENV,GL_TEXTURE_ENV_MODE,GL_DECAL);
    glTexImage2D(GL_TEXTURE_RECTANGLE_NV,0,GL_LUMINANCE,GetStride( Plane_V ),videoHeight /2,0,GL_LUMINANCE,GL_UNSIGNED_BYTE,GetPlane( Plane_V ));
    // Select texture unit 0 as the active unit and bind the Y texture.
    glActiveTexture(GL_TEXTURE0);
    i=glGetUniformLocation(pProgramHandle,"Ytex");
    glUniform1i(i,0);  // Bind Ytex to texture unit 0
    glBindTexture(GL_TEXTURE_RECTANGLE_NV,textures[2]);
    glTexParameteri(GL_TEXTURE_RECTANGLE_NV,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
    glTexParameteri(GL_TEXTURE_RECTANGLE_NV,GL_TEXTURE_MIN_FILTER,GL_LINEAR);
    glTexEnvf(GL_TEXTURE_ENV,GL_TEXTURE_ENV_MODE,GL_DECAL);
    glTexImage2D(GL_TEXTURE_RECTANGLE_NV,0,GL_LUMINANCE,GetStride( Plane_Y ),videoHeight ,0,GL_LUMINANCE,GL_UNSIGNED_BYTE,GetPlane( Plane_Y ));

    // Note that this image is horizontally flipped
    glBegin(GL_QUADS);
    glTexCoord2i(          0,           0 );
    glVertex2i(            0, videoHeight );
    glTexCoord2i( videoWidth,           0 );
    glVertex2i(   videoWidth, videoHeight );
    glTexCoord2i( videoWidth, videoHeight );
    glVertex2i(   videoWidth,           0 );
    glTexCoord2i(          0, videoHeight );
    glVertex2i(            0,           0 );
    glEnd();

    // Disable the program.
    glUseProgram(0);

    // Clean up
    if (textures[0]) { glDeleteTextures( 1, &textures[0] ); textures[0] = NULL; }
    if (textures[1]) { glDeleteTextures( 1, &textures[1] ); textures[1] = NULL; }
    if (textures[2]) { glDeleteTextures( 1, &textures[2] ); textures[2] = NULL; }
}


En vervolgens is dit mijn (versimpelde) renderloop:
C++:
1
2
3
4
5
6
7
8
// Begin
glClearColor( 0.0f, 0.0f, 0.0f, 0.0f );
glClear( GL_COLOR_BUFFER_BIT );

RenderConverted();

// Flip the surfaces
SDL_GL_SwapBuffers();


Bovenstaande code geeft 't gewenste resultaat.


Vervolgens ben ik met de FrameBuffer aan de slag gegaan...
Ik heb voor de oudere EXT functies gekozen omdat ik heb gelezen dat deze ook op OpenGL ES 2.0 zullen werken, en de nieuwe functies zonder EXT onderdeel zijn van OpenGL 3.1. But correct me if i'm wrong!

Een globale FrameBuffer aangemaakt met:
C++:
1
2
3
GLuint frameBufferObject = 0;
glGenFramebuffersEXT(1, &frameBufferObject);
if (!frameBufferObject) { return; }


Gebruik van de FrameBuffer:
C++:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
void CreateVideoTexture()
{
    // Prepare texture for the FrameBuffer to render on
    glGenTextures( 1, &texture );
    if (!texture) { return false; } // No texture created
    const int videoWidth = 300;
    const int videoHeight = 225;
    GLenum textureFormat = (SDL_BYTEORDER == SDL_BIG_ENDIAN) ? GL_BGRA : GL_RGBA;
    glBindTexture(GL_TEXTURE_2D, texture);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, videoWidth, videoHeight, 0, textureFormat, GL_UNSIGNED_BYTE, NULL); // Reserve memory
    glBindTexture(GL_TEXTURE_2D, 0);

    // Prepare depth buffer
    glGenTextures(1, &depth);
    glBindTexture(GL_TEXTURE_2D, depth);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT32, videoWidth, videoHeight, 0, GL_RED, GL_BYTE, NULL); // Reserve memory

    glBindTexture(GL_TEXTURE_2D, 0); // Make sure no texture is bound when starting to use the Frame Buffer

    // Bind the framebuffer object
    glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, frameBufferObject);

    // Attach a texture to the Frame Buffer Object
    glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, texture, 0);
    glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_2D, depth, 0);

    // Check if the Frame Buffer Object is OK
    GLenum framebufferStatus = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);
    if (framebufferStatus != GL_FRAMEBUFFER_COMPLETE_EXT) { return; }

    // Render the fragment shader stuff
    RenderConverted();

    // Unbind the Frame Buffer Object
    glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
}


Nieuwe renderloop:
C++:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
// Begin
glClearColor( 0.0f, 0.0f, 0.0f, 0.0f );
glClear( GL_COLOR_BUFFER_BIT );

if (!texture) { CreateVideoTexture(); }

const int videoWidth = 300;
const int videoHeight = 225;
// Render the texture!
glBindTexture(GL_TEXTURE_2D, texture);
glBegin(GL_QUADS);
glTexCoord2i(          0,           0 );
glVertex2i(            0,           0 );
glTexCoord2i( videoWidth,           0 );
glVertex2i(   videoWidth,           0 );
glTexCoord2i( videoWidth, videoHeight );
glVertex2i(   videoWidth, videoHeight );
glTexCoord2i(          0, videoHeight );
glVertex2i(            0, videoHeight );
glEnd();

// Flip the surfaces
SDL_GL_SwapBuffers();


Dit geeft mij het volgende resultaat:
Afbeeldingslocatie: http://i47.tinypic.com/2qbsjn4.png

Voor mijn ongetraind oog lijkt het wel alsof ik onbedoelt een feedback loop heb gemaakt, waar ze in menig voorbeeld al voor waarschuwen. Maar voor zover ik weet unbind ik alles netjes optijd...

Elke tip of opmerking is welkom!
(Note: mijn voorbeeld plaatje hierboven is 480x320, maar in de code staat voor video 300x225. Dit heb ik gedaan om duidelijk aan te geven dat het renderwindow en de video verschillende afmetingen hebben)

WhatPulse! - Rosetta@Home - Docking@Home


Acties:
  • 0 Henk 'm!

  • PrisonerOfPain
  • Registratie: Januari 2003
  • Laatst online: 26-05 17:08
Je cleared je depth buffer niet.

Acties:
  • 0 Henk 'm!

  • Zoijar
  • Registratie: September 2001
  • Niet online

Zoijar

Because he doesn't row...

Dacht ik ook, maar aan de andere kant is de default glDisable(GL_DEPTH_TEST).

Je moet even na elk stukje OpenGL op errors testen. Kan je zoiets voor gebruiken:

C++:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
#ifndef FS_NO_GL_ERRORS
/// Check the GL for errors.
/// \param msg Message to append to an error
/// \param th Throw exception on error
inline void check_gl_errors(const char* msg, bool th = true) {
    bool error = false;
    GLuint errnum;

    std::string errstr;
    while ((errnum = glGetError())) {
        switch (errnum) {
        case GL_INVALID_ENUM:
            errstr = std::string("INVALID_ENUM: enum argument out of range");
            break;
        case GL_INVALID_VALUE:
            errstr = std::string("INVALID_VALUE: Numeric argument out of range");
            break;
        case GL_INVALID_OPERATION:
            errstr = std::string("INVALID_OPERATION: Operation illegal in current state");
            break;
        case GL_INVALID_FRAMEBUFFER_OPERATION:
            errstr = std::string("INVALID_FRAMEBUFFER_OPERATION: Framebuffer object is not complete");
            break;
        case GL_OUT_OF_MEMORY:
            errstr = std::string("OUT_OF_MEMORY: Not enough memory left to execute command");
            break;
        default:
            errstr = std::string("Unknown error");
        }

        std::cerr << "GLError: " << errstr << std::endl;
        std::cerr << "   at: " << msg << std::endl;
        std::cerr.flush();
        error = true;
    }

    if (th && error) {
        throw std::runtime_error(
            std::string("OpenGL Error [") + errstr + std::string("] at ") + std::string(msg)
        );
    }
}
#else
/// Disabled version of GL error check. Does nothing.
/// \param msg Message to append to an error
/// \param th Throw exception on error
inline void check_gl_errors(const char* msg, bool th = true) {}
#endif


Kan beter tegenwoordig met debug faciliteiten, maar aangezien je legacy opengl gebruikt is dat denk ik niet aan de orde. Overigens is dat ook een punt terzijde; dit is hele oude opengl code, zelfs 3.1 is erg oud. Je kan het beste nu opengl 4.3 gebruiken. Hoewel legacy code wel nog mogelijk is.

Het is erg lastig fouten te zien aan opengl code omdat het grote state machine is -- als je ergens anders misschien een state flag zet, of dat je GUI dat doet, en die zet je niet goed terug, kan dat fouten veroorzaken die niet te zien zijn aan code.

Je shader staat er ook niet bij overigens.

Als je de hardware hebt kan je beter naar ogl 4.3 compute shaders kijken, stuk makkelijker dan naar textures renderen.

Ik zie ook geen glDrawBuffer(GL_COLOR_ATTACHMENT0); geloof wel dat dat moet. (ik zet wel altijd gldrawbuffers voor multiple render targets output)

Oh, wacht, bind je nou dezelfde texture voor input naar je shader als voor output in je FBO? Dat werkt namelijk niet (altijd, undefined). Je code is rommelig; ik zie niet precies wat je nou doet in welke volgorde... waarom maak je elke frame nieuwe textures?

[ Voor 4% gewijzigd door Zoijar op 14-03-2013 12:49 ]


Acties:
  • 0 Henk 'm!

  • KompjoeFriek
  • Registratie: Maart 2001
  • Laatst online: 15-08 22:46
Bedankt voor jullie reacties!
Deze hele depth buffer wordt verder niet eens gebruikt. Ik had heb toegevoegd omdat vrijwel elk voorbeeld dat aangeeft wel te doen want anders zou het framebuffer niet compleet zijn.

Ondertussen heb ik de hele depth buffer verwijderd.
Zoijar schreef op donderdag 14 maart 2013 @ 12:38:
[...]
dit is hele oude opengl code, zelfs 3.1 is erg oud. Je kan het beste nu opengl 4.3 gebruiken. Hoewel legacy code wel nog mogelijk is.
Gaat die nieuwe code ook werken op OpenGL ES 2.0? Ik wil het straks ook op IOS en Android kunnen gebruiken :)
Zoijar schreef op donderdag 14 maart 2013 @ 12:38:
[...]
Ik zie ook geen glDrawBuffer(GL_COLOR_ATTACHMENT0); geloof wel dat dat moet. (ik zet wel altijd gldrawbuffers voor multiple render targets output)

[...]
waarom maak je elke frame nieuwe textures?
De glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT); heb ik toegevoegd, net voor ik glCheckFramebufferStatusEXT() uitvoer.

Error checken lijkt me ook een goed plan, thanx!

Ik maak voor elk videoframe nieuwe textures omdat ik straks frames zou willen "preloaden" om haperingen tijdens het afspelen te voorkomen door bv schijf IO.

De fragment shader had ik weggelaten omdat ik dacht dat deze verder niks met mijn problemen te maken heeft, maar hier is ie:
C++:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
const char* fragmentShaderCode =
    "uniform float height;\n"
    "uniform sampler2DRect Ytex;\n"
    "uniform sampler2DRect Utex,Vtex;\n"
    "void main(void) {\n"
    "  float nx,ny,r,g,b,y,u,v;\n"
    "  vec4 txl,ux,vx;"
    "  nx=gl_TexCoord[0].x;\n"
    "  ny=height-gl_TexCoord[0].y;\n"
    "  y=texture2DRect(Ytex,vec2(nx,ny)).r;\n"
    "  u=texture2DRect(Utex,vec2(nx/2.0,ny/2.0)).r;\n"
    "  v=texture2DRect(Vtex,vec2(nx/2.0,ny/2.0)).r;\n"
    
    "  y=1.1643*(y-0.0625);\n"
    "  u=u-0.5;\n"
    "  v=v-0.5;\n"
    
    "  r=y+1.5958*v;\n"
    "  g=y-0.39173*u-0.81290*v;\n"
    "  b=y+2.017*u;\n"
    
    "  gl_FragColor=vec4(r,g,b,1.0);\n"
    "}\n";

Deze komt van fourcc.org, alleen is de height bij mij variabel.


Heb nog wat verder zitten spelen, en na het aanzetten van GL_TEXTURE_RECTANGLE_NV krijg ik wat meer resultaat!
dus dit toegevoegd boven in RenderConverted():
C++:
1
glEnable( GL_TEXTURE_RECTANGLE_NV );

Hierdoor krijg in geen troep meer.
Blijkbaar moet ik nog spelen met de viewport en ortho om het beeld goed te zetten. En op zijn kop tekenen hoeft ook niet meer, dat doet de framebuffer al blijkbaar. Deze dingen kom ik wel uit.

Maar door het aanzetten van GL_TEXTURE_RECTANGLE_NV is er wel een ander probleem ontstaan:
Alle overige GL_TEXTURE_2D dingen worden niet meer gerenderd!
Als ik onderaan in RenderConverted() de GL_TEXTURE_RECTANGLE_NV weer uitzet gaan de GL_TEXTURE_2D dingen weer goed, maar krijg ik alsnog troep in plaats van video.

Na wat zoekwerk is het duidelijk dat GL_TEXTURE_RECTANGLE_NV voorrang heeft op GL_TEXTURE_2D, dus zolang GL_TEXTURE_RECTANGLE_NV aanstaat zal GL_TEXTURE_2D niet werken. Dat zie ik ook direct terug.
Maar waarom faalt GL_TEXTURE_RECTANGLE_NV als ik deze waar dan ook weer uitzet?

WhatPulse! - Rosetta@Home - Docking@Home


Acties:
  • 0 Henk 'm!

  • KompjoeFriek
  • Registratie: Maart 2001
  • Laatst online: 15-08 22:46
Probleem is opgelost!

glEnable(GL_TEXTURE_RECTANGLE_NV); staat nu voor het binden van de FrameBuffer, en ook voor het renderen van de FrameBuffer.

glDisable(GL_TEXTURE_RECTANGLE_NV); komt dan uiteraard na het binden van de FrameBuffer, en ook na het renderen van de FrameBuffer.

Verder heb ik nog voor het binden van de FrameBuffer de viewport en ortho goed gezet
C++:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
    // Store attibutes
    glPushAttrib(GL_VIEWPORT_BIT | GL_COLOR_BUFFER_BIT);
    glViewport( 0, 0, videoWidth, videoHeight );
    glClear( GL_COLOR_BUFFER_BIT );

    // Setup modelview matrix
    glMatrixMode(GL_MODELVIEW);
    glPushMatrix();
    glLoadIdentity();

    // Setup projection matrix
    glMatrixMode(GL_PROJECTION);
    glPushMatrix();
    glLoadIdentity();

    glOrtho( 0.0, videoWidth, videoHeight, 0.0, 0.0, 1.0 );


En na het unbinden van de framebuffer:
C++:
1
2
3
4
5
6
7
8
9
10
    // reset projection matrix
    glMatrixMode(GL_PROJECTION);
    glPopMatrix();

    // reset modelview matrix
    glMatrixMode(GL_MODELVIEW);
    glPopMatrix();

    // restore attributes
    glPopAttrib();


En verder heb ik dankzij de error checking er nog een hele berg andere fouten uitgehaald.
duizendmaal dank hiervoor! _o_
PrisonerOfPain schreef op donderdag 14 maart 2013 @ 16:24:
Ik zou eerst eens je (vendor) extensions nalopen, een hoop van je code gebruikt oude standaarden (FBOs zijn opgenomen in de ARB, er is native support voor rectangle textures etc).

Verder zijn rectangle textures niet echt nodig meer, ze waren geintroduceerd om non-power-of-two textures to ondersteunen alleen doet iedereen dat tegenwoordig al. Ze hebben nu dus enkel het side-effect dat je unnormalized texture coordinates kunt gebruiken volgens mij is dat geen harde requirement voor je. Kortom, switch het allemaal naar GL_TEXTURE_2D en pas je shader code aan dat alles in de 0..1 range zit ipv een pixel range.
Dat klinkt ook wel interessant. Wellicht een goede vervolgstap. Thanx!

[ Voor 94% gewijzigd door KompjoeFriek op 14-03-2013 16:40 ]

WhatPulse! - Rosetta@Home - Docking@Home


Acties:
  • 0 Henk 'm!

  • PrisonerOfPain
  • Registratie: Januari 2003
  • Laatst online: 26-05 17:08
Ik zou eerst eens je (vendor) extensions nalopen, een hoop van je code gebruikt oude standaarden (FBOs zijn opgenomen in de ARB, er is native support voor rectangle textures etc).

Verder zijn rectangle textures niet echt nodig meer, ze waren geintroduceerd om non-power-of-two textures to ondersteunen alleen doet iedereen dat tegenwoordig al. Ze hebben nu dus enkel het side-effect dat je unnormalized texture coordinates kunt gebruiken volgens mij is dat geen harde requirement voor je. Kortom, switch het allemaal naar GL_TEXTURE_2D en pas je shader code aan dat alles in de 0..1 range zit ipv een pixel range.

Acties:
  • 0 Henk 'm!

  • KompjoeFriek
  • Registratie: Maart 2001
  • Laatst online: 15-08 22:46
Onderstaande post stond in een nieuw topic ([OpenGL] FragmentShader) maar is naar dit topic gemerged ([C++] OpenGL: FrameBuffer geeft "corrupt" resultaat) omdat het, in dit geval, handiger is in 't bestaande topic verder te gaan


Na de tip van PrisonerOfPain in "\[C++] OpenGL: FrameBuffer geeft "corrupt" resultaat" ben ik begonnen met de vertaalslag van GL_TEXTURE_RECTANGLE_NV naar GL_TEXTURE_2D.

De laatste stap die ik hiervoor nog moet doen, is m'n shader aanpassen dat hij z'n coördinaten van 0 tot 1 gebruikt ipv 0 tot width.

Dat heb ik gedaan door de width en height door te geven aan de shader. In de shader deel ik de fragment positie door de totale grootte van de textures, waardoor ik netjes die coördinaten tussen 0 en 1 moet krijgen.

Het resultaat dat ik hiermee krijg lijkt net of de pixel op 0, 0 uit de bron textures gebruikt wordt, en op alle pixels gerenderd wordt... :|

Originele shader voor GL_TEXTURE_RECTANGLE_NV:
C++:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
    uniform float height;
    uniform sampler2DRect Ytex;
    uniform sampler2DRect Utex,Vtex;
    void main(void) {
      float nx,ny,r,g,b,y,u,v;
      vec4 txl,ux,vx;
      nx=gl_TexCoord[0].x;
      ny=height-gl_TexCoord[0].y;
      y=texture2DRect(Ytex,vec2(nx,ny)).r;
      u=texture2DRect(Utex,vec2(nx/2.0,ny/2.0)).r;
      v=texture2DRect(Vtex,vec2(nx/2.0,ny/2.0)).r;
     
      y=1.1643*(y-0.0625);
      u=u-0.5;
      v=v-0.5;
           
      r=y+1.5958*v;
      g=y-0.39173*u-0.81290*v;
      b=y+2.017*u;
           
      gl_FragColor=vec4(r,g,b,1.0);
    }


Aangepaste shader voor GL_TEXTURE_2D:
C++:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
    uniform vec2 resolution;
    uniform sampler2D Ytex;
    uniform sampler2D Utex,Vtex;
    void main(void) {
      float nx,ny,r,g,b,y,u,v;
      vec4 txl,ux,vx;
      nx=gl_TexCoord[0].x/resolution.x;
      ny=(resolution.y-gl_TexCoord[0].y)/resolution.y;
      y=texture2D(Ytex,vec2(nx,ny)).r;
      u=texture2D(Utex,vec2(nx/2.0,ny/2.0)).r;
      v=texture2D(Vtex,vec2(nx/2.0,ny/2.0)).r;
     
      y=1.1643*(y-0.0625);
      u=u-0.5;
      v=v-0.5;
           
      r=y+1.5958*v;
      g=y-0.39173*u-0.81290*v;
      b=y+2.017*u;
           
      gl_FragColor=vec4(r,g,b,1.0);
    }


In mijn vorige topic heb ik de volledige code gepost van hoe ik de textures aanbied aan de shader, maar hier een korte snippit voor één van de textures:
C++:
1
2
3
4
5
6
7
8
9
10
    // Select texture unit 0 as the active unit and bind the Y texture.
    glActiveTexture(GL_TEXTURE0);
    i=glGetUniformLocation(pShaderProgram->getProgram(),"Ytex");
    glUniform1i(i,0);  // Bind Ytex to texture unit 0
    glBindTexture(GL_TEXTURE_RECTANGLE_NV,m_textures[2]);

    glTexParameteri(GL_TEXTURE_RECTANGLE_NV,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
    glTexParameteri(GL_TEXTURE_RECTANGLE_NV,GL_TEXTURE_MIN_FILTER,GL_LINEAR);
    glTexEnvf(GL_TEXTURE_ENV,GL_TEXTURE_ENV_MODE,GL_DECAL);
    glTexImage2D(GL_TEXTURE_RECTANGLE_NV,0,GL_LUMINANCE,planeStride[Plane_Y],pixelsHigh,0,GL_LUMINANCE,GL_UNSIGNED_BYTE,planeData[Plane_Y]);


Hier heb ik dus letterlijk alle GL_TEXTURE_RECTANGLE_NV vervangen voor GL_TEXTURE_2D.

Na weer een tijd specs lezen (verschil sampler2DRect -> sampler2D en verschil texture2DRect -> texture2D) en hardcoded waardes bij de shader invullen ben ik eigenlijk geen steek verder gekomen :/

Heb het gevoel dat het iets heel triviaals is dat ik over het hoofd zie... Als iemand me weer op de goede weg kan helpen, graag :D

ps: Nog mooie en handige tools gevonden: GLIntercept en gDEBugger, maar ook hiermee kwam ik niet verder.

[ Voor 3% gewijzigd door RobIII op 19-03-2013 18:25 . Reden: Merged topics ]

WhatPulse! - Rosetta@Home - Docking@Home


Acties:
  • 0 Henk 'm!

  • Zoijar
  • Registratie: September 2001
  • Niet online

Zoijar

Because he doesn't row...

Ik zie even niet precies "de" fout, maar een paar dingen:

Je kan gewoon texture coordinates tussen [0,1] meegeven als je dit zo wilt doen; die wordt goed geinterpoleerd. Anders kan je je gl_FragCoord built-in gebruiken voor de pixel coordinaten in integers, en delen door textureSize(sampler) glsl functie. Of is je texcoord al [0,1], dan hoef je natuurlijk niets te delen door de resolutie?

Je leest gefilterd uit je texture; is dat echt wat je wilt? Je hebt ook dingen als texelFetch om gewoon echt een texel op te halen. In combinatie met gl_FragCoord werkt dit prima.

Waarom maak je drie single-channel textures (GL_LUMINANCE etc is overigens ook allemaal deprecated, dat is gewoon GL_RED nu, en als format de combinatie intern: GL_R8 extern: GL_RED, type: GL_UNSIGNED_BYTE) en niet gewoon een RGB texture? Of krijg je het zo uit je camera oid?

texture2D() is ook deprecated. Ik zou je aanraden om alle fixed functie te vervangen door modern opengl -- als in, leer het dan meteen goed.

Zie ook http://www.opengl.org/wiki/Sampler_%28GLSL%29 en http://www.opengl.org/wiki/Main_Page iha, dat is een geweldige website.

Het is een beetje lastig lezen soms omdat het legacy en modern door elkaar is.

Maar ik weet niet precies welke hardware je target -- ogl 3.2, ogl 4.3, ogl es 2.0 of ogl es 3.0. De nieuwe releases kunnen dit allemaal wel.

[ Voor 13% gewijzigd door Zoijar op 19-03-2013 20:25 ]

Pagina: 1