如何在片段着色器中将分辨率从静态更改为动态

Posted

技术标签:

【中文标题】如何在片段着色器中将分辨率从静态更改为动态【英文标题】:How to change the resolution from static to dynamic in fragment shader 【发布时间】:2018-12-22 09:25:54 【问题描述】:

我有分辨率为 1920x1080 的片段着色器。但是,无论用户选择什么,我都想更改为动态分辨率。

我已经参考了 http://www.fourcc.org/source/YUV420P-OpenGL-GLSLang.c> 这个链接并将ny=576.0-gl_TexCoord[0].y;\n 行修改为ny=1080.0-gl_TexCoord[0].y;\n 1920 x 1080。

我的程序的完整来源是

#include <cplaywidget.h>
#include <mainwindow.h>


#define ATTRIB_VERTEX 3
#define ATTRIB_TEXTURE 4
#define BHANU
#define WORKING_420P
#define YUY2_test

extern int g_cs_Index;
#ifdef BHANU
QOpenGLTexture* texName;
GLuint texture;
#endif

#ifdef YUY2_test
GLubyte *Ytex,*UVtex;
GLhandleARB FSHandle,PHandle;
QOpenGLExtension_ARB_shader_objects* myShader = new QOpenGLExtension_ARB_shader_objects();

// fy   = /*1080.0-*/gl_TexCoord[0].y;
const char *FProgram=
      "uniform sampler2DRect Ytex;\n"
      "uniform sampler2DRect UVtex;\n"
      "void main(void) \n"
      "  float fx, fy, y, u, v, r, g, b;\n"

      "  fx   = gl_TexCoord[0].x;\n"
      "  fy   = 1080.0-gl_TexCoord[0].y;\n"

      "  y = texture2DRect(Ytex,vec2(fx,fy)).a;\n"
      "  u = texture2DRect(UVtex,vec2(fx/2.0,fy)).b;\n"
      "  v = texture2DRect(UVtex,vec2(fx/2.0,fy)).r;\n"

      "  y=1.164*(y-0.0627);\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";
#endif
extern camera_t* camera;


CPlayWidget::CPlayWidget(QWidget *parent):QOpenGLWidget(parent)

    textureUniformY = 0;
    textureUniformU = 0;
    textureUniformV = 0;

    id_y = 0;
    id_u = 0;
    id_v = 0;

    m_pBufYuv420p = NULL;
    m_pVSHader = NULL;
    m_pFSHader = NULL;
    m_pShaderProgram = NULL;
    m_pTextureY = NULL;
    m_pTextureU = NULL;
    m_pTextureV = NULL;
    m_pYuvFile = NULL;
    m_nVideoH = 0;
    m_nVideoW = 0;


CPlayWidget::~CPlayWidget()




void CPlayWidget::initializeGL()


    initializeOpenGLFunctions();

#ifdef YUY2_test
    int i;
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    glOrtho(0,1920,0,1080,-1,1);
    glViewport(0,0,1920,1080);
    glClearColor(0,0,0,0);
    glColor3f(1.0,0.84,0.0);
    glHint(GL_POLYGON_SMOOTH_HINT,GL_NICEST);

     myShader->initializeOpenGLFunctions();

    PHandle = myShader->glCreateProgramObjectARB();
    FSHandle= myShader->glCreateShaderObjectARB(GL_FRAGMENT_SHADER_ARB);

    myShader->glShaderSourceARB(FSHandle,1,&FProgram,NULL);
    myShader->glCompileShaderARB(FSHandle);

    myShader->glGetObjectParameterivARB(FSHandle,GL_OBJECT_COMPILE_STATUS_ARB,&i);

    myShader->glAttachObjectARB(PHandle,FSHandle);
    myShader->glLinkProgramARB(PHandle);

    myShader->glUseProgramObjectARB(PHandle);

#endif


void CPlayWidget::resizeGL(int w, int h)

    if(h == 0)
    
    h = 1;
    
    glViewport(0,0, w,h);


 void CPlayWidget::paintGL()
 
 #ifdef YUY2_test
     int i;
     glClear(0);

     glActiveTexture(GL_TEXTURE1);
     i=myShader->glGetUniformLocationARB(PHandle,"UVtex");
     myShader->glUniform1iARB(i,1);  /* Bind Utex to texture unit 1 -YUY2 working*/
     glBindTexture(GL_TEXTURE_RECTANGLE_NV, 1);
     glEnable(GL_TEXTURE_RECTANGLE_NV);

     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_RGBA8, 1920/2/*(camera->width/2)*/, 1080/*(camera->height)*/,0, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, UVtex); //UV

     glActiveTexture(GL_TEXTURE0);
     i=myShader->glGetUniformLocationARB(PHandle,"Ytex");
     myShader->glUniform1iARB(i,0);  /* Bind Ytex to texture unit 0 -YUY2 Working*/
     glBindTexture(GL_TEXTURE_RECTANGLE_NV, 2);//id_y);
     glEnable(GL_TEXTURE_RECTANGLE_NV);

     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_ALPHA, 1920, 1080, 0, GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE,Ytex); //Y


     glBegin(GL_QUADS);
     glTexCoord2i(0,0);
     glVertex2i(0,0);
     glTexCoord2i(1920,0);
     glVertex2i(1920,0);
     glTexCoord2i(1920,1080);
     glVertex2i(1920,1080);
     glTexCoord2i(0,1080);
     glVertex2i(0,1080);
     glEnd();

     glDrawArrays(GL_QUADS, 0, 4);

#endif
    return;
 

void CPlayWidget::PlayOneFrame(unsigned char *l_ui_arr)



    m_nVideoW = camera->width;
    m_nVideoH = camera->height;
    int nLen;

    switch (g_cs_Index)
    
    case I420:
    case I422:
    case YV12:
     nLen = m_nVideoW*m_nVideoH*3/2;
    break;
    case RGB24:
     nLen = m_nVideoW*m_nVideoH*3;
    break;
    case YUY2:
    case UYVY:
    nLen = m_nVideoW*m_nVideoH*2;
       break;
    case RGB32:
     nLen = m_nVideoW*m_nVideoH*4;
    break;
    default:
     qDebug() << "Unsupported format\n";
    

    if(NULL == m_pBufYuv420p)
    
    m_pBufYuv420p = new unsigned char[nLen];
    Ytex=(GLubyte *)malloc(nLen);
    UVtex = (GLubyte *)malloc(nLen);
    qDebug("CPlayWidget::PlayOneFrame new data memory. Len=%d width=%d height=%d\n",
           nLen, m_nVideoW, m_nVideoH);
    
    m_pBufYuv420p = l_ui_arr;

    Ytex =UVtex = (GLubyte *)m_pBufYuv420p;
    update();
    return;

(动态意味着用户将选择分辨率,可以是 640x480、800x600、1920x1200 等)?

【问题讨论】:

更新:如果我从“ny=1080.0-gl_TexCoord[0].y;\n”更改为“ny=Image_Width-gl_TexCoord[0].y;\n”,那么我就是变黑屏。其中 Image_Width 是包含动态分辨率的参数。 【参考方案1】:

不要对常量进行硬编码。而是在运行时在主机代码中计算它们并通过制服将它们传递给着色器。

【讨论】:

如果我从“ny=1080.0-gl_TexCoord[0].y;\n”更改为“ny=Image_Width-gl_TexCoord[0].y;\n”,那么我会变黑屏幕。其中 Image_Width 是包含动态分辨率的参数。 @ChakravarthiPradeep:你的代码在哪里定义了Image_Width?那里没有那个名字的制服。另外,您为什么首先使用基于像素的纹理坐标?只需使用归一化纹理坐标(即 0 到 1 范围内的数字)并使用 texture 函数而不是 texture2DRect 获取纹理。 Image_Width 是一个包含应用程序值的参数。例如,如果用户选择 1920x1080,那么 Image_Width 将有 1920,Image_Height 将有 1080。抱歉,在我之前的评论中,而不是 Image_Width,它应该是 Image_Height。另外,您为什么首先使用基于像素的纹理坐标?我会尝试,但我不确定。 @ChakravarthiPradeep:您仍然没有回答我的问题:您在哪里以及如何将Image_WidthImage_Height 参数传递给着色器?到目前为止,您没有向我们展示执行此操作的代码。你确实意识到,你必须为此穿制服,对吗? 您在哪里以及如何将 Image_Width 和 Image_Height 参数传递给着色器?我已将着色器从“ny=1080.0-gl_TexCoord[0].y;\n”修改为“ny=Image_Height-gl_TexCoord[0].y;\n”。如果我这样做,那么我将黑屏。

以上是关于如何在片段着色器中将分辨率从静态更改为动态的主要内容,如果未能解决你的问题,请参考以下文章

如何在iphone编程中将位置从临时文件更改为高清

如何在 Pyspark 中将字符串更改为时间戳?

将精灵从灰度着色为彩色

如何在 ggplot 等值线图中将 NA 颜色从灰色更改为白色?

如果几何着色器处于活动状态,如何将信息从顶点着色器传递到片段着色器?

如何在 html5 日期时间选择器中将格式从 12 小时更改为 24 小时?