鸿蒙开发-想做水面和镜面反射?光线追踪反射效果详解
想象一下:你的游戏里有一滩水,水面应该能反射周围的山和天空;或者游戏里有一面镜子,角色走过的时候应该能看到自己的倒影。传统的做法是用 CubeMap 或者平面反射来模拟,效果说得过去但总有"假"的感觉。光线追踪反射(RT Reflection)就不一样了。它通过真正的光线追踪算法来计算反射,能准确地反映场景中的物体、光照和阴影。效果逼真得多,当然计算量也大得多。XEngine 提供了 RT Ref
让游戏画面更真实——用 XEngine 实现光线追踪反射
想象一下:你的游戏里有一滩水,水面应该能反射周围的山和天空;或者游戏里有一面镜子,角色走过的时候应该能看到自己的倒影。传统的做法是用 CubeMap 或者平面反射来模拟,效果说得过去但总有"假"的感觉。
光线追踪反射(RT Reflection)就不一样了。它通过真正的光线追踪算法来计算反射,能准确地反映场景中的物体、光照和阴影。效果逼真得多,当然计算量也大得多。
XEngine 提供了 RT Reflection 特性,让你可以在 Vulkan 环境下方便地使用光线追踪反射。
查询支持
RT Reflection 的整体使用流程如下:
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 的三个参数:
device:VkDevicepCreateInfo:创建信息结构体指针,当前仅支持XEG_RTReflectionCreateInfo类型。不允许为空pRtReflection:输出句柄的指针
当创建参数(比如场景信息、分辨率等)变化时,你需要销毁旧对象、创建新对象。
录制反射渲染命令
每帧在命令缓冲里录制反射计算命令:
XEG_RTReflectionDescription description = {
// 当前帧的反射渲染参数
};
VkResult result = HMS_XEG_CmdRenderRTReflection(commandBuffer, rtReflection, &description);
if (result != VK_SUCCESS) {
// 命令录制失败
}
HMS_XEG_CmdRenderRTReflection 的三个参数:
commandBuffer:VkCommandBuffer,需要是 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);
使用场景
-
水面反射:湖面、河流、水坑等水体的反射效果。这是 RT 反射最常见的应用场景。
-
镜面反射:游戏中的镜子、玻璃、抛光金属等材质。
-
湿润地面:雨后的地面会有积水,能反射周围的灯光和建筑。
-
科幻/魔幻场景:能量护盾、传送门等需要反射效果的特殊物体。
和 SSR(屏幕空间反射)的区别
下面是两种反射技术的对比流程:
你可能听说过 SSR(Screen Space Reflection),这也是做反射的常用技术。它们的区别是:
SSR:只能反射屏幕上已经可见的物体。如果被反射的物体在屏幕外面(比如你低头看地面的水坑,水面应该反射天空,但天空不在屏幕里),SSR 就无能为力了,会出现"缺失"的反射。
RT Reflection:通过真正的光线追踪来计算反射,不管被反射的物体在不在屏幕内都能正确渲染。效果更准确,但计算成本更高。
和 XEG_StructureType 的关系
RT Reflection 使用了 XEG_StructureType 枚举里的两个值:
XEG_STRUCTURE_TYPE_RT_REFLECTION_CREATE_INFO = 2XEG_STRUCTURE_TYPE_RT_REFLECTION_DESCRIPTION = 3
使用建议
-
控制反射的范围:光线追踪反射的计算量和反射的范围成正比。你不需要让所有表面都做反射——只对那些反射效果明显的材质(水面、镜子、金属)开启就行。
-
配合降噪使用:光线追踪的反射结果可能会有噪点(特别是低采样率的情况下)。你可能需要配合降噪算法来获得平滑的反射效果。
-
命令缓冲类型:文档明确要求使用 Primary 类型的命令缓冲。
-
创建参数别频繁改:
XEG_RTReflectionCreateInfo变了就要重建对象。尽量在初始化的时候把参数确定好。 -
注意性能:RT Reflection 是所有 XEngine 特性里计算量比较大的。在移动端设备上使用时,要特别注意性能预算。建议从低分辨率的反射开始测试,逐步调高。
光线追踪反射能让游戏画面的质感提升一个档次。虽然计算成本不低,但 XEngine 已经帮你做了底层优化,你只需要提供场景数据和参数就行。
更多推荐

所有评论(0)