您如何将不同尺寸的图像与一个图像的大小相结合,而尺寸为2?

发布于 2025-01-24 22:04:03 字数 468 浏览 6 评论 0原文

某些上下文

我正在从事体素游戏(例如Minecraft)的 。我无法使用预建的纹理地图集,因为我需要允许玩家在游戏中添加自定义块。这就是为什么我必须根据所提供的纹理在运行时创建纹理地图集的原因。这些纹理的尺寸不一定(一个可以是16 x 16,而另一个可以是64 x 64),所以我不能只在常规距离上粘贴图像。

实际问题

我如何结合多个图像,这些图像可以将不同的大小分解为一个,而我可以尽可能多地填充图像,以及图像应尽可能密集地包装,并且如果可以将图像放在最终图像上的较小位置应该放置在那里,以免使用其他图像可能使用的空间。 最终图像必须是一个正方形,其大小必须是2的最小功率。例如,如果有4 x 16张图像,则只能创建一个32 x 32映像,足以包含这些图像。但是说有5张图像,它应该创建一个64 x 64张图像,因为它的最小尺寸可以包含这些图像。 我还需要可以将其映射到区块的纹理的UV值。

游戏引擎我使用的

是我使用Godot游戏引擎。

Some context

I am working on a voxel game (like minecraft). I can not use a prebuilt texture atlas as I need to allow players to add custom blocks to the game. That's why I must create texture atlases at the runtime based on the textures provided. These textures need not be same in size (one can be 16 by 16 while other can be 64 by 64) so I can't just paste the images at a regular distance.

Actual question

How can I combine multiple images which can be different sizes into one while cramming as much images I can, i.e., images should be as densely packed as possible and if an image can be placed at a smaller place on the final image, it should be placed there as to not use the space that may be used by other images.
The final image must be a square and its size must be the smallest power of 2. For example if there are 4 16 by 16 images, only a 32 by 32 image should be created as its enough to contain those images. But say that there were 5 images, it should create a 64 by 64 image as its the smallest size that can contain those images.
I would also need the UV values of the textures that I can map to blockfaces.

Game engine I use

I use godot game engine.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

私野 2025-01-31 22:04:03

输入

让我们说您有一系列image要放入纹理地图集。我们说这是一个数组:

var images:Array

该数组的值可以是:

  • 将图像文件导入为image
  • get_data on 纹理>纹理 s获取。
  • 图像在运行时通过其他方式创建的。

现在编译尺寸

,我们可以得到它们的尺寸。我们将在poolvector2array中需要它们(我们实际上可以在常规array中获取它们并进行转换,但是没有必要执行此操作):

var sizes:PoolVector2Array
for image in images:
    sizes.append(image.get_size())

计算Atlas

一旦有尺寸,我们就可以调用geome.make_atlas

var atlas_data := Geometry.make_atlas(sizes)

geemoge.make_atlas的算法将尝试制作Atlas Square。

我们应该查询我们得到的大小:

var min_atlas_size:Vector2 = atlas_data.size

可悲的是,戈多不会暴露“ 2”功能的“下一个力量”。在上下文的情况下,我相信一个简单的循环在这种情况下会做得很好:

var atlas_size := 16
while min_atlas_size.x > atlas_size or min_atlas_size.y > atlas_size:
    atlas_size *= 2

构建Atlas

创建一个Atlas image

现在我们已经确定了大小,我们可以创建一个新的图像用于地图集:

var atlas := Image.new() 
atlas.create(atlas_size, atlas_size, true, Image.FORMAT_RGBA8)

您可能会怀疑前两个参数是widthheight。第三个参数是您是否要生成MIPMAP。最后一个是像素格式,我在这里选择的格式有四个通道(红色,绿色,蓝色,alpha),分别为8位(颜色深度)。


将输入图像 s复制到地图集图像

现在将原始图像复制到地图集。我们在从make_atlas中获得的结果获得每个位置:

var points:PoolVector2Array = atlas_data.points
for index in images.size():
    var image:Image = images[index]
    var point:Vector2 = points[index]
    var size:Vector2 = image.get_size()
    atlas.blit_rect(image, Rect2(Vector2.ZERO, size), point)

这是rect2image> image我们要绘制的区域(所有)。

注意根据要绘制的image的格式,您可能必须先转换它:

source.convert(Image.FORMAT_RGBA8)

而且,通常,图像以压缩格式导入,无法为直接转换,因此您必须首先解压缩:

source.decompress()
source.convert(Image.FORMAT_RGBA8)

如果BLIT_RECT行给您问题,请尝试一下。


UV坐标

顺便说一句,您说要紫外线坐标,我们应该从相同的循环中获取它们:

var points:PoolVector2Array = atlas_data.points
var uv_scale := 1.0/atlas_size
var uv_rects := []
for index in images.size():
    var image:Image = images[index]
    var point:Vector2 = points[index]
    var size:Vector2 = image.get_size()
    atlas.blit_rect(image, Rect2(Vector2.ZERO, size), point)
    uv_rects.append(Rect2(point * uv_scale, size * uv_scale))

转换为纹理

并且由于您想要紫外线坐标,我认为这是对于某些着色器,将成为纹理。因此,让我们做一个纹理

var texture_atlas := ImageTexture.new()
texture_atlas.create_from_image(atlas)

然后您应该能够将其设置在需要的地方。我把它留给你。

Inputs

Let us say you have a series of Images you want to put into your texture atlas. Let us say it is an array:

var images:Array

And the values of that array can be either:

  • Image files imported as Image.
  • Got from calling get_data on Textures.
  • Images created at runtime by other means.

Compiling the sizes

Now, we can get their sizes. We are going to need them in a PoolVector2Array (we can actually get them in a regular Array and convert it, but there is no need to do that):

var sizes:PoolVector2Array
for image in images:
    sizes.append(image.get_size())

Computing the atlas

Once we have the sizes, we can call Geometry.make_atlas:

var atlas_data := Geometry.make_atlas(sizes)

The algorithm of Geometry.make_atlas will try to make the atlas square.

We should query what size we got:

var min_atlas_size:Vector2 = atlas_data.size

Sadly Godot does not expose a "next power of 2" function. Given the context, I believe a simple loop will do well on this case:

var atlas_size := 16
while min_atlas_size.x > atlas_size or min_atlas_size.y > atlas_size:
    atlas_size *= 2

Building the atlas

Create an atlas Image

Now that we have decided the size, we can create a new Image for the atlas:

var atlas := Image.new() 
atlas.create(atlas_size, atlas_size, true, Image.FORMAT_RGBA8)

As you might suspect the first two parameters are width and height. The third parameter is whether or not you want to generate mipmaps. And the last is the pixel format, the one I'm picking here has four channels (Red, Green, Blue, Alpha) of 8 bits (color depth) each.


Copy the input Images to the atlas Image

Now copy your original images to the atlas. We get the position for each one on the result we got from make_atlas:

var points:PoolVector2Array = atlas_data.points
for index in images.size():
    var image:Image = images[index]
    var point:Vector2 = points[index]
    var size:Vector2 = image.get_size()
    atlas.blit_rect(image, Rect2(Vector2.ZERO, size), point)

Here the Rect2 is the area of the Image we want to draw (all of it).

Note depending on the format of the Image you want to draw, you may have to convert it first:

source.convert(Image.FORMAT_RGBA8)

Also, usually, the images are imported in a compressed format that cannot be converted directly, and thus you would have to decompress first:

source.decompress()
source.convert(Image.FORMAT_RGBA8)

If the blit_rect line is giving you problems, try that.


UV Coordinates

By the way, you say you want UV coordinates, we should get them from the same loop:

var points:PoolVector2Array = atlas_data.points
var uv_scale := 1.0/atlas_size
var uv_rects := []
for index in images.size():
    var image:Image = images[index]
    var point:Vector2 = points[index]
    var size:Vector2 = image.get_size()
    atlas.blit_rect(image, Rect2(Vector2.ZERO, size), point)
    uv_rects.append(Rect2(point * uv_scale, size * uv_scale))

Converting to Texture

And since you want UV coordinates, I presume this is going to be a Texture for some shader. So, let us make a Texture:

var texture_atlas := ImageTexture.new()
texture_atlas.create_from_image(atlas)

Then you should be able to set it where you need it. I leave that to you.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文