让游戏画面更真实——用 XEngine 实现光线追踪反射

想象一下:你的游戏里有一滩水,水面应该能反射周围的山和天空;或者游戏里有一面镜子,角色走过的时候应该能看到自己的倒影。传统的做法是用 CubeMap 或者平面反射来模拟,效果说得过去但总有"假"的感觉。

光线追踪反射(RT Reflection)就不一样了。它通过真正的光线追踪算法来计算反射,能准确地反映场景中的物体、光照和阴影。效果逼真得多,当然计算量也大得多。

XEngine 提供了 RT Reflection 特性,让你可以在 Vulkan 环境下方便地使用光线追踪反射。

查询支持

RT Reflection 的整体使用流程如下:

查询设备是否支持 RT Reflection

支持?

使用 SSR 或平面反射替代

创建 XEG_RTReflection 对象

每帧录制反射渲染命令

提交命令缓冲执行光线追踪

获取反射命中信息

采样环境贴图或计算反射颜色

合成到最终画面

退出时销毁对象

RT Reflection 是 Vulkan 专用的特性(起始版本 6.0.0(20)),需要通过扩展查询确认:

uint32_t propertyCount = 0;
HMS_XEG_EnumerateDeviceExtensionProperties(physicalDevice, &propertyCount, NULL);

XEG_ExtensionProperties* properties = malloc(sizeof(XEG_ExtensionProperties) * propertyCount);
HMS_XEG_EnumerateDeviceExtensionProperties(physicalDevice, &propertyCount, properties);

bool supported = false;
for (uint32_t i = 0; i < propertyCount; i++) {
    if (strcmp(properties[i].extensionName, XEG_RT_REFLECTION_EXTENSION_NAME) == 0) {
        supported = true;
        break;
    }
}
free(properties);
if (!supported) return;

XEG_RT_REFLECTION_EXTENSION_NAME 的值是 "XEG_rt_reflection"

创建 XEG_RTReflection 对象

确认支持之后,创建反射对象:

XEG_RTReflection rtReflection = VK_NULL_HANDLE;

XEG_RTReflectionCreateInfo createInfo = {
    // 反射场景的配置信息
};

VkResult result = HMS_XEG_CreateRTReflection(device, &createInfo, &rtReflection);
if (result != VK_SUCCESS) {
    // 创建失败
    return;
}

HMS_XEG_CreateRTReflection 的三个参数:

  • deviceVkDevice
  • pCreateInfo:创建信息结构体指针,当前仅支持 XEG_RTReflectionCreateInfo 类型。不允许为空
  • pRtReflection:输出句柄的指针

当创建参数(比如场景信息、分辨率等)变化时,你需要销毁旧对象、创建新对象。

录制反射渲染命令

每帧在命令缓冲里录制反射计算命令:

XEG_RTReflectionDescription description = {
    // 当前帧的反射渲染参数
};

VkResult result = HMS_XEG_CmdRenderRTReflection(commandBuffer, rtReflection, &description);
if (result != VK_SUCCESS) {
    // 命令录制失败
}

HMS_XEG_CmdRenderRTReflection 的三个参数:

  • commandBufferVkCommandBuffer,需要是 Primary 类型
  • rtReflection:已创建的 XEG_RTReflection 对象
  • pDescription:反射渲染输入信息结构体指针,当前是 XEG_RTReflectionDescription 类型,不允许为空

这个命令录制之后,GPU 执行时会进行光线追踪求交计算,输出反射的命中信息。你可以用这些信息来采样环境贴图或者计算反射颜色。

销毁对象

HMS_XEG_DestroyRTReflection(rtReflection);

完整流程

// 1. 查询扩展
uint32_t propertyCount = 0;
HMS_XEG_EnumerateDeviceExtensionProperties(physicalDevice, &propertyCount, NULL);
XEG_ExtensionProperties* properties = malloc(sizeof(XEG_ExtensionProperties) * propertyCount);
HMS_XEG_EnumerateDeviceExtensionProperties(physicalDevice, &propertyCount, properties);

bool supported = false;
for (uint32_t i = 0; i < propertyCount; i++) {
    if (strcmp(properties[i].extensionName, XEG_RT_REFLECTION_EXTENSION_NAME) == 0) {
        supported = true;
        break;
    }
}
free(properties);
if (!supported) return;

// 2. 创建对象
XEG_RTReflection rtReflection = VK_NULL_HANDLE;
XEG_RTReflectionCreateInfo createInfo = { /* ... */ };
HMS_XEG_CreateRTReflection(device, &createInfo, &rtReflection);

// 3. 每帧:录制反射计算命令
XEG_RTReflectionDescription desc = { /* 当前帧参数 */ };
HMS_XEG_CmdRenderRTReflection(commandBuffer, rtReflection, &desc);

// 4. 提交命令缓冲
vkQueueSubmit(queue, 1, &submitInfo, fence);

// 5. 反射结果可用于后续的渲染合成

// 6. 退出时销毁
HMS_XEG_DestroyRTReflection(rtReflection);

使用场景

  1. 水面反射:湖面、河流、水坑等水体的反射效果。这是 RT 反射最常见的应用场景。

  2. 镜面反射:游戏中的镜子、玻璃、抛光金属等材质。

  3. 湿润地面:雨后的地面会有积水,能反射周围的灯光和建筑。

  4. 科幻/魔幻场景:能量护盾、传送门等需要反射效果的特殊物体。

和 SSR(屏幕空间反射)的区别

下面是两种反射技术的对比流程:

需要渲染反射效果

选择反射技术

SSR 屏幕空间反射

RT Reflection 光线追踪反射

只能反射屏幕上可见物体

性能开销较低

屏幕外物体会缺失反射

可反射屏幕内外所有物体

效果更准确逼真

计算成本较高

你可能听说过 SSR(Screen Space Reflection),这也是做反射的常用技术。它们的区别是:

SSR:只能反射屏幕上已经可见的物体。如果被反射的物体在屏幕外面(比如你低头看地面的水坑,水面应该反射天空,但天空不在屏幕里),SSR 就无能为力了,会出现"缺失"的反射。

RT Reflection:通过真正的光线追踪来计算反射,不管被反射的物体在不在屏幕内都能正确渲染。效果更准确,但计算成本更高。

和 XEG_StructureType 的关系

RT Reflection 使用了 XEG_StructureType 枚举里的两个值:

  • XEG_STRUCTURE_TYPE_RT_REFLECTION_CREATE_INFO = 2
  • XEG_STRUCTURE_TYPE_RT_REFLECTION_DESCRIPTION = 3

使用建议

  1. 控制反射的范围:光线追踪反射的计算量和反射的范围成正比。你不需要让所有表面都做反射——只对那些反射效果明显的材质(水面、镜子、金属)开启就行。

  2. 配合降噪使用:光线追踪的反射结果可能会有噪点(特别是低采样率的情况下)。你可能需要配合降噪算法来获得平滑的反射效果。

  3. 命令缓冲类型:文档明确要求使用 Primary 类型的命令缓冲。

  4. 创建参数别频繁改XEG_RTReflectionCreateInfo 变了就要重建对象。尽量在初始化的时候把参数确定好。

  5. 注意性能:RT Reflection 是所有 XEngine 特性里计算量比较大的。在移动端设备上使用时,要特别注意性能预算。建议从低分辨率的反射开始测试,逐步调高。

光线追踪反射能让游戏画面的质感提升一个档次。虽然计算成本不低,但 XEngine 已经帮你做了底层优化,你只需要提供场景数据和参数就行。

Logo

讨论HarmonyOS开发技术,专注于API与组件、DevEco Studio、测试、元服务和应用上架分发等。

更多推荐