是否可以实现 MAX(As,Ad) openGL 混合? [英] Is it possible to achieve MAX(As,Ad) openGL blending?

查看:20
本文介绍了是否可以实现 MAX(As,Ad) openGL 混合?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在开发一款游戏,我想在网格上的一系列精灵下创建阴影.阴影比精灵本身大,并且精灵是动画的(即移动和旋转).

I am working on a game where I want to create shadows under a series of sprites on a grid. The shadows are larger than the sprites themselves and the sprites are animated (i.e. move and rotate).

我不能简单地将它们渲染到精灵 png 中,否则阴影会与相邻的精灵重叠.

I cannot simply render them into the sprite png, or the shadows will overlap adjacent sprites.

我也不能简单地将阴影单独放在较低的层上,因为当它们重叠时,它们会在它们的交叉处产生暗带.

I also cannot simply put shadows on a lower layer by themselves, because when they overlap, they will create dark bands at their intersection.

这些精灵是动画的,因此无法整体渲染.

These sprites are animated, so it is not feasible to render these en masse.

基本上,我希望精灵的阴影混合在一起,以使它们在设定的不透明度下最大化.示例:

Basically, I want the sprites' shadows to blend together such that they max out at a set opacity. Example:

我相信这相当于 (Rs,Gs,Bs,Max(As,Ds)) 的 openGL 混合,我并不真正关心 R、G 和 B,因为它总是相同的src 和 dst 中的颜色.

I believe this is equivalent to an openGL blending of (Rs,Gs,Bs,Max(As,Ds)), where I don't really care about R,G, and B, as it will always be the same color in src and dst.

但是,这不是有效的 openGL 混合模式.有没有一种简单的方法可以做到这一点,尤其是在 cocos2d-iphone 中?

However, this is not a valid openGL blending mode. Is there an easy way to accomplish this, especially in cocos2d-iphone?

我可以通过使阴影精灵不透明,然后将它们都应用到父精灵,并使父精灵的不透明度为 40% 来近似这一点.但是,cocos2d 的工作方式只是将每个孩子的不透明度设置为 40%,而不是组合的 sprite 图像,这会导致相同的条纹.

I would be able to approximate this by making the shadow sprites opaque, then applying them both to a parent sprite, and making the parent sprite 40% opacity. However, the way cocos2d works, this only sets the opacity of each child to 40%, rather than the combined sprite image, which results in the same stripe.

推荐答案

好吧,我想经过大量研究,我意识到我的想法的错误.

OK, I think after much research, I realize the error in my thinking.

首先,有一种方法可以进行 Max Alpha openGL 混合,那就是使用 glBlendEquations.您必须修改 draw 方法来执行此操作(并为 textureNode 创建一些新属性以在这些方法之间切换),并使用以下任一方法:

First, there is a way to do Max Alpha openGL blending, and that is using glBlendEquations. You would have to modify the draw method to do this (and make some new attribute for a textureNode to switch between these methods), and use either of these:

 glBlendEquationOES( GL_MAX_EXT );
 glBlendEquationSeparateOES( GL_FUNC_ADD_OES, GL_MAX_EXT );

第一个对 RGBA 使用 max(),第二个对 RGB 使用标准加法,对 alpha 使用 max().

The first uses max() for RGBA, while the second uses standard addition for RGB, and max() for alpha.

现在的问题是,每个精灵及其子元素按 z 顺序被绘制到 屏幕.这意味着,在绘制第一个阴影之后,它是主屏幕缓冲区的一部分.换句话说,它的不透明度发生了变化,并且通过 max() 混合和标准的不透明背景,它现在被绘制到背景上,所以当你绘制下一个阴影时,它会执行 max(As, 1) ,即 1,因为背景不透明.所以我没有达到我想要的混合效果.如果我的背景是透明的,它会工作",但是我不能在后面"应用任何背景,我们只能添加到缓冲区中.

Now, the problem is that each sprite, and it's children, in z-order, are drawn to the screen. This means, that after the first shadow is drawn, it is part of the main screen buffer. In other words, its opacity is changed, and with max() blending and a standard opaque background, it's now painted onto the background, so when you draw the next shadow, it will do max(As, 1) which is 1, because the background is opaque. So I don't achieve the blending I want. It would "work" if my background was transparent, but then I could not apply any background "behind" that, we can only add to the buffer.

我可以先绘制阴影,使用 max() 混合,然后执行 {ONE_MINUS_DST_ALPHA, DST_ALPHA} glBlend.这是一个不错的解决方法,但我还有其他问题让这变得困难.

I could draw the shadows first, using the max() blend and then do a {ONE_MINUS_DST_ALPHA, DST_ALPHA} glBlend. This is an OK workaround, but I have other issues that make this difficult.

现在,我终于意识到,真正的解决方案是在将阴影应用到背景之前,使用 RenderTexture 将阴影渲染到单独的缓冲区.这可能会对性能产生影响,所以我们将看看它的发展方向.

Now, the real solution, I finally realize, is to use a RenderTexture to render the shadows to a separate buffer before applying them to the background. This could have performance implications, so we'll see where this goes.

更新:

好的,我现在有一个可行的解决方案.

OK, I have a working solution now.

奇怪的是,我最终不需要这个解决方案,因为在我的特殊情况下,条带不够明显,不足以保证努力,但是这是我想出的解决方案,似乎可以满足我的要求:

Oddly, I ended up not needing this solution after all, because in my particular case, the banding was not noticeable enough to warrant the effort, however this is the solution I came up with that seemed to do what I wanted:

  1. 首先在整个屏幕上绘制一个 0% 黑色的 alpha png.(不知道有没有必要,不知道屏幕默认的alpha是多少).

  1. First draw a 0% black alpha png to the entire screen. (I don't know if this is necessary. I don't know what the default alpha of the screen is).

使用 glEquationSeperateOES( GL_ADD, GL_MAX_ENT)glBlend( GL_ONE, GL_ONE ) 将阴影绘制到屏幕上.这将按照描述将所有阴影混合在一起,采用 alpha 的 max().

Draw the shadows to the screen using glEquationSeperateOES( GL_ADD, GL_MAX_ENT) and glBlend( GL_ONE, GL_ONE ). This will blend all of the shadows together as described, taking the max() of the alphas.

  • 因为你是合成黑色,所以相当于使用glBlendEquationOES(GL_MAX_ENT).(X+0 == max(X,0))

  • Because you are compositing to black, it is equivalent to use glBlendEquationOES( GL_MAX_ENT ). (X+0 == max(X,0))

glBlend( GL_ZERO, GL_ONE ) 将消除第 1 步的需要,或者至少不需要该层为 0% 黑色.GL_ZERO 本质上强制它为 0% 黑色.

glBlend( GL_ZERO, GL_ONE ) will eliminate the need of step 1, or at least the requirement of that layer to be 0% black. GL_ZERO essentially forces it to be 0% black.

绘制地板,将覆盖阴影,但使用 glBlend( ONE_MINUS_DST_ALPHA, DST_ALPHA ).这与您使用 glBlend( SRC_ALPHA, ONE_MINUS_SRC_ALPHA ) 将阴影添加到地板上的结果完全相同,但是如果您这样做,您将无法将阴影混合在一起(阅读答案顶部的原因).

Draw the floor, which will be over the shadows, but use glBlend( ONE_MINUS_DST_ALPHA, DST_ALPHA ). This results in exactly the same results as if you added the shadows to the floor with glBlend( SRC_ALPHA, ONE_MINUS_SRC_ALPHA ), however if you did it this way, you would not be able to blend the shadows together (read why at top of answer).

你已经完成了!这种方法的好处是阴影精灵可以像往常一样进行动画处理,而无需在单独的 renderTexture 上调用访问".

You are done! The nice thing about this method is that the shadow sprites can be animated as usual, without having to call "visit" on a separate renderTexture.

其余的:

我还修改了 CocosNode 以允许我向层添加阴影,该层链接到另一个 CocosNode.这样,阴影被渲染为地板的子节点,(或用于阴影混合的 0% 黑色背景精灵),但链接到另一个 CocosNode.当精灵移动时,如果它有阴影,它也会更新阴影位置.这允许我在屏幕上的所有对象下方拥有所有阴影,并让阴影自动跟随对象.

I also modified CocosNode to allow me to add a shadow to a layer, which links to another CocosNode. This way, the shadow is rendered as a child of the floor, (or the 0% black background sprite for the shadow blending), but is linked to another CocosNode. When a sprite moves, if it has a shadow, it updates the shadows position as well. This allows me to have all shadows below all objects on the screen, and to have the shadows automatically follow the object.

抱歉,答案很长.也许我的解决方案很笨拙,但似乎效果很好.

Sorry for the long answer. Maybe my solution is kludgy, but it seems to work great.

这篇关于是否可以实现 MAX(As,Ad) openGL 混合?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆