首页 > 解决方案 > 从 OpenGL 控件中删除纹理以外的区域 - c# opentk

问题描述

使用下面的着色器代码,我可以将来自三个摄像机的帧显示到单个 OpenGL 控件。此 opengl 控件的起始位置应从屏幕中心开始,并且应从左端开始到全屏宽度。也就是说控件的宽度是屏幕宽度,高度是屏幕高度的一半。但问题是除了纹理之外还有其他区域,它显示为 ClearColor(设置为蓝色)。

在此处输入图像描述

如果 (uv.y > 1.0) 丢弃;

我可以从 GLControl 中删除/删除这个额外的区域吗?

   int y = Screen.PrimaryScreen.Bounds.Height - this.PreferredSize.Height;
        glControl1.Location = new Point(0, y/2);
    private void OpenGL_SizeChanged(object sender, EventArgs e)
    {
        glControl1.Width = this.Width;
        glControl1.Height = this.Height/2;
    }

 GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMinFilter, (int)TextureMinFilter.Nearest);
 GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMagFilter, (int)TextureMagFilter.Linear);
 GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapS, (int)TextureWrapMode.ClampToBorder);
 GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapT, (int)TextureWrapMode.ClampToBorder);

  private void CreateShaders()
    {
        /***********Vert Shader********************/
        vertShader = GL.CreateShader(ShaderType.VertexShader);
        GL.ShaderSource(vertShader, @"attribute vec3 a_position;
                                varying vec2 vTexCoordIn; 
                         //uniform float aspect;   
     void main() {
       vTexCoordIn=( a_position.xy+1)/2;
      gl_Position = vec4(a_position,1);
      }");
        GL.CompileShader(vertShader);

        /***********Frag Shader ****************/
        fragShader = GL.CreateShader(ShaderType.FragmentShader);
        GL.ShaderSource(fragShader, @"
uniform sampler2D sTexture;
uniform sampler2D sTexture1;
uniform sampler2D sTexture2; 

uniform vec2 sTexSize;
uniform vec2 sTexSize1;
uniform vec2 sTexSize2;
varying vec2 vTexCoordIn;
void main ()
{                                               
vec2 vTexCoord=vec2(vTexCoordIn.x,vTexCoordIn.y);
if ( vTexCoord.x < 1.0/3.0 )
{
    vec2 uv = vec2(vTexCoord.x * 3.0, vTexCoord.y);
    uv.y *= sTexSize.x / sTexSize.y;
    if (uv.y > 1.0)
    discard;  
    else
    gl_FragColor = texture2D(sTexture, uv);
}
else if ( vTexCoord.x >= 1.0/3.0 && vTexCoord.x < 2.0/3.0 )
{  
 vec2 uv = vec2(vTexCoord.x * 3.0 - 1.0, vTexCoord.y);
 uv.y *= sTexSize1.x / sTexSize1.y;
 if (uv.y > 1.0)
 discard;  
 else
 gl_FragColor = texture2D(sTexture1, uv);
}
else if ( vTexCoord.x >= 2.0/3.0 )
{
  vec2 uv = vec2(vTexCoord.x * 3.0 - 2.0, vTexCoord.y);
  uv.y *= sTexSize2.x / sTexSize2.y;
  if (uv.y > 1.0)
  discard;
  else
  gl_FragColor = texture2D(sTexture2, uv);
 }
   }");
  GL.CompileShader(fragShader);
    }

标签: c#winformsopenglfragment-shaderopentk

解决方案


我认为你应该在 CPU 端而不是着色器上调整大小......

  1. 将所有框架调整为共同高度
  2. 将调整大小的帧宽度相加
  3. 重新缩放所有帧,使总宽度等于您的窗口/桌面宽度
  4. 调整窗口高度以匹配 #3 之后的新公共高度

看起来您正在着色器中执行#1、#2、#3,而忽略#4会导致该空白区域。在不破坏相机图像的纵横比的情况下,您无法同时匹配窗口的 x 和 y 大小。因此,保留 x 大小并更改窗口的 y 大小以解决您的问题。

这里是小的VCL/C++/legacy GL示例(对不起,我没有用C#编写代码并且懒得为此编写新的东西):

//---------------------------------------------------------------------------
#include <vcl.h>
#include <gl\gl.h>
#pragma hdrstop
#include "Unit1.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TForm1  *Form1;                 // VCL Application window object
int     xs,ys;                  // window resolution
HDC     hdc=NULL;               // device context for GL
HGLRC   hrc=NULL;               // rendering context for GL
//---------------------------------------------------------------------------
const int camera_res[]= // (x,y) resolutions of each camera
    {
    320,200,
    640,480,
    352,288,
    0,0
    };
float frame_pos[128];   // (x0,x1) position of each frame
void frame_resize(int xs,int &ys)   // position/resize frames and change ys to common height so xs fit without breaking aspect ratio
    {
    int i,j;
    float dx,dy,x,y;
    // comon height placemet
    for (x=0.0,i=0,j=0;camera_res[i];)
        {
        dx=camera_res[i]; i++;
        dy=camera_res[i]; i++;
        dx*=1000.0/dy;          // any non zero common height for example 1000
        frame_pos[j]=x; x+=dx; j++;
        frame_pos[j]=x-1.0;    j++;
        }
    frame_pos[j]=-1.0; j++;
    frame_pos[j]=-1.0; j++;
    // rescale summed width x to match xs
    x=float(xs)/x;              // scale
    ys=float(1000.0*x);         // common height
    for (j=0;frame_pos[j]>-0.1;)
        {
        frame_pos[j]*=x; j++;
        frame_pos[j]*=x; j++;
        }
    }
//---------------------------------------------------------------------------
void gl_draw()
    {
    if (hrc==NULL) return;

    glClearColor(0.0,0.0,0.0,0.0);
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    glDisable(GL_DEPTH_TEST);
    glDisable(GL_CULL_FACE);

    // view in pixel units
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    glTranslatef(-1.0,+1.0,0.0);
    glScalef(2.0/float(xs),-2.0/float(ys),1.0);
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();

    // render rectangle
    int i; float x0,y0,x1,y1;
    y0=0.0; y1=ys-1;
    glColor3f(1.0,1.0,1.0);
    for (i=0;frame_pos[i]>-0.1;)
        {
        x0=frame_pos[i]; i++;
        x1=frame_pos[i]; i++;
        // here bind (i/2) camera frame as texture (only one texture at a time)
        glBegin(GL_LINE_LOOP);
        glTexCoord2f(0.0,0.0); glVertex2f(x0,y0);
        glTexCoord2f(0.0,1.0); glVertex2f(x0,y1);
        glTexCoord2f(1.0,1.0); glVertex2f(x1,y1);
        glTexCoord2f(1.0,0.0); glVertex2f(x1,y0);
        glEnd();
        }

    glFlush();
    SwapBuffers(hdc);
    }
//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner):TForm(Owner)
    {
    // desktop      You can hardcode xs,ys instead
    TCanvas *scr=new TCanvas();
    scr->Handle=GetDC(NULL);
    xs=scr->ClipRect.Width();               // desktop width
    ys=scr->ClipRect.Height();              // desktop height
    delete scr;
    // window       This is important
    int ys0=ys;                             // remember original height
    frame_resize(xs,ys);                    // compute sizes and placements
    SetBounds(0,(ys0-ys)>>1,xs,ys);         // resize window and place in the center of screen

    // GL init      most likely you can ignore this you already got GL
    hdc = GetDC(Handle);                    // get device context for this App window
    PIXELFORMATDESCRIPTOR pfd;
    ZeroMemory( &pfd, sizeof( pfd ) );      // set the pixel format for the DC
    pfd.nSize = sizeof( pfd );
    pfd.nVersion = 1;
    pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER;
    pfd.iPixelType = PFD_TYPE_RGBA;
    pfd.cColorBits = 24;
    pfd.cDepthBits = 24;
    pfd.iLayerType = PFD_MAIN_PLANE;
    SetPixelFormat(hdc,ChoosePixelFormat(hdc, &pfd),&pfd);
    hrc = wglCreateContext(hdc);            // create current rendering context
    if(hrc == NULL)
        {
        ShowMessage("Could not initialize OpenGL Rendering context !!!");
        Application->Terminate();
        }
    if(wglMakeCurrent(hdc, hrc) == false)
        {
        ShowMessage("Could not make current OpenGL Rendering context !!!");
        wglDeleteContext(hrc);          // destroy rendering context
        Application->Terminate();
        }
    // resize GL framebufers            this is important
    glViewport(0,0,xs,ys);
    }
//---------------------------------------------------------------------------
void __fastcall TForm1::FormDestroy(TObject *Sender)
    {
    // GL exit          most likely you can ignore this
    wglMakeCurrent(NULL, NULL);     // release current rendering context
    wglDeleteContext(hrc);          // destroy rendering context
    }
//---------------------------------------------------------------------------
void __fastcall TForm1::FormPaint(TObject *Sender)
    {
    gl_draw();
    }
//---------------------------------------------------------------------------
void __fastcall TForm1::FormKeyDown(TObject *Sender, WORD &Key,TShiftState Shift)
    {
    if (Key==27) Close();   // Escape exits app
    }
//---------------------------------------------------------------------------

忽略VCL的东西,这里唯一重要的是frame_resize功能及其用途。只是渲染矩形而gl_draw不是您的框架,因此只需绑定纹理并使用GL_QUAD而不是GL_LINE_LOOP. 或者将它移植到新的 GL 东西,所以 VBO/VAO ...

我对其进行了编码,因此它支持 0 以上的任意数量的摄像头......只要确保frame_pos数组足够大(每个摄像头 2 个条目)。

如您所见,不需要着色器。在新的 GL 风格中,你需要着色器,所以在它们中只需将纹理从纹理复制到片段......


推荐阅读