delphi glCopyImageSubData()的透明度问题?[关闭]

mfuanj7w  于 2023-05-12  发布在  其他
关注(0)|答案(1)|浏览(160)

**关闭。**此题需要debugging details。目前不接受答复。

编辑问题以包含desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem。这将帮助其他人回答这个问题。
昨天关门了。
Improve this question
我有一个大小为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,一切正常。为什么?
第二个更大的问题。我想削减部分第二纹理和创造第三纹理从他们。一切都很好(除了上面的问题),直到我尝试重叠部分。例如,我剪了三个部分,第三部分是重叠的,第二部分的最后8px是完全透支的,即使第三部分的线条是透明的。
我贴了一张图片作为例子。左侧为重叠。我需要的只是非透明部分,上面的内容(黄色框架应在触摸)。

这里是黑色区域和透明的图像。

这也是我尝试创作的一些作品。它们太大了,所以我必须将位图转换为PNG(并更改加载图像的代码部分)。

下面是“FormCreate”过程中更改的部分代码。

{background := TBitmap.Create;
  background.LoadFromFile('back1-test.bmp');
  signs := TBitmap.Create;
  signs.LoadFromFile('znakovi-test.bmp');}
  png := TPngImage.Create;
  png.LoadFromFile('back1.png');
  background := TBitmap.Create;
  background.PixelFormat := pf32bit;
  background.SetSize(png.Width, png.Height);
  background.Canvas.Brush.Color := RGB(0, 0, 0);
  background.Canvas.FillRect(background.Canvas.ClipRect);
  png.Draw(background.Canvas, background.Canvas.ClipRect);
  png.Free;
  png := TPngImage.Create;
  png.LoadFromFile('znakovi.png');
  signs := TBitmap.Create;
  signs.PixelFormat := pf32bit;
  signs.SetSize(png.Width, png.Height);
  signs.Canvas.Brush.Color := RGB(0, 0, 0);
  signs.Canvas.FillRect(signs.Canvas.ClipRect);
  png.Draw(signs.Canvas, signs.Canvas.ClipRect);
  png.Free;
qacovj5a

qacovj5a1#

glCopyImageSubData执行原始数据复制,但不混合图像。此函数不关心Alpha通道。这是错误的功能为您的任务。您需要使用着色器程序绘制图像并启用混合。

相关问题