glCopyImageSubData() 的透明度问题?

问题描述 投票:0回答:0

我的代码在 Delphi 中。

我有 1920x1080 的背景图片和 305x3132 的第二张图片。第二张图片由 12 个高度为 261px 的标志创建。两个图像都是 32 位位图并且具有透明度。背景图像没有透明部分。大多数事情都可以正常工作,但我有两个问题。所以这是我的代码。 OpenGL 的所有代码都在单独的单元中,她就是这样。

unit OpenGLProc;

interface

uses
  Winapi.Windows, Vcl.Graphics, OpenGL, Gifimg, Pngimage;

  type
    TTexture = record
      Handle : GLuint;
      Width : integer;
      Height : integer;
    end;

  procedure InitOpenGL(DCin : HDC; FGLContext : HGLRC);
  procedure LoadTexture(image : TBitmap; offsetX, offsetY, texWidth, texHeight : integer; mode : integer; out text : TTexture);
  procedure DrawTexture(texIn : TTexture; width, height, winWidth, winHeight, texOffsetX, texOffsetY, offsetX, offsetY : single; flipped : integer);
  procedure BindFramebufferTex(texIn : TTexture);
  procedure FramebufferTexture2DTex(texIn : TTexture);
  procedure UpdateTexture(inTex : TTexture; offsetXsrc, offsetYsrc, offsetXdst, offsetYdst, width, height : integer; outTex : TTexture);

  type
    TglGenFramebuffers = procedure(n: GLsizei; framebuffers: PGLuint); {$IFDEF MSWINDOWS}stdcall;{$ELSE}cdecl;{$ENDIF}
    TglBindFramebuffer = procedure(target: GLenum; framebuffer: GLuint); {$IFDEF MSWINDOWS}stdcall;{$ELSE}cdecl;{$ENDIF}
    TglFramebufferTexture2D = procedure(target: GLenum; attachment: GLenum; textarget: GLenum; texture: GLuint; level: GLint); {$IFDEF MSWINDOWS}stdcall;{$ELSE}cdecl;{$ENDIF}
    TglCopyImageSubData = procedure(srcName: GLuint; srcTarget: GLenum; srcLevel: GLint; srcX: GLint; srcY: GLint; srcZ: GLint; dstName: GLuint; dstTarget: GLenum; dstLevel: GLint; dstX: GLint; dstY: GLint; dstZ: GLint; width: GLsizei; height: GLsizei; depth: GLsizei); {$IFDEF MSWINDOWS}stdcall;{$ELSE}cdecl;{$ENDIF}

  var
    glGenFramebuffers : TglGenFramebuffers = nil;
    glBindFramebuffer : TglBindFramebuffer = nil;
    glFramebufferTexture2D : TglFramebufferTexture2D = nil;
    glCopyImageSubData : TglCopyImageSubData = nil;

    FGLMainContext : HGLRC;
    screenTex : TTexture;
    screenFB : TTexture;
    bckTex, signsTex : TTexture;

  const
    GL_FRAMEBUFFER = $8D40;
    GL_COLOR_ATTACHMENT0 = $8CE0;


implementation

type
  TRGBA = packed record
    R, G, B, A : Byte;
  end;

  PRGBA = ^TRGBA;

procedure InitOpenGL(DCin : HDC; FGLContext : HGLRC);
var
  pfd : TPixelFormatDescriptor;
  pf : integer;
  glc : HGLRC;
begin
  ZeroMemory(@pfd, SizeOf(TPixelFormatDescriptor));
  pfd.nSize := SizeOf(TPixelFormatDescriptor);
  pfd.nVersion := 1;
  pfd.dwFlags := PFD_DRAW_TO_WINDOW or PFD_SUPPORT_OPENGL or PFD_DOUBLEBUFFER;
  pfd.iPixelType := PFD_TYPE_RGBA;
  pfd.cColorBits := 24;
  pfd.cDepthBits := 32;
  pf := ChoosePixelFormat(DCin, @pfd);
  SetPixelFormat(DCin, pf, @pfd);
  glc := wglCreateContext(DCin);
  wglMakeCurrent(DCin, glc);
  FGLContext := glc;

  // Enable blending
  glEnable(GL_BLEND);

  // Set the blend function to take alpha into account
  glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

  // Enable texturing
  glEnable(GL_TEXTURE_2D);

  // Initialize OpnenGL functions
  glGenFramebuffers := TglGenFramebuffers(wglGetProcAddress('glGenFramebuffers'));
  glBindFramebuffer := TglBindFramebuffer(wglGetProcAddress('glBindFramebuffer'));
  glFramebufferTexture2D := TglFramebufferTexture2D(wglGetProcAddress('glFramebufferTexture2D'));
  glCopyImageSubData := TglCopyImageSubData(wglGetProcAddress('glCopyImageSubData'));
end;

procedure LoadTexture(image : TBitmap; offsetX, offsetY, texWidth, texHeight : integer; mode : integer; out text : TTexture);
var
  PixelData : PByte;
  Pixel : PRGBA;
  x, y : integer;
  row : pRGBQuadArray;
begin
  case mode of
    0: // empty texture will be created
    begin
      try
        // Create and bind the texture object
        glGenTextures(1, @text.Handle);
        glBindTexture(GL_TEXTURE_2D, text.Handle);
        text.Width := texWidth;
        text.Height := texHeight;

        // Set the texture parameters
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);

        // Load the texture data into the texture object
        glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, texWidth, texHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, nil);
      finally
      end;
    end;

    1: // New texture will be created and populated
    begin
      // Allocate memory for the texture data
      GetMem(PixelData, texWidth * texHeight * SizeOf(TRGBA));
      try
        // Copy the bitmap image data into the texture data
        Pixel := PRGBA(PixelData);
        for y := offsetY to texHeight - 1 do
        begin
          row := image.ScanLine[y];
          for x := offsetX to texWidth - 1 do
          begin
            Pixel^.R := row[x].rgbRed;
            Pixel^.G := row[x].rgbGreen;
            Pixel^.B := row[x].rgbBlue;
            Pixel^.A := row[x].rgbReserved;
            Inc(Pixel);
          end;
        end;

        // Create and bind the texture object
        glGenTextures(1, @text.Handle);
        glBindTexture(GL_TEXTURE_2D, text.Handle);
        text.Width := texWidth;
        text.Height := texHeight;

        // Set the texture parameters
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);

        // Load the texture data into the texture object
        glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, texWidth, texHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, PixelData);
      finally
        FreeMem(PixelData);
      end;
    end;
  end;
end;

procedure DrawTexture(texIn : TTexture; width, height, winWidth, winHeight, texOffsetX, texOffsetY, offsetX, offsetY : single; flipped : integer);
begin
  glPushMatrix();
  glTranslatef(-1 + (offsetX / winWidth * 2.0) + (width / winWidth), 1 - (offsetY / WinHeight * 2.0) - (height / winHeight), 0.0);

    // Unbind the screen texture and framebuffer
    glBindTexture(GL_TEXTURE_2D, 0);
    glBindFramebuffer(GL_FRAMEBUFFER, 0);
    glBindTexture(GL_TEXTURE_2D, texIn.Handle);

    glBegin(GL_QUADS);
      glTexCoord2f(texOffsetX / texIn.Width, (texOffsetY + height) / texIn.Height); glVertex2f(-width / winWidth, -height / winHeight);
      glTexCoord2f((texOffsetX + width) / texIn.Width, (texOffsetY + height) / texIn.Height); glVertex2f(width / winWidth, -height / winHeight);
      glTexCoord2f((texOffsetX + width) / texIn.Width, texOffsetY / texIn.Height); glVertex2f(width / winWidth, height / winHeight);
      glTexCoord2f(texOffsetX / texIn.Width, texOffsetY / texIn.Height); glVertex2f(-width / winWidth, height / winHeight);
    glEnd;

    glFlush;

  glPopMatrix();
end;

procedure BindFramebufferTex(texIn : TTexture);
begin
  glBindFramebuffer(GL_FRAMEBUFFER, texIn.Handle);
end;

procedure FramebufferTexture2DTex(texIn : TTexture);
begin
  glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texIn.Handle, 0);
end;

procedure UpdateTexture(inTex : TTexture; offsetXsrc, offsetYsrc, offsetXdst, offsetYdst, width, height : integer; outTex : TTexture);
begin
  glCopyImageSubData(inTex.Handle, GL_TEXTURE_2D, 0,
    offsetXsrc, offsetYsrc, 0,
    outTex.Handle, GL_TEXTURE_2D, 0,
    offsetXdst, offsetYdst, 0,
    width, height, 1);
end;

end.

现在在主要形式中我称这些程序为

unit Unit1;

interface

uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
  Vcl.Controls, Vcl.Forms, Vcl.Dialogs, OpenGLProc, Vcl.StdCtrls;

type
  TForm1 = class(TForm)
    btnClose: TButton;
    btnDrawBck: TButton;
    btnDrawCol: TButton;
    btnDrawColOver: TButton;
    procedure FormCreate(Sender: TObject);
    procedure btnCloseClick(Sender: TObject);
    procedure btnDrawBckClick(Sender: TObject);
    procedure btnDrawColClick(Sender: TObject);
    procedure btnDrawColOverClick(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form1: TForm1;
  background, signs : TBitmap;
  colTex : TTexture;
  DC : HDC;

const
  signHeight = 261;

implementation

{$R *.dfm}

procedure TForm1.btnCloseClick(Sender: TObject);
begin
  Form1.Close;
end;

procedure TForm1.btnDrawBckClick(Sender: TObject);
begin
  UpdateTexture(bckTex, 0, 0, 0, 0, bckTex.Width, bckTex.Height, screenTex);
  DrawTexture(screenTex, screenTex.Width, screenTex.Height, Form1.Width, Form1.Height, 0, 0, 0, 0, 1);
  SwapBuffers(Canvas.Handle);
end;

procedure TForm1.btnDrawColClick(Sender: TObject);
begin
  UpdateTexture(bckTex, 0, 0, 0, 0, bckTex.Width, bckTex.Height, screenTex);
  UpdateTexture(signsTex, 0, 1827, 198, 120, signsTex.Width, 3 * signHeight, screenTex);
  DrawTexture(screenTex, screenTex.Width, screenTex.Height, Form1.Width, Form1.Height, 0, 0, 0, 0, 1);
  SwapBuffers(Canvas.Handle);
end;

procedure TForm1.btnDrawColOverClick(Sender: TObject);
begin
  UpdateTexture(signsTex, 0, 0, 0, 0, 305, signHeight, colTex);
  UpdateTexture(signsTex, 0, 9 * signHeight, 0, signHeight, 305, signHeight, colTex);
  UpdateTexture(signsTex, 0, 8 * signHeight, 0, 2 * signHeight - 8, 305, signHeight, colTex);
  UpdateTexture(colTex, 0, 0, 503, 120, signsTex.Width, 3 * signHeight, screenTex);
  DrawTexture(screenTex, screenTex.Width, screenTex.Height, Form1.Width, Form1.Height, 0, 0, 0, 0, 1);
  SwapBuffers(Canvas.Handle);
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
  background := TBitmap.Create;
  background.LoadFromFile('back1.bmp');
  signs := TBitmap.Create;
  signs.LoadFromFile('znakovi.bmp');

  DC := GetDC(Handle);
  Sleep(200);
  InitOpenGL(DC, FGLMainContext);

  // Create the texture for the framebuffer
  LoadTexture(background, 0, 0, background.Width, background.Height, 0, screenTex);

  // Set up the framebuffer
  if Assigned(glGenFramebuffers) then
  begin
    glGenFramebuffers(1, @screenFB);
  end
  else
  begin
    ShowMessage('glGenFramebuffers is not initialized!');
  end;

  BindFramebufferTex(screenFB);
  FramebufferTexture2DTex(screenTex);

  LoadTexture(background, 0, 0, background.Width, background.Height, 1, bckTex);
  LoadTexture(signs, 0, 0, signs.Width, signs.Height, 1, signsTex);
  LoadTexture(signs, 0, 0, signs.Width, signs.Height, 0, colTex);
end;

end.

所以这是我的问题。

当我只点击按钮 btnDrawCol 时,第二个纹理的透明部分在屏幕上是黑色的。背景纹理没问题,第二个纹理的非透明部分没问题,但为什么透明部分是黑色的????

奇怪的是,当我第一次点击按钮 btnDrawBck(这只会在屏幕上绘制背景)然后点击按钮 btnDrawCol 一切正常。为什么?

第二个更大的问题。我想切割第二个纹理的部分并从中创建第三个纹理。一切都很好(除了上面的问题),直到我尝试重叠部分。例如,我切割了三个部分,第三部分与第二部分重叠 8 px 第二部分的最后 8 px 完全透支,即使第三部分中的线条是透明的。

我张贴一张图片作为例子。左侧是重叠的。我只需要上面的非透明部分透支内容(黄色框架应该接触)。

delphi winapi opengl transparency
© www.soinside.com 2019 - 2024. All rights reserved.