网易首页 > 网易号 > 正文 申请入驻

使用 DDGI 创建逼真的光影

0
分享至

每日分享最新,最流行的软件开发知识与最新行业趋势,希望大家能够一键三连,多多支持,跪求关注,点赞,留言。
DDGI 是实现逼真的照明效果的绝佳功能。了解如何为移动应用配备 DDGI。

为什么我们需要 DDGI
在使 3D 游戏身临其境的所有因素中,全局照明效果(包括反射、折射和阴影)无疑是皇冠上的明珠。简而言之,糟糕的照明会破坏原本出色的游戏体验。
一种用于创建真实照明的技术被称为动态漫反射全局照明(简称 DDGI)。该技术为游戏提供实时渲染,以精致和吸引人的视觉效果装饰游戏场景。换句话说,DDGI通过动态改变光照,呈现出场景中的每一种颜色,实现物体与场景温度之间的明显关系,丰富场景中信息的表示层次。


使用直接照明渲染的场景与使用 DDGI 渲染的场景
实现具有上图所示照明效果的场景需要强大的技术力量——这不是唯一的挑战。不同的材料以不同的方式对光作出反应。这种差异通过漫反射来表示,漫反射均匀地散射照明信息,包括照度、光移动方向和光移动速度。巧妙地处理所有这些变量需要具有海量计算能力的高性能开发平台。
HMS Core Scene Kit 的 DDGI 插件为所有这些挑战提供了一种解决方案。它支持移动应用程序,并且可以扩展到所有操作系统,无需预烘焙。利用光探针,插件在更新和着色探针时采用了改进的算法。这样,插件的计算负载比传统的DDGI方案低。该插件模拟光对物体表面的多次反射,以支持具有动态、交互式和逼真的照明效果的移动应用程序。


演示
场景中的美妙灯光效果是使用刚才提到的插件创建的,我没有说谎,只需几个简单的步骤即可完成。然后让我们深入了解如何为应用程序配备此插件的步骤。
开发流程
概述
1.初始化阶段:配置Vulkan环境,初始化DDGIAPI类。
2.准备阶段:
创建两个将存储 DDGI 插件的渲染结果的纹理,并将纹理信息传递给插件。
准备好所需的信息,然后将其传递给插件。此类信息包括网格、材料、光源、相机和分辨率的数据。
为插件设置必要的参数。
3. 渲染阶段:
当应用于网格、光源或相机的变换矩阵信息发生变化时,新信息将传递给 DDGI 插件。
调用Render()函数进行渲染,将DDGI插件的渲染结果保存到准备阶段创建的纹理中。
将 DDGI 插件的渲染结果应用于着色计算。
艺术限制
1、在场景中使用DDGI插件时,将下面过程部分中步骤6中的origin设置为场景的中心坐标,并相应配置探针数和光线行进数。这有助于确保插件的音量可以覆盖整个场景。
2. 要使DDGI插件能够模拟场景中的光障碍,请确保场景中的墙壁都具有适当的厚度(应该大于探针密度)。否则会出现漏光问题。最重要的是,我建议您创建一个由两个单面平面组成的墙。
3. DDGI插件专为移动应用而设计。考虑到性能和功耗,建议(非必需):
传递给 DDGI 插件的网格顶点数小于等于 50,000,以控制网格数。例如,仅传递将创建间接光的主要结构。
探针的密度和数量高达 10 x 10 x 10。
程序
1、下载DDGI插件的包并解压。将获得一个头文件和两个 Android 的 SO 文件。你可以在这里找到包。
2. 使用 CMake 创建一个CMakeLists.txt文件。以下是该文件的示例。
cmake_minimum_required(VERSION 3.4.1 FATAL_ERROR)
set(NAME DDGIExample)
project(${NAME})
set(PROJ_ROOT ${CMAKE_CURRENT_SOURCE_DIR})
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++14 -O2 -DNDEBUG -DVK_USE_PLATFORM_ANDROID_KHR")
file(GLOB EXAMPLE_SRC "${PROJ_ROOT}/src/*.cpp") # Write the code for calling the DDGI plugin by yourself.
include_directories(${PROJ_ROOT}/include) # Import the header file. That is, put the DDGIAPI.h header file in this directory.
# Import two SO files (librtcore.so and libddgi.so).
ADD_LIBRARY(rtcore SHARED IMPORTED)
SET_TARGET_PROPERTIES(rtcore
PROPERTIES IMPORTED_LOCATION
${CMAKE_SOURCE_DIR}/src/main/libs/librtcore.so)
ADD_LIBRARY(ddgi SHARED IMPORTED)
SET_TARGET_PROPERTIES(ddgi
PROPERTIES IMPORTED_LOCATION
${CMAKE_SOURCE_DIR}/src/main/libs/libddgi.so)
add_library(native-lib SHARED ${EXAMPLE_SRC})
target_link_libraries(
native-lib
ddgi # Link the two SO files to the app.
rtcore
android
log
z

3、配置Vulkan环境,初始化DDGIAPI类。
// Set the Vulkan environment information required by the DDGI plugin,
// including logicalDevice, queue, and queueFamilyIndex.
void DDGIExample::SetupDDGIDeviceInfo()
m_ddgiDeviceInfo.physicalDevice = physicalDevice;
m_ddgiDeviceInfo.logicalDevice = device;
m_ddgiDeviceInfo.queue = queue;
m_ddgiDeviceInfo.queueFamilyIndex = vulkanDevice->queueFamilyIndices.graphics;
void DDGIExample::PrepareDDGI()
// Set the Vulkan environment information.
SetupDDGIDeviceInfo();
// Call the initialization function of the DDGI plugin.
m_ddgiRender->InitDDGI(m_ddgiDeviceInfo);

void DDGIExample::Prepare()

// Create a DDGIAPI object.
std::unique_ptr m_ddgiRender = make_unique();
PrepareDDGI();

4. 创建两个纹理:一个用于存储辐照度结果(即来自摄像机视图的漫反射全局照明),另一个用于存储法线和深度。为了提高渲染性能,您可以为这两个纹理设置较低的分辨率。较低的分辨率会带来更好的渲染性能,但也会导致渲染结果失真,例如锯齿状边缘。
// Create two textures for storing the rendering results.
void DDGIExample::CreateDDGITexture()
VkImageUsageFlags usage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT;
int ddgiTexWidth = width / m_shadingPara.ddgiDownSizeScale; // Texture width.
int ddgiTexHeight = height / m_shadingPara.ddgiDownSizeScale; // Texture height.
glm::ivec2 size(ddgiTexWidth, ddgiTexHeight);
// Create a texture for storing the irradiance results.
m_irradianceTex.CreateAttachment(vulkanDevice,
ddgiTexWidth,
ddgiTexHeight,
VK_FORMAT_R16G16B16A16_SFLOAT,
usage,
VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
m_defaultSampler);
// Create a texture for storing the normal and depth.
m_normalDepthTex.CreateAttachment(vulkanDevice,
ddgiTexWidth,
ddgiTexHeight,
VK_FORMAT_R16G16B16A16_SFLOAT,
usage,
VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
m_defaultSampler);
// Set the DDGIVulkanImage information.
void DDGIExample::PrepareDDGIOutputTex(const vks::Texture& tex, DDGIVulkanImage *texture) const
texture->image = tex.image;
texture->format = tex.format;
texture->type = VK_IMAGE_TYPE_2D;
texture->extent.width = tex.width;
texture->extent.height = tex.height;
texture->extent.depth = 1;
texture->usage = tex.usage;
texture->layout = tex.imageLayout;
texture->layers = 1;
texture->mipCount = 1;
texture->samples = VK_SAMPLE_COUNT_1_BIT;
texture->tiling = VK_IMAGE_TILING_OPTIMAL;
void DDGIExample::PrepareDDGI()

// Set the texture resolution.
m_ddgiRender->SetResolution(width / m_downScale, height / m_downScale);
// Set the DDGIVulkanImage information, which tells your app how and where to store the rendering results.
PrepareDDGIOutputTex(m_irradianceTex, &m_ddgiIrradianceTex);
PrepareDDGIOutputTex(m_normalDepthTex, &m_ddgiNormalDepthTex);
m_ddgiRender->SetAdditionalTexHandler(m_ddgiIrradianceTex, AttachmentTextureType::DDGI_IRRADIANCE);
m_ddgiRender->SetAdditionalTexHandler(m_ddgiNormalDepthTex, AttachmentTextureType::DDGI_NORMAL_DEPTH);

void DDGIExample::Prepare()

CreateDDGITexture();
PrepareDDGI();

5、准备好DDGI插件进行渲染所需的mesh、material、lightsource、camera等信息。
// Mesh structure, which supports submeshes.
struct DDGIMesh {
std::string meshName;
std::vector meshVertex;
std::vector meshIndice;
std::vector materials;
std::vector subMeshStartIndexes;

// Directional light structure. Currently, only one directional light is supported.
struct DDGIDirectionalLight {
CoordSystem coordSystem = CoordSystem::RIGHT_HANDED;
int lightId;
DDGI::Mat4f localToWorld;
DDGI::Vec4f color;
DDGI::Vec4f dirAndIntensity;
// Main camera structure.
struct DDGICamera {
DDGI::Vec4f pos;
DDGI::Vec4f rotation;
DDGI::Mat4f viewMat;
DDGI::Mat4f perspectiveMat;
// Set the light source information for the DDGI plugin.
void DDGIExample::SetupDDGILights()
m_ddgiDirLight.color = VecInterface(m_dirLight.color);
m_ddgiDirLight.dirAndIntensity = VecInterface(m_dirLight.dirAndPower);
m_ddgiDirLight.localToWorld = MatInterface(inverse(m_dirLight.worldToLocal));
m_ddgiDirLight.lightId = 0;
// Set the camera information for the DDGI plugin.
void DDGIExample::SetupDDGICamera()
m_ddgiCamera.pos = VecInterface(m_camera.viewPos);
m_ddgiCamera.rotation = VecInterface(m_camera.rotation, 1.0);
m_ddgiCamera.viewMat = MatInterface(m_camera.matrices.view);
glm::mat4 yFlip = glm::mat4(1.0f);
yFlip[1][1] = -1;
m_ddgiCamera.perspectiveMat = MatInterface(m_camera.matrices.perspective * yFlip);
// Prepare the mesh information required by the DDGI plugin.
// The following is an example of a scene in glTF format.
void DDGIExample::PrepareDDGIMeshes()
for (constauto& node : m_models.scene.linearNodes) {
DDGIMesh tmpMesh;
tmpMesh.meshName = node->name;
if (node->mesh) {
tmpMesh.meshName = node->mesh->name; // Mesh name.
tmpMesh.localToWorld = MatInterface(node->getMatrix()); // Transformation matrix of the mesh.
// Skeletal skinning matrix of the mesh.
if (node->skin) {
tmpMesh.hasAnimation = true;
for (auto& matrix : node->skin->inverseBindMatrices) {
tmpMesh.boneTransforms.emplace_back(MatInterface(matrix));

// Material node information and vertex buffer of the mesh.
for (vkglTF::Primitive *primitive : node->mesh->primitives) {

m_ddgiMeshes.emplace(std::make_pair(node->index, tmpMesh));

void DDGIExample::PrepareDDGI()

// Convert these settings into the format required by the DDGI plugin.
SetupDDGILights();
SetupDDGICamera();
PrepareDDGIMeshes();
// Pass the settings to the DDGI plugin.
m_ddgiRender->SetMeshs(m_ddgiMeshes);
m_ddgiRender->UpdateDirectionalLight(m_ddgiDirLight);
m_ddgiRender->UpdateCamera(m_ddgiCamera);

6.设置DDGI探针的位置和数量等参数。
// Set the DDGI algorithm parameters.
void DDGIExample::SetupDDGIParameters()
m_ddgiSettings.origin = VecInterface(3.5f, 1.5f, 4.25f, 0.f);
m_ddgiSettings.probeStep = VecInterface(1.3f, 0.55f, 1.5f, 0.f);

void DDGIExample::PrepareDDGI()

SetupDDGIParameters();
// Pass the settings to the DDGI plugin.
m_ddgiRender->UpdateDDGIProbes(m_ddgiSettings);

7.调用DDGI插件的Prepare()函数解析接收到的数据。
void DDGIExample::PrepareDDGI()

m_ddgiRender->Prepare();
8.调用DDGI插件的Render()函数,缓存漫反射全局光照更新到第4步创建的贴图。
笔记:
在这个版本中,渲染结果是两种纹理:一种用于存储辐照度结果,另一种用于存储法线和深度。然后,可以使用双边滤波算法和存储法线和深度的纹理对存储辐照度结果的纹理进行上采样,通过一定的计算得到最终的漫反射全局光照结果。
如果未调用Render()函数,则渲染结果为更改发生之前的场景。
#define RENDER_EVERY_NUM_FRAME 2
void DDGIExample::Draw()

// Call DDGIRender() once every two frames.
if (m_ddgiON && m_frameCnt % RENDER_EVERY_NUM_FRAME == 0) {
m_ddgiRender->UpdateDirectionalLight(m_ddgiDirLight); // Update the light source information.
m_ddgiRender->UpdateCamera(m_ddgiCamera); // Update the camera information.
m_ddgiRender->DDGIRender(); // Use the DDGI plugin to perform rendering once and save the rendering results to the textures created in step 4.

void DDGIExample::Render()
if (!prepared) {
return;
SetupDDGICamera();
if (!paused || m_camera.updated) {
UpdateUniformBuffers();
Draw();
m_frameCnt++;
9. 应用DDGI插件的全局光照(也叫间接光照)效果如下。


// Apply the rendering results of the DDGI plugin to shading calculations.
// Perform upsampling to calculate the DDGI results based on the screen space coordinates.
vec3 Bilateral(ivec2 uv, vec3 normal)

void main()

vec3 result = vec3(0.0);
result += DirectLighting();
result += IndirectLighting();
vec3 DDGIIrradiances = vec3(0.0);
ivec2 texUV = ivec2(gl_FragCoord.xy);
texUV.y = shadingPara.ddgiTexHeight - texUV.y;
if (shadingPara.ddgiDownSizeScale == 1) { // Use the original resolution.
DDGIIrradiances = texelFetch(irradianceTex, texUV, 0).xyz;
} else { // Use a lower resolution.
ivec2 inDirectUV = ivec2(vec2(texUV) / vec2(shadingPara.ddgiDownSizeScale));
DDGIIrradiances = Bilateral(inDirectUV, N);
result += DDGILighting();
Image = vec4(result_t, 1.0);
现在集成了DDGI插件,应用程序可以释放动态光效。
带走
DDGI 是一种在 3D 游戏中广泛采用的技术,通过提供动态照明效果,使游戏感觉更加身临其境和真实。然而,传统的 DDGI 解决方案要求很高,并且很难将其集成到移动应用程序中。Scene Kit 通过引入其 DDGI 插件打破了这些障碍。

特别声明:以上内容(如有图片或视频亦包括在内)为自媒体平台“网易号”用户上传并发布,本平台仅提供信息存储服务。

Notice: The content above (including the pictures and videos if any) is uploaded and posted by a user of NetEase Hao, which is a social media platform and only provides information storage services.

相关推荐
热点推荐
复旦数院教授谈姜萍:答案超越95%的数学专业学生!引来更多高校的橄榄枝:同济大学祝贺

复旦数院教授谈姜萍:答案超越95%的数学专业学生!引来更多高校的橄榄枝:同济大学祝贺

和讯网
2024-06-17 14:30:57
就在刚刚,中方正式下达“逐客令”,要求这国4天内必须离华!

就在刚刚,中方正式下达“逐客令”,要求这国4天内必须离华!

小乐讲故事
2023-05-17 09:52:08
人过了60岁,这四个人就没必要见面了,这是老祖宗的告诫。

人过了60岁,这四个人就没必要见面了,这是老祖宗的告诫。

娱乐洞察点点
2024-06-19 15:21:52
创纪录!网约车司机被乘客殴打获赔26万!

创纪录!网约车司机被乘客殴打获赔26万!

网约车观察室
2024-06-18 11:35:52
使馆车违停后续:女司机真实身份曝光,生活照被扒,亚太受牵连

使馆车违停后续:女司机真实身份曝光,生活照被扒,亚太受牵连

飘飘视角
2024-06-18 23:54:10
女排12人出征总决赛!张常宁当队长,21岁得分王+美女二传成亮点

女排12人出征总决赛!张常宁当队长,21岁得分王+美女二传成亮点

李喜林篮球绝杀
2024-06-18 16:45:03
员工懵了!著名快餐连锁店突然关闭15家门店!另外129 家门店也危了

员工懵了!著名快餐连锁店突然关闭15家门店!另外129 家门店也危了

北美省钱快报
2024-06-19 02:56:58
怎么会有这么邋遢的女艺人

怎么会有这么邋遢的女艺人

刘空青
2024-06-16 20:06:28
田三为字母做证?田家对抗许敏失败,郭威回归九江只有一条路可走

田三为字母做证?田家对抗许敏失败,郭威回归九江只有一条路可走

水泥土的搞笑
2024-06-19 13:16:40
国安迎来大牌新归化!曾效力南美老牌豪门,本人已提前成功入籍

国安迎来大牌新归化!曾效力南美老牌豪门,本人已提前成功入籍

罗掌柜体育
2024-06-18 16:48:30
中雨、大雨、雷暴大风明天就到!西安这里实行封闭管理

中雨、大雨、雷暴大风明天就到!西安这里实行封闭管理

91.6陕西交通广播
2024-06-19 16:21:10
被大49岁的谢贤养了12年,拿2000万分手费走人的coco,如今怎样了

被大49岁的谢贤养了12年,拿2000万分手费走人的coco,如今怎样了

闻星盼夏
2024-06-17 18:50:02
洪荒70成功放电!全球首台全高温超导托卡马克装置落地

洪荒70成功放电!全球首台全高温超导托卡马克装置落地

中新经纬
2024-06-18 21:10:10
工地上的临时夫妻生活,是农民工在城市边缘的温情还是生存的无奈

工地上的临时夫妻生活,是农民工在城市边缘的温情还是生存的无奈

小鱼滑
2024-04-26 00:25:56
美女模特,蜂腰大长腿,凹凸有致,请你吃晚饭你去不去

美女模特,蜂腰大长腿,凹凸有致,请你吃晚饭你去不去

傲娇的马甲线
2024-06-13 17:30:03
童年被拐,36岁找到亲生父母,却被母亲撕上热搜

童年被拐,36岁找到亲生父母,却被母亲撕上热搜

米粒妈爱分享
2024-06-18 18:00:12
沿着丁神的足迹!曝国青核心加盟山东 他被看作是第二个丁彦雨航

沿着丁神的足迹!曝国青核心加盟山东 他被看作是第二个丁彦雨航

大嘴爵爷侃球
2024-06-19 11:46:54
乌军创历史 俄遭巨大打击

乌军创历史 俄遭巨大打击

小新在洗手间
2024-06-17 17:17:04
干部躺平熬龄的大变局来了

干部躺平熬龄的大变局来了

芯怡飞
2024-06-19 10:32:02
仅领先国足13名?格鲁吉亚FIFA排名仅第75,但去年曾8-0狂胜泰国

仅领先国足13名?格鲁吉亚FIFA排名仅第75,但去年曾8-0狂胜泰国

直播吧
2024-06-19 02:05:51
2024-06-19 19:22:44
墨谈科技
墨谈科技
业务数码玩家.无聊的博主
3005文章数 567关注度
往期回顾 全部

科技要闻

英伟达超越苹果、微软登顶全球新股王

头条要闻

胖东来"爆改"的永辉超市营业挤满顾客:员工月薪涨千元

头条要闻

胖东来"爆改"的永辉超市营业挤满顾客:员工月薪涨千元

体育要闻

欧洲杯最大的混子,非他莫属

娱乐要闻

黄一鸣“杀疯了” 直播间卖大葱养孩子

财经要闻

深化科创板改革 证监会发布八条措施

汽车要闻

双肾格栅变化大/内饰焕新 新一代宝马X3官图发布

态度原创

房产
健康
数码
教育
亲子

房产要闻

17.9亿!终于,有民企在三亚大手笔拿地了!周边房价10万+!

晚餐不吃or吃七分饱,哪种更减肥?

数码要闻

Vidda C2 Pro跻身京东明星投影前三 自研自产实力曝光

教育要闻

孩子买学习机,到底该关注哪些核心问题才能不踩坑?

亲子要闻

有些家长的无知能到什么程度?看文字都感觉窒息!毁了孩子一生!

无障碍浏览 进入关怀版