c# - 从 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);
}
解决方案
我认为你应该在 CPU 端而不是着色器上调整大小......
- 将所有框架调整为共同高度
- 将调整大小的帧宽度相加
- 重新缩放所有帧,使总宽度等于您的窗口/桌面宽度
- 调整窗口高度以匹配 #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 风格中,你需要着色器,所以在它们中只需将纹理从纹理复制到片段......
推荐阅读
- xamarin.forms - 如何在 Xamarin 表单滑动视图中获取偏移属性
- c++ - g++.exe: 安装问题, cannot exec `as': No such file or directory
- ios - Swift - 无法从 UITextField 获取真实文本 - 改为获取 NCISr 结果
- omnet++ - 运行时错误:可能它的代码没有链接,或者类没有注册到 Register_Class()/Define_Module()/Define_Channel()?
- visual-studio - Visual Studio:自动(重新)生成解决方案文件夹
- javascript - 如何拆分字符串中的多个条件?(JavaScript)
- r - 使用 cross 和 .names 进行变异:“胶水无法将函数插入字符串”错误
- java - Vuforia + ArCore 相机模糊
- c - 如何以正确的顺序进行 printf() 打印输出?
- python - 配置:错误:在 Ubuntu 18 中找不到 Python.h