围绕精灵绘制轮廓的有效方法


21

我正在使用XNA对游戏进行编程,并且一直在尝试各种方法来对我的精灵实现“选定”效果。我遇到的麻烦是,在spritebatch中绘制的每个可单击对象均使用多个sprite绘制(每个对象最多可以由6个sprite组成)。

如果有人可以建议我如何为X像素的精灵添加轮廓,我将不胜感激(因此轮廓宽度可以是整个像素的各种数量)。

提前致谢,

  • 格雷格

Answers:


20

到目前为止,最简单的方法(最好是最好的方法,除非您真的为性能而苦恼)是拥有两个Sprite。

  • 普通版
  • “胖”的无色版本-基本上是精灵X的白色版本,比原始像素多很多。

使用“胖”版本绘制整个对象,然后在顶部绘制常规版本。

通过将“胖”版本设为白色,可以使用SpriteBatch的内置颜色着色来动态更改选择颜色。

为了生成您的“胖子”版本,我建议编写一个内容管道扩展程序,该扩展程序可以自动获取原始精灵,读取其Alpha通道,通过对原始图像中的最大Alpha通道进行采样(每个像素周围X个像素)来创建新的Alpha通道,并设置RGB =(1,1,1)。

您必须确保所有精灵都具有足够的透明边框以添加轮廓(您可以在内容处理器中进行检查-必要时甚至腾出空间)。

如果只有几个精灵,则可以使用一个好的图像编辑器(GIMP,Photoshop)并手动完成:将Alpha通道选区,扩展选区,将选区设置为Alpha,将颜色通道填充为白色。


4

我猜您需要先绘制每个对象到单个精灵的所有片段。然后,我认为您必须编写一个着色器以检测精灵的边缘,并在找到边缘的位置绘制一个像素。我希望已经有一些着色器可以执行此操作,您可以使用也可以移植。


11
我听说,这种着色器令人惊讶地令人讨厌(我们在一款3D游戏中使用了它,并且不断遇到难看的边缘情况)。您可能要考虑的一件事是将轮廓直接编码为具有特定颜色(如(0,255,255,0))的sprite纹理,并在选择了sprite时使着色器将其颜色转换。然后,着色器将变成很小的颜色变化,并且您可以对轮廓和所需的任何细节进行高级的艺术家控制。

4

根据要求,可能仅对子画面按需创建轮廓也可能有效。我假设您的精灵具有透明性,并且形状不规则,而不仅仅是矩形(虽然这样做会很好,但轮廓矩形应该是平凡的)。

when selected:
   outline = new sprite canvas of appropriate size
   for sprite in object:
      # use larger numbers for thicker outlines
      for x in (-1, 0, 1) and y in (-1, 0, 1):
         render sprite mask into canvas at x,y with desired color

请注意,您不需要每次绘制都执行此操作(尽管我想可以这样做),而只是在切换精灵时创建新的轮廓精灵。


是的,这也是我想建议的。在现有子画面下,向原始子画面的左,右,顶部和底部渲染1个像素的蒙版子画面。许多游戏使用此方法来概述渲染文本的轮廓,或者仅使用4个位置中的2个创建阴影。
Kaj 2010年

1

最简单的暴力方法是为每个精灵创建两个副本,一个是普通副本,另一个是突出显示的副本。然后在突出显示时交换它们。

如果您有足够的存储空间,则无需变得更加复杂。加上突出显示的艺术家,您可以完全控制外观,因此您可以绘制轮廓或其他任何想要的东西。


我认为部分问题是OP指出每个对象都可以由多个精灵组成。因此,我想轮廓必须是组合对象的轮廓,而不是在每个组件精灵周围都有单独的轮廓。
克里斯·豪

1
克里斯(Chris),它不必是组合对象的轮廓,它对于由多个子图形组成的对象也可以正常工作。只需按照wkerslake所说的去做即可,但请确保在该对象的所有普通精灵之后绘制突出显示的精灵。这样,无论对象由多少个精灵组成,高光将仅使用该对象两倍的绘制时间,这比使用合并的精灵在渲染时生成轮廓要少得多。
AttackingHobo 2010年

1

每个精灵还有另一个精灵,它是基本精灵的轮廓。绘制轮廓对象时,请绘制基本精灵,然后对组合渲染进行遮罩,然后绘制不包括遮罩的轮廓精灵。


2
为什么不先绘制轮廓精灵并在其上方绘制常规精灵呢?
克里斯·豪

不这样做的一个原因(或克里斯的建议)是因为它使用了两倍的纹理内存。另一个原因是艺术家工作流程很糟糕,因为每次更改精灵时都需要更新两个文件。

2
是的,理想情况下,您不会有两个实际的Sprite资产。如果您对精灵使用alpha测试,则可以将轮廓放入精灵中,并将其alpha设置为比透明区域略高。然后,通过控制Alpha测试参考值,您可以控制轮廓是否可见。我要说的是,如果您有2个版本的精灵(无论是2个资产还是同一资产的2个状态),则应先绘制轮廓版本,然后再绘制普通版本。这样,您就不需要任何花哨的着色器,蒙版或其他任何东西。
克里斯·豪

1
克里斯的想法很有价值。此外,如果您生成工具来为作为资产/内容管道一部分运行的轮廓精灵生成Alpha,则可以避免使用美工师更新2个文件(甚至相同的资产)。纹理内存可能是问题,也可能不是问题,但是单独的轮廓精灵应具有很高的DXT可压缩性。可能是视频存储器中原始纹理大小的1/6,并且没有保真度损失。
jpaver

1

几种具有不同权衡取舍的解决方案。

最简单:使用平面颜色多次渲染对象并抖动位置(向左,向上,向下,向右等偏移),这将为您在其上渲染的任何内容创建轮廓版本,但会降低性能,并且不会允许边框很胖,而没有很多额外的渲染。一个或两个像素边框可以使用4倍分辨率。

最快:对纹理进行预处理,并具有已经加边框的副本,或者仅仅是边框,或者是可以在着色器中着色的纯灰度8位蒙版。这可能会很快而以内存为代价。

最佳:我认为,但是生成对象的符号距离场(SDF)表示可能是最佳解决方案。这些纹理可以比源纹理小得多,并且仍可以捕获有用的数据。本质上,每个像素都将其编码成与用于生成它的对象有多远。有了这些数据,您可以编写从发光到轮廓的各种效果。边框可能会改变大小和颜色等,并且仍然是一个相对便宜的着​​色器,并且只能绘制一次。缺点是工具和预处理。


0

我不确定效率,但我能看到的最简单的方法是以您要首先选择的颜色绘制较大版本的精灵。在其上绘制精灵。您只会看到第一个精灵的边缘,从而产生选择效果。

编辑:但是,正如您从评论中看到的那样,这不是一个好主意。


1
只是放大精灵并不能给出真实的轮廓
Iain 10'9

2
我认为不会,但是那很容易。
共产党鸭子

2
很多事情都很容易,但不能解决问题。对于具有任何有趣轮廓的精灵,放大将产生绝对垃圾。

放大只会对实心正方形或圆形对象好看。如果形状真的很宽,很高或有间隙,它将看起来非常糟糕。
AttackingHobo

3
扩大规模会比不采取任何行动提供更好的结果,并且在“完美”道路上也是有用的一步。尽管图形结果并不完美,但如果是用于内部工具,则可能就足够了。
dash-tom-bang 2010年

0

我同意扩大精灵的规模。到目前为止,这是最简单的方法,您可以将其应用于选择任何sprite,而不必为此专门创建其他sprite。

  • 即spriteOutline.Scale = spriteOriginal.Scale * 0.1f; spriteOutline.Color =新的Color(255,0,0,255);

0

用轮廓颜色替换原始精灵的颜色(或者根据需要着色)。以1个像素的偏移量四次渲染此平面着色或着色的精灵:x,y =(-1,-1),然后(+ 1,-1),然后(-1,+ 1)然后(+1) ,+ 1)。对组成对象的所有子画面重复上述步骤。

之后,以适当的顺序在(0,0)的顶部渲染原始精灵。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.