一、VXAL

Voxel Area Lighting (VXAL)主要是基于体素的面光源处理,其中主要有两种处理方法:

1.1 自发光材质处理面光源

本方法处理最为简单,基本不用更改原有VXGI的所有流程,仅需在体素化过程中存储自发光材质的相关特性,之后在处理Cone Tracing的时候正常采样体素即可,其中可以自定义材质的Diffuse与Specular来实现不同的材质特性。

1.2 面光源上均匀分布Cone

本方法是NVIDIA VXGI2.0中对VXAL技术的提升,其对外API提供了如下接口可以来更好的设置面光源:

通过上述接口调用,可以直接获取VXAL的相关辐照信息供渲染使用(其中不仅包含LTC光源处理算法,还包括了更多的全局光照技术),其具体原理如下:

  1. 在面光源均匀分布Cone,对采样点贡献,其中影响因素包括着色点距离衰减、光源尺寸影响Cone个数等多重影响

  1. 之后处理相关遮蔽数据:其中对于大比例场景,即clipMap较大体素使用VXAO技术,对细节场景采用屏幕空间阴影技术。

  1. 接下来处理面光源对场景的辐照影响,其中包含Diffuse与Specular两项,并且使用了LTC技术对不规则面光源进行更好的处理(LTC算法后续再具体研究)

  1. 之后调整下遮蔽阴影与光源的融合,可见如下:

  1. 最后将光源材质等信息叠加至场景,可渲染整体如下


最后放一张其官宣演示渲染场景:

本部分主要使用自发光材质实现面光源。

二、代码实现

简单的实现方式可以将面光源当成自发光材质进行处理,在cone tracing的时候正常采样,可根据物体表面材质特性自行控制Diffuse与Specular的占比来实现不同材质表现。

2.1 体素化的处理过程

以下代码主要为体素化PS过程中的处理,重点查看注释部分说明即可。

其中需要注意的是,相对于之前VXGI文章的区别是增加了emissiveMap贴图,并将采样纹理贴图的信息也一并存储到体素中

#version 450 core// 灯光设置.
#define POINT_LIGHT_INTENSITY 1
#define MAX_LIGHTS 1// 灯光设置衰减因子.
#define DIST_FACTOR 1.1f /* Distance is multiplied by this when calculating attenuation. */
#define CONSTANT 1
#define LINEAR 0
#define QUADRATIC 1// 返回给定距离的衰减因子  .
float attenuate(float dist){ dist *= DIST_FACTOR; return 1.0f / (CONSTANT + LINEAR * dist + QUADRATIC * dist * dist); }struct PointLight {vec3 position;vec3 color;
};struct Material {vec3 diffuseColor;vec3 specularColor;float diffuseReflectivity;float specularReflectivity;float emissivity;//自发光特性float transparency;
};
layout(binding = 0) uniform sampler2D emissiveMap;
uniform Material material;
uniform PointLight pointLights[MAX_LIGHTS];
uniform int numberOfLights;
uniform vec3 cameraPosition;
layout(RGBA8) uniform image3D texture3D;in vec3 worldPositionFrag;
in vec3 normalFrag;vec3 calculatePointLight(const PointLight light){const vec3 direction = normalize(light.position - worldPositionFrag);const float distanceToLight = distance(light.position, worldPositionFrag);const float attenuation = attenuate(distanceToLight);const float d = max(dot(normalize(normalFrag), direction), 0.0f);return d * POINT_LIGHT_INTENSITY * attenuation * light.color;
};vec3 scaleAndBias(vec3 p) { return 0.5f * p + vec3(0.5f); }bool isInsideCube(const vec3 p, float e) { return abs(p.x) < 1 + e && abs(p.y) < 1 + e && abs(p.z) < 1 + e; }void main(){vec3 color = vec3(0.0f);if(!isInsideCube(worldPositionFrag, 0)) return;const uint maxLights = min(numberOfLights, MAX_LIGHTS);for(uint i = 0; i < maxLights; ++i) color += calculatePointLight(pointLights[i]);vec3 spec = material.specularReflectivity * material.specularColor;vec3 diff = material.diffuseReflectivity * material.diffuseColor;//体素化过程中存储自发光面光源的特性vec4 emissive = texture(emissiveMap, texCoord.xy);color = (diff + spec) * color + clamp(material.emissivity, 0, 1) * material.diffuseColor * emissive.rgb ;vec3 voxel = scaleAndBias(worldPositionFrag);ivec3 dim = imageSize(texture3D);float alpha = pow(1 - material.transparency, 4); // For soft shadows to work better with transparent materials.vec4 res = alpha * vec4(vec3(color), 1);imageStore(texture3D, ivec3(dim * voxel), res);
}

经过上述处理后对面光源的体素化表示如下:

2.2 Cone Tracing过程的处理

其中主要查看自发光部分的处理即可。

#version 450 core
#define TSQRT2 2.828427
#define SQRT2 1.414213
#define ISQRT2 0.707106
// --------------------------------------
// 光(体素)圆锥跟踪设置.
// --------------------------------------
#define MIPMAP_HARDCAP 5.4f /* mipmap层级,影响渲染效果. */
#define VOXEL_SIZE (1/64.0) /* 体素的大小. 128x128x128 => 1/128 = 0.0078125. */
#define SHADOWS 1 /* 阴影开关. */
#define DIFFUSE_INDIRECT_FACTOR 0.52f /* 漫射间接光照的强度. */
// --------------------------------------
// 其余光照设置.
// --------------------------------------
#define SPECULAR_MODE 1 /* 0 == Blinn-Phong , 1 == reflection model. */
#define SPECULAR_FACTOR 4.0f /* 镜面强度调整因子. */
#define SPECULAR_POWER 65.0f /* 镜面强度粗糙度. */
#define DIRECT_LIGHT_INTENSITY 0.96f /* (直接)点光强度因子. */
#define MAX_LIGHTS 1 /* 灯光数. */// 光照衰减的因子。 可参见函数“attenuate()” .
#define DIST_FACTOR 1.1f /* 在计算衰减时,距离乘以这个系数. */
#define CONSTANT 1
#define LINEAR 0 /* . */
#define QUADRATIC 1// 其他数据.
#define GAMMA_CORRECTION 1 /* 是否使用伽马校正. */// 基础点光源.
struct PointLight {vec3 position;vec3 color;
};// 基础材质.
struct Material {vec3 diffuseColor;float diffuseReflectivity;vec3 specularColor;float specularDiffusion; // “反射和折射”镜面扩散. float specularReflectivity;float emissivity; // 发射材料使用漫射色作为发射色 .float refractiveIndex;float transparency;
};layout(binding = 0) uniform sampler2D gEmissive;struct Settings {bool indirectSpecularLight; // 是否渲染间接反射光.bool indirectDiffuseLight; // 是否渲染间接漫射光.bool directLight; // 是否要渲染直射光.bool shadows; // 是否渲染阴影.
};uniform Material material;
uniform Settings settings;
uniform PointLight pointLights[MAX_LIGHTS];
uniform int numberOfLights; // 灯光数.
uniform vec3 cameraPosition; // 世界空间下相机位置.
uniform int state; // .
uniform sampler3D texture3D; // 体素纹理.in vec3 worldPositionFrag;
in vec3 normalFrag;out vec4 color;vec3 normal = normalize(normalFrag);
float MAX_DISTANCE = distance(vec3(abs(worldPositionFrag)), vec3(-1));// 返回给定距离的衰减因子 .
float attenuate(float dist){ dist *= DIST_FACTOR; return 1.0f / (CONSTANT + LINEAR * dist + QUADRATIC * dist * dist); }// 返回一个正交于u的向量.
vec3 orthogonal(vec3 u){u = normalize(u);vec3 v = vec3(0.99146, 0.11664, 0.05832); // Pick any normalized vector.return abs(dot(u, v)) > 0.99999f ? cross(u, vec3(0, 1, 0)) : cross(u, v);
}// (from [-1, 1] to [0, 1]).
vec3 scaleAndBias(const vec3 p) { return 0.5f * p + vec3(0.5f); }// 如果点p在单位立方体内,返回true  .
bool isInsideCube(const vec3 p, float e) { return abs(p.x) < 1 + e && abs(p.y) < 1 + e && abs(p.z) < 1 + e; }//使用阴影圆锥跟踪返回一个柔和的阴影混合。
//每个步骤使用2个样本,性能开销较大。
float traceShadowCone(vec3 from, vec3 direction, float targetDistance){from += normal * 0.05f; float acc = 0;float dist = 3 * VOXEL_SIZE;// 影响范围大小.const float STOP = targetDistance - 16 * VOXEL_SIZE;while(dist < STOP && acc < 1){    vec3 c = from + dist * direction;if(!isInsideCube(c, 0)) break;c = scaleAndBias(c);float l = pow(dist, 2); // 对阴影进行平方衰减.float s1 = 0.062 * textureLod(texture3D, c, 1 + 0.75 * l).a;float s2 = 0.135 * textureLod(texture3D, c, 4.5 * l).a;float s = s1 + s2;acc += (1 - acc) * s;dist += 0.9 * VOXEL_SIZE * (1 + 0.05 * l);}return 1 - pow(smoothstep(0, 1, acc * 1.4), 1.0 / 1.4);
}   // 追踪漫反射体素锥.
vec3 traceDiffuseVoxelCone(const vec3 from, vec3 direction){direction = normalize(direction);const float CONE_SPREAD = 0.325;vec4 acc = vec4(0.0f);//控制闭合表面漏光情况。  //如果使用阴影圆锥跟踪,较低的值会导致效果很差。    float dist = 0.1953125;// Trace.while(dist < SQRT2 && acc.a < 1){vec3 c = from + dist * direction;c = scaleAndBias(from + dist * direction);float l = (1 + CONE_SPREAD * dist / VOXEL_SIZE);float level = log2(l);float ll = (level + 1) * (level + 1);vec4 voxel = textureLod(texture3D, c, min(MIPMAP_HARDCAP, level));acc += 0.075 * ll * voxel * pow(1 - voxel.a, 2);dist += ll * VOXEL_SIZE * 2;}return pow(acc.rgb * 2.0, vec3(1.5));
}// 追踪高光体素锥.
vec3 traceSpecularVoxelCone(vec3 from, vec3 direction){direction = normalize(direction);const float OFFSET = 8 * VOXEL_SIZE;const float STEP = VOXEL_SIZE;from += OFFSET * normal;vec4 acc = vec4(0.0f);float dist = OFFSET;// Trace.while(dist < MAX_DISTANCE && acc.a < 1){ vec3 c = from + dist * direction;if(!isInsideCube(c, 0)) break;c = scaleAndBias(c); float level = 0.1 * material.specularDiffusion * log2(1 + dist / VOXEL_SIZE);vec4 voxel = textureLod(texture3D, c, min(level, MIPMAP_HARDCAP));float f = 1 - acc.a;acc.rgb += 0.25 * (1 + material.specularDiffusion) * voxel.rgb * voxel.a * f;acc.a += 0.25 * voxel.a * f;dist += STEP * (1.0f + 0.125f * level);}return 1.0 * pow(material.specularDiffusion + 1, 0.8) * acc.rgb;
}//使用体素锥追踪计算间接漫射光。当前的实现与展示的一样使用9个圆锥。   vec3 indirectDiffuseLight(){const float ANGLE_MIX = 0.5f; // 角度混合(1.0f =>正交方向,0.0f =>法线方向)  .const float w[3] = {1.0, 1.0, 1.0}; // 锥的权重.// 求边锥的底,法向量为其底向量之一.const vec3 ortho = normalize(orthogonal(normal));const vec3 ortho2 = normalize(cross(ortho, normal));// 求角锥的基向量.const vec3 corner = 0.5f * (ortho + ortho2);const vec3 corner2 = 0.5f * (ortho - ortho2);//找到跟踪的起始位置(从偏移量开始)   .const vec3 N_OFFSET = normal * (1 + 4 * ISQRT2) * VOXEL_SIZE;const vec3 C_ORIGIN = worldPositionFrag + N_OFFSET;// 累积间接漫射光用.vec3 acc = vec3(0);//我们在法线方向上向前偏移,在圆锥方向上向后偏移。  //向后锥体方向可以改善GI,而向前方向可以移除artifacts。 const float CONE_OFFSET = -0.01;// 追踪前锥acc += w[0] * traceDiffuseVoxelCone(C_ORIGIN + CONE_OFFSET * normal, normal);// 追踪4个边锥.const vec3 s1 = mix(normal, ortho, ANGLE_MIX);const vec3 s2 = mix(normal, -ortho, ANGLE_MIX);const vec3 s3 = mix(normal, ortho2, ANGLE_MIX);const vec3 s4 = mix(normal, -ortho2, ANGLE_MIX);acc += w[1] * traceDiffuseVoxelCone(C_ORIGIN + CONE_OFFSET * ortho, s1);acc += w[1] * traceDiffuseVoxelCone(C_ORIGIN - CONE_OFFSET * ortho, s2);acc += w[1] * traceDiffuseVoxelCone(C_ORIGIN + CONE_OFFSET * ortho2, s3);acc += w[1] * traceDiffuseVoxelCone(C_ORIGIN - CONE_OFFSET * ortho2, s4);// 追踪4个中心锥.const vec3 c1 = mix(normal, corner, ANGLE_MIX);const vec3 c2 = mix(normal, -corner, ANGLE_MIX);const vec3 c3 = mix(normal, corner2, ANGLE_MIX);const vec3 c4 = mix(normal, -corner2, ANGLE_MIX);acc += w[2] * traceDiffuseVoxelCone(C_ORIGIN + CONE_OFFSET * corner, c1);acc += w[2] * traceDiffuseVoxelCone(C_ORIGIN - CONE_OFFSET * corner, c2);acc += w[2] * traceDiffuseVoxelCone(C_ORIGIN + CONE_OFFSET * corner2, c3);acc += w[2] * traceDiffuseVoxelCone(C_ORIGIN - CONE_OFFSET * corner2, c4);// 返回结果return DIFFUSE_INDIRECT_FACTOR * material.diffuseReflectivity * acc * (material.diffuseColor + vec3(0.001f));
}// 使用体素圆锥追踪计算间接镜面光。
vec3 indirectSpecularLight(vec3 viewDirection){const vec3 reflection = normalize(reflect(viewDirection, normal));return material.specularReflectivity * material.specularColor * traceSpecularVoxelCone(worldPositionFrag, reflection);
}// 使用体素锥追踪计算折射光 .
vec3 indirectRefractiveLight(vec3 viewDirection){const vec3 refraction = refract(viewDirection, normal, 1.0 / material.refractiveIndex);const vec3 cmix = mix(material.specularColor, 0.5 * (material.specularColor + vec3(1)), material.transparency);return cmix * traceSpecularVoxelCone(worldPositionFrag, refraction);
}//计算一个给定点光的漫反射和镜面直射光。
//使用阴影圆锥跟踪软阴影。
vec3 calculateDirectLight(const PointLight light, const vec3 viewDirection){vec3 lightDirection = light.position - worldPositionFrag;const float distanceToLight = length(lightDirection);lightDirection = lightDirection / distanceToLight;const float lightAngle = dot(normal, lightDirection);// --------------------// Diffuse lighting.// --------------------float diffuseAngle = max(lightAngle, 0.0f); // Lambertian.  // --------------------// Specular lighting.// --------------------
#if (SPECULAR_MODE == 0) /* Blinn-Phong. */const vec3 halfwayVector = normalize(lightDirection + viewDirection);float specularAngle = max(dot(normal, halfwayVector), 0.0f);
#endif#if (SPECULAR_MODE == 1) /* Perfect reflection. */const vec3 reflection = normalize(reflect(viewDirection, normal));float specularAngle = max(0, dot(reflection, lightDirection));
#endiffloat refractiveAngle = 0;if(material.transparency > 0.01){vec3 refraction = refract(viewDirection, normal, 1.0 / material.refractiveIndex);refractiveAngle = max(0, material.transparency * dot(refraction, lightDirection));}// --------------------// Shadows.// --------------------float shadowBlend = 1;
#if (SHADOWS == 1)if(diffuseAngle * (1.0f - material.transparency) > 0 && settings.shadows)shadowBlend = traceShadowCone(worldPositionFrag, lightDirection, distanceToLight);
#endif// --------------------// 光照叠加.// --------------------diffuseAngle = min(shadowBlend, diffuseAngle);specularAngle = min(shadowBlend, max(specularAngle, refractiveAngle));const float df = 1.0f / (1.0f + 0.25f * material.specularDiffusion); // Diffusion factor.const float specular = SPECULAR_FACTOR * pow(specularAngle, df * SPECULAR_POWER);const float diffuse = diffuseAngle * (1.0f - material.transparency);const vec3 diff = material.diffuseReflectivity * material.diffuseColor * diffuse;const vec3 spec = material.specularReflectivity * material.specularColor * specular;const vec3 total = light.color * (diff + spec);return attenuate(distanceToLight) * total;
};// 累加所有来自点光源的直接光线(包括漫射和镜面) .
vec3 directLight(vec3 viewDirection){vec3 direct = vec3(0.0f);const uint maxLights = min(numberOfLights, MAX_LIGHTS);for(uint i = 0; i < maxLights; ++i) direct += calculateDirectLight(pointLights[i], viewDirection);direct *= DIRECT_LIGHT_INTENSITY;return direct;
}void main(){color = vec4(0, 0, 0, 1);const vec3 viewDirection = normalize(worldPositionFrag - cameraPosition);// 间接的漫射光.if(settings.indirectDiffuseLight && material.diffuseReflectivity * (1.0f - material.transparency) > 0.01f) color.rgb += indirectDiffuseLight();// 间接镜面光(镜面反射).if(settings.indirectSpecularLight && material.specularReflectivity * (1.0f - material.transparency) > 0.01f) color.rgb += indirectSpecularLight(viewDirection);// 采样自发光贴图vec3 emissive = texture(gEmissive, texCoord).rgb;// 自发光.color.rgb += material.emissivity * emissive ;// 透明if(material.transparency > 0.01f)color.rgb = mix(color.rgb, indirectRefractiveLight(viewDirection), material.transparency);// 直接光照.if(settings.directLight)color.rgb += directLight(viewDirection);#if (GAMMA_CORRECTION == 1)color.rgb = pow(color.rgb, vec3(1.0 / 2.2));
#endif
}

处理完之后,可如下渲染结果:

Global Illumination_Voxel Area Lighting (VXAL)相关推荐

  1. Global Illumination_Spherical Harmonic Lighting(球谐光照)

    首先我们需要知道的是,如何计算环境光shading,一般我们会想到IBL,其实我们也可以使用球谐函数来进行表示,本部分我们就先来了解下如何使用SH来计算环境光照(后续我们也会继续来看一下环境光阴影的计 ...

  2. Global Illumination_Voxel Global Illumintaion (VXGI)

    我们本次来看一下VXGI技术,首先了解一下其基本情况:Parse Voxel Octree GI(又叫Voxel Cone Tracing)和VXGI都是NVIDIA的技术,VXGI就是SVOGI最终 ...

  3. Image-based Lighting approaches and parallax-corrected cubemap

    Image-based Lighting approaches and parallax-corrected cubemap SEPTEMBER 29, 2012 25 COMMENTS Versio ...

  4. Cubemaps相关

    使用 Cubmap 可以模拟出环境的反射,预先将环境渲染到 Cubmap 中,从而避免在游戏运行时对环境的实时反射产生的消耗,而且这样做表现效果也非常好.在一些户外环境尤其适用,比如说车身反射外部的环 ...

  5. c/c++内存机制(一)(原)

    一:C语言中的内存机制 在C语言中,内存主要分为如下5个存储区: (1)栈(Stack):位于函数内的局部变量(包括函数实参),由编译器负责分配释放,函数结束,栈变量失效. (2)堆(Heap):由程 ...

  6. CMA内存管理子系统

    转:http://www.wowotech.net/memory_management/cma.html 前言 本文是近期学习CMA模块的一个学习笔记,方便日后遗忘的时候,回来查询以便迅速恢复上下文. ...

  7. 详解操作系统中虚拟内存与物理内存的关系

    点击链接: 一文理解虚拟内存.物理内存.内存分配.内存管理 - 知乎 目录 一.虚拟内存与物理内存 1.1 虚拟内存 1.2 虚拟内存与物理内存 二.C/C++中虚拟内存分配模型 2.1 C语言中内存 ...

  8. 部分网站公开数据的汇总(2)

    数据整理 1.Natural Earth Data Natural Earth Data提供了全球范围内的矢量和影像数据.Natural Earth Data的最大优势就是数据是开放性的,用户有传播和 ...

  9. POJ3130(还是判断多边形的内核是否存在)

    题目:How I Mathematician Wonder What You Are! 题意:给一个多边形,判断它是否是星形多边形,星形多边形的定义就是:如果在多边形内部能够找到一点能观察到多边形边上 ...

最新文章

  1. matlab---边缘之sobel简单实例
  2. 03、NavMesh--导航网格寻路
  3. 学python好找工作嘛-Python开发学完好找工作吗?
  4. wxWidgets:wxAuiNotebookEvent类用法
  5. linux5.5 dvd安装教程,linux 5.5 yum的安装方法(ftp)
  6. 深入 Lucene 索引机制
  7. LinkCutTree 总结
  8. phaser java_【Java并发编程实战】-----“J.U.C”:Phaser
  9. linux通过操作界面和命令行的方式查看ip地址、mac地址
  10. 博弈论与最优化的关系
  11. 数据分析(Data Analysis)
  12. Spring框架详解
  13. Vue.js框架(二)
  14. EduCoder-Web程序设计基础-html5-表格基本结构-第4关:表格中单元格样式的设置
  15. 作家天地杂志作家天地杂志社作家天地编辑部2022年第23期目录
  16. Spring5 框架新功能(Webflux)
  17. JAVA正则表达式,matcher.find()和 matcher.matches()的区别
  18. OC5038内置 MOS 开关降压型 LED 恒流驱动器
  19. append、appendTo、appendChild、prepend
  20. Linux日常软件安装(FC6)

热门文章

  1. m1芯片 mysql_苹果M1芯片各种不支持,但居然可以刷朋友圈!你会买单吗?
  2. 九联UNT402A_S905L_S905L3通刷版线刷固件包及优盘刷机包
  3. vue项目打包后直接修改ip地址
  4. Vue 动态绑定组件
  5. 关于使用fgetc函数和feof函数的一些注意事项
  6. noip 2018 做题记录
  7. zabbix监控nginx
  8. fgets()、gets()、EOF、feof()
  9. 企业网络会议室解决方案-VIP会议室解决方案
  10. 搭建属于自己的翻译系统