iPhone OpenGL ES 2.0 与 Cocos2D 混合给出了意想不到的结果

2023-12-22

我有非常简单的 CCScene,只有 1 个 CCLayer 包含:

  1. 采用标准混合模式的 CCSprite 背景
  2. CCRenderTexture 绘制画笔,其精灵附加到背景精灵上方的根 CCLayer:


_bgSprite = [CCSprite spriteWithFile:backgroundPath];
_renderTexture = [CCRenderTexture renderTextureWithWidth:self.contentSize.width height:self.contentSize.height];
[_renderTexture.sprite setBlendFunc:(ccBlendFunc){GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA}];
[self addChild:_bgSprite z:-100];
[self addChild:_renderTexture];
  

画笔渲染代码:

[_renderTexture begin];
glBlendFuncSeparate(GL_ONE, GL_ZERO, GL_ONE, GL_ONE); // 1.
// calculate vertices code,etc...
glDrawArrays(GL_TRIANGLES, 0, (GLsizei)count);
[_renderTexture end];

当用户用第一个彩色画笔刷时,按预期与背景混合。 但何时继续在前一个画笔之上使用另一种颜色进行涂刷,会出错(当 2 个画笔彼此重叠时,软 Alpha 边缘会失去不透明度):

我尝试了很多混合选项,但不知怎的我找不到正确的一个。

CCRenderTexture 是否有什么特别之处,它没有按预期与自身(与先前绘制的内容)混合?

我用于刷涂的片段着色器只是标准纹理着色器,稍作更改即可保留纹理中的输入颜色 alpha:



void main()
{
    gl_FragColor = texture2D(u_texture, v_texCoord);
    gl_FragColor.a = v_fragmentColor.a;
}
  

更新 - 近乎完美的解决方案:通过 jozxyqk

glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA,
                        GL_ONE, GL_ONE_MINUS_SRC_ALPHA);

在渲染代码中(代替// 1. and

[_renderTexture.sprite setBlendFunc:(ccBlendFunc){GL_ONE, GL_ONE_MINUS_SRC_ALPHA}];

这效果很好,给了我我想要的......

...但仅当 _rederTexture 处于完全不透明状态时。

当不透明度为_rendertexture.sprite降低时,画笔会变亮,而不是像人们预期的那样淡出:

为什么当父纹理完全不透明时,画笔的 Alpha 能与背景正确混合,但当不透明度降低时却会变得疯狂?如何使画笔与背景正确融合?


EDIT

混合画笔->图层->背景

好吧,发生的事情是glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)正在将画笔描边混合到画笔纹理中,但纹理中生成的 alpha 值是错误的。每个添加的片段都需要 1. 将其 alpha 添加到最终的 alpha 值 - 它必须精确地去除交互所需的光量,并且 2. 按余数缩放先前的 alpha - 先前的表面将光减少先前的值,但由于添加了一个新的表面,可以减少的光线更少。我不确定这是否有意义,但它导致了这个......

glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA,
                    GL_ONE, GL_ONE_MINUS_SRC_ALPHA);

现在画笔纹理的颜色通道包含要与背景混合的总颜色(预先乘以 Alpha),而 Alpha 通道给出权重(或颜色遮盖背景的量)。由于颜色预先与 Alpha 相乘,因此默认的 RenderTexture 混合GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA与阿尔法缩放again从而使整体颜色变暗。现在,您需要使用以下函数将画笔纹理与背景混合,我认为该函数必须在 Cocos2D 中设置:

glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);

希望这是可能的。我没有过多考虑如何管理设置画笔纹理以与其混合的可能性GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA但它可能需要浮点纹理和/或额外的通道来划分/标准化阿尔法,这听起来很痛苦。

或者,在绘制之前将背景放入渲染纹理中,并将背景保留在那里,而不进行任何图层混合。

这对我有用:

glDisable(GL_DEPTH_TEST);
glClear(GL_COLOR_BUFFER_BIT);
glEnable(GL_TEXTURE_2D);
glEnable(GL_BLEND);

fbo.bind();
glClear(GL_COLOR_BUFFER_BIT);
glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA,
                    GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
drawTexture(brush1);
drawTexture(brush2);
fbo.unbind();

drawTexture(grassTex); //tex alpha is 1.0, so blending doesn't affect background
glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
drawTexture(fbo.getColour(0)); //blend in the brush layer

画笔层不透明度

Using GL_ONE, GL_ONE_MINUS_SRC_ALPHA导致库在图层混合中实现不透明度的问题,因为它假设颜色乘以 alpha。通过减少opacity值,画笔层的 Alpha 在混合过程中按比例缩小。GL_ONE_MINUS_SRC_ALPHA然后导致背景颜色的数量增加,但是GL_ONE笔刷层的总和为 100%,并使图像过饱和。

我认为最简单的解决方案是找到一种方法来自行缩小全局图层不透明度的颜色并继续使用GL_ONE, GL_ONE_MINUS_SRC_ALPHA.

  • 实际使用GL_CONSTANT_COLOR, GL_ONE_MINUS_SRC_ALPHA如果图书馆支持它,这可能是一个答案,但显然不支持。
  • 您可以使用固定管道渲染来缩放颜色:glColor4f(opacity, opacity, opacity, opacity),但这将需要第二个渲染目标并手动进行混合,类似于上面的代码,您为背景绘制一次全屏四边形,然后为画笔层绘制一次。
  • 如果您手动进行混合,那么使用片段着色器而不是使用片段着色器会更稳健glColor方法。如果您想要使用更复杂的混合函数,这将允许更大的控制,特别是在涉及 0 到 1 范围之外的除法和临时函数时:gl_FragColour = texture(brushTexture, coord) * layerOpacity;

END EDIT


标准的 alpha 混合函数是glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);,不完全是 GL“初始”/默认功能。

像在 glBlendFuncSeparate 中那样对 alpha 值求和将使 alpha 过度饱和,并且下面的颜色将被完全替换。饱和度混合可能会给出不错的结果:glBlendFunc(GL_SRC_ALPHA_SATURATE, GL_ONE) http://www.opengl.org/sdk/docs/man/xhtml/glBlendFunc.xml。也许也值得尝试glBlend方程分离 http://www.opengl.org/wiki/GLAPI/glBlendEquationSeparate和 MAX 混合(如果支持)。使用 MAX 的优点是减少线条绘制代码中的重叠伪像(硬三角形位) - 例如替换颜色,但仅限于达到总 alpha 值 X。编辑:这两种情况都需要在每次笔划后进行混合和清除.

我只能假设将渲染纹理混合到背景上实际上是有效的。(不适用于当前图层值)

顺便说一句,基本上不相关的还有“混合不足”,您可以在其中保留透射率值而不是 alpha/不透明度(来自here http://developer.download.nvidia.com/SDK/10/opengl/src/dual_depth_peeling/doc/DualDepthPeeling.pdf):

glBlendEquation(GL_FUNC_ADD); 
glBlendFuncSeparate(GL_DST_ALPHA, GL_ONE, GL_ZERO, GL_ONE_MINUS_SRC_ALPHA); 
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

iPhone OpenGL ES 2.0 与 Cocos2D 混合给出了意想不到的结果 的相关文章

  • 当具有 PagingEnabled 的 UIScrollView 更改页面时如何更新 UIPageControl?

    我该如何做到这一点 以便当用户滚动到 UIScrollView 中的新页面时 UIPageControl 更新 我以前用过这个 看起来效果很好 请务必将 UIScrollView delegate 设置为 self pragma mark
  • iPhone Simulator - 模拟慢速连接?

    有没有办法减慢 iPhone 模拟器的互联网连接速度 以便模拟当您处于蜂窝网络速度较慢的位置时应用程序的反应 如何安装 Apple 的网络链接调节器 这些说明截至 2019 年 10 月有效 警告 如果您刚刚升级到新版本的 macOS 确保
  • 当今最常用的跨平台移动应用程序开发框架是什么?

    我和这里的许多其他人一样 在移动世界迈出第一步时不知道从哪里开始 嗯 我在这里看到了一些关于移动开发框架或 sdk 的帖子 但所有这些都是针对特定目的的 例如 Web 客户端 小部件 html 开发等 我真正想知道的是 在目前市场上的所有选
  • 不使用 MFMailComposeViewController 发送邮件

    我想从 iPhone 应用程序发送邮件而不显示MFMailComposeViewController 我还希望从用户的默认邮件帐户发送此邮件 是否有可能做到这一点 iPhone SDK 不支持这一点 可能是因为 Apple 不希望您这样做
  • PlaySystemSound 静音开关打开

    我知道 我必须设置AudioSession到 播放 类别 即使静音开关打开也允许播放音频 这就是我所做的 但打开开关时声音仍然静音 UInt32 sessionCategory kAudioSessionCategory MediaPlay
  • iOS - 自动调整 CVPixelBufferRef 的大小

    我正在尝试裁剪和缩放CMSampleBufferRef基于用户的输入 基于ratio 下面的代码采用 CMSampleBufferRef 将其转换为 CVImageBufferRef 并使用 CVPixelBuffer 根据其字节裁剪内部图
  • 处于编辑模式时滑动即可删除

    我有一个使用 uitableview 的 iPhone 应用程序 我希望始终显示 重新排序 控件 并让用户滑动以删除行 我目前采取的方法是将表格视图置于编辑模式并允许在编辑模式下进行选择 self tableView editing YES
  • 我如何知道网页视图已加载完成

    我有网络视图 因为我正在加载pdf文件 pdf 文件大小为 2 mb 因此需要时间 我想添加指标 为此 我如何知道我的文件已加载到网络视图中 UIWebView 委托 http developer apple com library ios
  • 进入/退出编辑模式时重绘 UITableViewCell

    我有一个表格视图 其中根据表格是否正在编辑 单元格的构建方式有所不同 具体来说 处于编辑模式时选择样式为无 非编辑模式时选择样式为蓝色 当我从一个单元转换到另一个单元时 我注意到某些单元格没有更新 快速的日志记录告诉我 即使单元格的外观发生
  • 如何在 AVAudioSession 内使用 iPhone XS 中内置的立体声(2 通道)麦克风?

    我试图从 iPhone XS 的所谓立体声后置麦克风获取两个通道 但在不同位置只能看到一个通道AVAudioSession and AVAudioSessionPortDescription与后置摄像头相关联 我尝试过使用AVAudioSe
  • iPhone 相当于 Application.DoEvents();

    iPHone 我们使用 MonoTouch 但 Obj C 答案还可以 我的单例域对象需要一段时间才能获取所有数据 因此它在线程中内部运行部分获取数据 我需要通知 UI 域已完成 目前我正在这样做 有没有更好的办法 在 WinForms 中
  • UITableview 中的水平和垂直滚动[关闭]

    Closed 这个问题需要多问focused help closed questions 目前不接受答案 I want to make a lineup for a festival You can see what I want to a
  • 您是否标记 UIView 或将它们保留为属性?

    这主要是一个风格问题 但自从我开始为 iPhone 编程以来 我一直很好奇其他人的想法是什么 当您的 iPhone 应用程序中有一个 UIView 并且需要在应用程序的其他位置访问它时 通常在视图控制器中的另一个函数中 您是否喜欢用整数标记
  • 是否有针对不同屏幕尺寸的单独故事板?

    基本上我已经完成了一个应用程序 我唯一的问题是 ATM 机应用程序在设计时只考虑了 4 英寸显示屏 当在 3 5 英寸模拟器上运行时 应用程序会丢失 0 5 英寸 显然 那么我的问题是 如何在 Xcode 5 中为不同的屏幕尺寸设置不同的故
  • 如何禁用 UITableView 中某些行的删除操作?

    我知道使用setEditing 启用UITableView的编辑模式 但我更喜欢禁用某些特定行的操作 启用其他行 是否可以 Thanks interdev 实施the tableView canEditRowAtIndexPath meth
  • 如何将 NSDecimal 值转换为 NSInteger 值?

    我遇到一种情况 我得到一个 NSDecimal 并且我需要一个 NSInteger 我确实知道这是一个非常小的值 这是绝对肯定的 它不会大于 100 所以将它转换为 NSInteger 就完全没问题 不会发生溢出 这怎么可能做到呢 NSDe
  • 在横向中自动调整 UITableCells 内容的大小

    在 UITableView 中 我通过 UILabels 将内容添加到单元格中 定义最佳尺寸 与单元格宽度允许的一样大 我注意到只有tableView contentSize width是可靠的 因为cell contentView bou
  • 将 SSLSetEnabledCiphers 与 AFNetworking 结合使用来禁用弱密码

    我正在尝试禁用一些密码 弱 例如单个 DES 单个 DES 40 位等 我尝试过使用这段代码在 Cocoa 中使用 CFSocket CFStream 时如何设置 SSL 密码 https stackoverflow com questio
  • 在发生更改事件时将货币格式重新应用到 UITextField

    我正在使用一个包含本地化货币值的 UITextField 我看过很多关于如何使用此功能的帖子 但我的问题是 如何在每次按键后将货币格式重新应用到 UITextField 我知道我可以通过以下方式设置和使用货币格式化程序 NSNumberFo
  • 在 UIScrollview 上显示缩略图的最佳方法是什么(从服务器下载)

    我想在 UIScrollview 如照片应用程序 上显示许多图像 作为缩略图 所有图像将从服务器下载 据我所知 有几种选择 1 通过创建 UIImageviews 然后将它们添加为主滚动视图上的子视图 2 通过子类化一个UIView类 然后

随机推荐