1

Using below shader code I can display frames from three cameras to a single openGL control. The starting location of this opengl control should be from center of screen and should start from left end to full screen width. That is width of control is screen width and height is half of screen height. But the problem is there is area other than textures and it appears as ClearColor (which is set as blue color).

enter image description here

if (uv.y > 1.0) discard;

Can I remove/delete this extra area from 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);
    }
nsds
  • 961
  • 4
  • 13
  • 39
  • 1
    too lazy to analyze your code (especially when I do not code in C#) but what you are describing is not job for a shader. For multiple camera views in a single frame You should use `glViewport` see [How to show visible part of planar world rendered with 3D perspective on topside 2D minimap?](https://stackoverflow.com/a/52475105/2521214). Anyway you should show us some screenshot showing your issue so we do not have to guess what you are dealing with. – Spektre May 21 '19 at 07:51
  • @Spektre please see screenshot added – nsds May 21 '19 at 08:07
  • 1
    So you have rescaled 3 images to common height and their width sum is equal to desktop width. And the empty area is just difference between your window height and the common height of images computed. So either resize your window or rescale your frames to its height (but the latter would break aspect ratio). As the frames are already images no need for glViewport ... That would be the case for rendered frames with different cameras not frames from physical camera :) – Spektre May 21 '19 at 09:09
  • each camera may have different resolutions. Now resolution of all textures are set as resolution of camera 2. – nsds May 21 '19 at 11:47

1 Answers1

1

I think you should do the resizing on the CPU side instead of shaders ...

  1. resize all frames to common height
  2. sum the resized frames widths
  3. rescale all frames so the summed width is equal to your window/desktop width
  4. resize window height to match new common height after #3

Looks like you are doing #1,#2,#3 inside your shaders bud ignoring #4 resulting in that empty area. You can not match both x and y size of window without breaking aspect ratio of the camera images. So leave x size and change the y size of the window to remedy your problem.

Here small VCL/C++/legacy GL example (sorry I do not code in C# and too lazy to code the new stuff for this):

//---------------------------------------------------------------------------
#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
    }
//---------------------------------------------------------------------------

Ignore the VCL stuff the only important thing here is the frame_resize function and its use. The gl_draw just renders rectangles instead of your frames so to remedy just bind texture and use GL_QUAD instead of GL_LINE_LOOP. Or port it to the new GL stuff so VBO/VAO ...

I encoded it so it support any number of cameras above 0 ... just be sure the frame_pos array is big enough (2 entries per camera).

As you can see no shaders are need. Of coarse in the new GL style you need shaders so in them just copy texel from texture to fragment ...

Spektre
  • 49,595
  • 11
  • 110
  • 380