颜色选择实现
Color picking implementation
我正在开发一个非常简单但可自定义的 OpenGL ES 2 渲染引擎(我知道像 "unity" 和 "unreal engine" 这样的东西是存在的,重新发明轮子可能不是最明智的做法,只是把它当作给定的 ;-))。
现在我面临对象拾取:我不想进行光线投射,我想改为进行颜色拾取(在这里自由笑:我在当前实现中使用 ES3 上的 MRT。它可以工作,但只有在它工作的地方,如果你明白我的意思...)。
AFAIK 取色时,您可以有两个缓冲区(一个用于选择,一个用于渲染),或者对同一个缓冲区写入两次:每种方法各有利弊。
假设我有未知数量的对象是否更好:
- 创建两个缓冲区并将每个对象绘制到每个缓冲区,然后再转到下一个缓冲区(从而最大限度地减少必须加载的制服数量,但为每个对象切换缓冲区两次)
- 创建单个缓冲区,绘制所有对象以供选择,进行颜色选择,然后绘制所有内容以进行渲染(从而限制上下文切换,但增加程序切换和制服加载)
我觉得问题可以概括为:"is it more expensive to switch buffers repetitively, or to switch programs and load uniforms"?
哦...如果问题没有意义,请随时告诉我:)
在移动设备上,绘制调用的数量是要考虑的最重要的性能因素之一,每个绘制调用的驱动程序开销通常很大(通常 Android 比 IOS 大) ,因此绘制两次对象对性能不利(将使用更多 CPU => 驱动程序调用成本)。
如果你有不超过 256 个不同的对象,那么没有 MRT 的简单解决方案是使用 RGBA 渲染目标(而不是 RGB)并将对象 "ID" 存储在 alpha 通道中(作为灰度)颜色)。
否则,你应该不惜一切代价避免重复切换缓冲区,否则你会变慢 load/store 操作(切换到新缓冲区时,GPU 被迫将当前缓冲区 memcpy 到 "backup it",想象一下每帧执行数百次...)
所以要回答你的问题,重复切换缓冲区比切换程序和加载制服的成本更高。
PS:如果您有超过 256 个对象,您最终可能会尝试在 256 个对象中的 "slices" 中渲染,在每个切片之后您 glRead 缓冲区像素并检查 alpha 中的对象选择channel 然后 glClear 仅 alpha 并继续下一个切片。但是请注意,这可能不是很有效,因为一旦您想读取缓冲区像素,CPU 就必须停止,等待 GPU 完成渲染,所以您正在破坏 CPU/GPU 并行性
我正在开发一个非常简单但可自定义的 OpenGL ES 2 渲染引擎(我知道像 "unity" 和 "unreal engine" 这样的东西是存在的,重新发明轮子可能不是最明智的做法,只是把它当作给定的 ;-))。
现在我面临对象拾取:我不想进行光线投射,我想改为进行颜色拾取(在这里自由笑:我在当前实现中使用 ES3 上的 MRT。它可以工作,但只有在它工作的地方,如果你明白我的意思...)。
AFAIK 取色时,您可以有两个缓冲区(一个用于选择,一个用于渲染),或者对同一个缓冲区写入两次:每种方法各有利弊。
假设我有未知数量的对象是否更好:
- 创建两个缓冲区并将每个对象绘制到每个缓冲区,然后再转到下一个缓冲区(从而最大限度地减少必须加载的制服数量,但为每个对象切换缓冲区两次)
- 创建单个缓冲区,绘制所有对象以供选择,进行颜色选择,然后绘制所有内容以进行渲染(从而限制上下文切换,但增加程序切换和制服加载)
我觉得问题可以概括为:"is it more expensive to switch buffers repetitively, or to switch programs and load uniforms"?
哦...如果问题没有意义,请随时告诉我:)
在移动设备上,绘制调用的数量是要考虑的最重要的性能因素之一,每个绘制调用的驱动程序开销通常很大(通常 Android 比 IOS 大) ,因此绘制两次对象对性能不利(将使用更多 CPU => 驱动程序调用成本)。
如果你有不超过 256 个不同的对象,那么没有 MRT 的简单解决方案是使用 RGBA 渲染目标(而不是 RGB)并将对象 "ID" 存储在 alpha 通道中(作为灰度)颜色)。
否则,你应该不惜一切代价避免重复切换缓冲区,否则你会变慢 load/store 操作(切换到新缓冲区时,GPU 被迫将当前缓冲区 memcpy 到 "backup it",想象一下每帧执行数百次...)
所以要回答你的问题,重复切换缓冲区比切换程序和加载制服的成本更高。
PS:如果您有超过 256 个对象,您最终可能会尝试在 256 个对象中的 "slices" 中渲染,在每个切片之后您 glRead 缓冲区像素并检查 alpha 中的对象选择channel 然后 glClear 仅 alpha 并继续下一个切片。但是请注意,这可能不是很有效,因为一旦您想读取缓冲区像素,CPU 就必须停止,等待 GPU 完成渲染,所以您正在破坏 CPU/GPU 并行性