使用帧缓冲与Scene2D

huangapple go评论57阅读模式
英文:

Using frame buffers with Scene2D

问题

我一直在使用自定义的Scene2D演员,并且在其绘制方法中使用了FrameBuffer时遇到了一些问题。最初的想法是使用一个着色器在FrameBuffer上绘制,然后使用另一个着色器将FrameBuffer的内容绘制到屏幕上,但这将需要等待。我现在面临的问题是如何使FrameBuffer的内容正确填充我期望的Actor在屏幕上占据的空间。经过许多实验,我得出了一些看起来有效的方法,但我仍然不明白为什么它有效。

这是绘制方法的代码:

@Override
public void draw(Batch batch, float parentAlpha) {
    
    batch.end();
    buffer.begin();
    ScreenUtils.clear(1, 0, 0, 1);
    batch.begin();
    batch.draw(texture, 0, 0, 640, 640); // 这是窗口大小!
    batch.end();
    buffer.end();
    batch.begin();
    batch.draw(buffer.getColorBufferTexture(),
               getX(),
               getY(),
               getWidth(),
               getHeight(),
               0,
               0,
               buffer.getColorBufferTexture().getWidth(),
               buffer.getColorBufferTexture().getHeight(),
               false,
               true);
}

我了解FrameBuffer使用像素坐标而不是Scene2D用于Actor位置和大小的“世界”坐标。但我不明白的是,为什么如果我将纹理绘制到FrameBuffer时,尺寸小于实际窗口大小,那么来自FrameBuffer的颜色缓冲纹理会以小于屏幕上Actor大小的方式呈现。

我想要的答案如下:

(1) FrameBuffer应该是什么尺寸?

我最初的想法是它应该与我打算绘制到其中的纹理的尺寸相同。

(2) 当我绘制到FrameBuffer时,是否应该使用不同的投影矩阵?

我最佳的猜测是,当我绘制到FrameBuffer时,应该更改SpriteBatch的投影矩阵,以考虑FrameBuffer与应用程序窗口的大小不同。不幸的是,我还没有能够在网上找到有用的示例或教程。

英文:

I've been having some trouble with a custom Scene2D actor whose draw method uses a FrameBuffer. The original idea was to draw to the FrameBuffer with one shader and then draw the contents of the FrameBuffer to the screen with another, but that will have to wait. The problem I have right now is to get the contents of the FrameBuffer to properly fill the space I expected the Actor to take up on the screen. After much experimentation, I have arrived at something that appears to work, but I still don't understand why it works.

Here's the draw method:

@Override
public void draw(Batch batch, float parentAlpha) {
	
	batch.end();
	buffer.begin();
	ScreenUtils.clear(1,0,0,1);
	batch.begin();
	batch.draw(texture,0,0,640,640); // This is the window size!
	batch.end();
	buffer.end();
	batch.begin();
	batch.draw(buffer.getColorBufferTexture(),
	           getX(),
	           getY(),
	           getWidth(),
			   getHeight(),
			   0,
			   0,
			   buffer.getColorBufferTexture().getWidth(),
			   buffer.getColorBufferTexture().getHeight(),
			   false,
			   true);

}

I understand that the FrameBuffer uses pixel coordinates rather than the "world" coordinates that Scene2D uses for Actor's position and size. What I don't understand is why, if render a texture to the FrameBuffer at anything less than the actual window size, the color buffer texture from the FrameBuffer gets rendered at less than the Actor's size on the screen.

I guess what I'm looking for are answers to the following questions.

(1) What size should the FrameBuffer be?

My initial thought was that it should be the size of the texture I intend to draw to it.

(2) When I draw to the FrameBuffer should I be using a different projection matrix?

My best guess for a proper solution is that when I'm drawing to the FrameBuffer I should change the SpriteBatch's projection matrix to account for the fact that the FrameBuffer isn't the same size as the application window. Unfortunately, I haven't been able to find a useful example or tutorial online.

答案1

得分: 0

由于您正在使用与舞台相同的SpriteBatch,因此您需要交换其投影矩阵来执行此操作。

另外,如果您的舞台使用了一个会在场景上添加黑边的视口,比如FitViewport或者ExtendViewport上设置了一些最大比例的视口,那么您还需要交换视口,但我现在会忽略这一点。

如果您要绘制一个填充整个帧缓冲区尺寸的纹理,那么事情就简单了。然后,您可以使用一个单位矩阵,并将纹理绘制到围绕世界原点的2x2正方形中。这是单位投影的定义视图(不仅仅是魔术数字)。它会被适当地拉伸。

我的libGDX知识有点生疏,但应该类似这样:

private final Matrix4 tempStageMatrixCopy = new Matrix4();

@Override
public void draw(Batch batch, float parentAlpha) {
    
    batch.end();
    tempStageMatrixCopy.set(batch.getProjectionMatrix()); // 存储舞台的矩阵值

    buffer.begin();
    ScreenUtils.clear(1,0,0,1);

    batch.getProjectionMatrix().idt(); // 将批次的投影设置为单位矩阵
    batch.begin();
    batch.draw(texture, -1f, 1f, 2f, -2f); // 如果这与您想要的垂直翻转不同,请使用 -1f, -1f, 2f, 2f
    batch.end();
    buffer.end();

    batch.setProjectionMatrix(tempStageMatrixCopy); // 恢复舞台的矩阵
    batch.begin();
    batch.draw(buffer.getColorBufferTexture(),
               getX(),
               getY(),
               getWidth(),
               getHeight(),
               0,
               0,
               buffer.getColorBufferTexture().getWidth(),
               buffer.getColorBufferTexture().getHeight(),
               false,
               true);

}

正如上面所提到的,这假定了texture具有与帧缓冲区匹配的纵横比,纹理和帧缓冲区的尺寸都适合于拉伸到填充缓冲区的纹理。如果您正在进行更复杂的操作,您可能需要创建一个相机,仅用于此帧缓冲区,然后相对于相机绘制物体,并在精灵批次中使用相机的矩阵。

英文:

Since you're using the same SpriteBatch as the Stage, you need to swap its projection matrix to do this.

Also, if your Stage uses a Viewport that letterboxes the scene, such as FitViewport or an ExtendViewport that has some maximum ratio set on it, then you will also have to swap the viewport, but I will ignore that for now.

If you are drawing a texture to the frame buffer that fills the entire frame buffer dimensions, that simplifies things. Then you can use an identity matrix and draw the texture to fit the 2x2 square around the world origin. This is the defined view of identity projection (not just magic numbers). It will be stretched appropriately.

My libGDX is rusty, but it should look something like this:

private final Matrix4 tempStageMatrixCopy = new Matrix4();

@Override
public void draw(Batch batch, float parentAlpha) {
    
    batch.end();
    tempStageMatrixCopy.set(batch.getProjectionMatrix()); // store stage's matrix value

    buffer.begin();
    ScreenUtils.clear(1,0,0,1);

    batch.getProjectionMatrix().idt(); // set the batch's projection to identity
    batch.begin();
    batch.draw(texture, -1f, 1f, 2f, -2f); // If this is vertically flipped from what you want
                                           // use -1f, -1f, 2f, 2f
    batch.end();
    buffer.end();

    batch.setProjectionMatrix(tempStageMatrixCopy); // restore stage's matrix
    batch.begin();
    batch.draw(buffer.getColorBufferTexture(),
               getX(),
               getY(),
               getWidth(),
               getHeight(),
               0,
               0,
               buffer.getColorBufferTexture().getWidth(),
               buffer.getColorBufferTexture().getHeight(),
               false,
               true);

}

As mentioned above, this is assuming whatever texture is, it has the aspect ratio to match the FrameBuffer, and both the texture and frame buffer have dimensions that are appropriate for the texture to stretch to fill the buffer. If you are doing something more complicated, you probably need to create a Camera to use with just this FrameBuffer, and then draw things relative to the camera and use the camera's matrix in the sprite batch.

huangapple
  • 本文由 发表于 2023年7月28日 04:48:24
  • 转载请务必保留本文链接:https://go.coder-hub.com/76783324.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定