首页 > 其他分享 >几个实用渲染技术原理和实现

几个实用渲染技术原理和实现

时间:2024-11-20 21:56:04浏览次数:1  
标签:return 渲染 float 0.5 实用 x2 原理 1.0 const

一、快速高斯模糊

1.1 背景

​ ​​  高斯模糊在wiki上定义为一种图像模糊滤波器,使用正态分布计算每个像素输出颜色。正态分布函数和图像如下所示:

\[G(u,v)=\frac{1}{2\pi\delta^2}e^{(-u^2+v^2)/(2\delta^2)} \]

​ ​​  由图可以发现,当x在\(-3\delta\)到\(3\delta\)的时候,函数曲线已经很平滑了,实际运用中大概只采样半径为\(3\delta\)内的像素计算。模糊的过程如下:

​ ​​  ​​  a. 输入当前像素的\(u v\)坐标

​ ​​  ​​  b. 遍历半径为\(3\delta\)内的像素,代入高斯函数中计算得到权重\(w_i\)

​ ​​  ​​  c. 将当前遍历的像素颜色乘以权重:\(w_i*(r,g,b)\)

​ ​​  ​​  d. 将所有颜色求和,并除以权重的和$\frac{\Sigma{w_i*(r,g,b)}}{\Sigma{w_i}} $

1.2 简化过程

​ ​​  高斯模糊算法因为线性可分,可以在二维图像上对两个独立的一维空间分别计算。对于矩形阴影这样的利用高斯模糊实现的效果,可以取捷径将高斯函数写成如下分段函数形式:

// =============================================================================
// approximation to the gaussian integral [x, infty)
// =============================================================================
static finline float gi(float x)
{
    const float i6 = 1.f / 6.0;
    const float i4 = 1.f / 4.0;
    const float i3 = 1.f / 3.0;
    if (x > 1.5) return 0.0;
    if (x < -1.5) return 1.0;
    float x2 = x * x;
    float x3 = x2 * x;
    if (x >  0.5) return .5625  - ( x3 * i6 - 3 * x2 * i4 + 1.125 * x);
    if (x > -0.5) return 0.5    - (0.75 * x - x3 * i3); // else
                  return 0.4375 + (-x3 * i6 - 3 * x2 * i4 - 1.125 * x);
}

​ ​​  也就是说对于如下图所示的单色边缘交界面,我们可以通过这个函数快速计算得到中间过渡带函数值,其效果和利用高斯函数多次采样纹理的一致。

1.3 shader实现

uniform sample2D baseTexture;
in  vec2 texCoord;
out vec4 fragColor;
// approximation to the gaussian integral [x, infty)  
float gi(float x) {
	float i6 = 1.0 / 6.0;
	float i4 = 1.0 / 4.0;
	float i3 = 1.0 / 3.0;

    if (x > 1.5) return 0.0;
    if (x < -1.5) return 1.0;

    float x2 = x * x;
    float x3 = x2 * x;
    
    if (x >  0.5) return .5625  - ( x3 * i6 - 3. * x2 * i4 + 1.125 * x);
    if (x > -0.5) return 0.5    - (0.75 * x - x3 * i3);
    return 0.4375 + (-x3 * i6 - 3. * x2 * i4 - 1.125 * x);
}
// create a line shadow mask
float lineShadow(vec2 border, float pos , float sigma) {
    float pos1 = ((border.x - pos) / sigma) * 1.5;
    float pos2 = ((pos - border.y) / sigma) * 1.5;
  	return 1.0 - abs(gi(pos1) - gi(pos2));
}
void main()
{
	vec4 texCol1=texture(baseTexture,texCoord);
	vec4 texCol2=texture(baseTexture,((texCoord-0.5)*2.0*1.5+1.0)*0.5);
	float lineV=lineShaow(vec2(0.18,0.82),texCoord.x,0.05);
	float lineH=lineShaow(vec2(0.2,0.8),texCoord.y,0.24);
	float dist=dot(texCoord,vec2(1.0,1.0));
	vec3 edgeCol=mix(vec3(0.8,0.9,0.8),vec3(0.0),lineV*lineH*smoothstep(1.5,0.5,dist));
	edgeCol=mix(edgeCol,texCol2.rgb,texCol2.a);
	fragColor=vec4(edgeCol,texCol1.a*mix(lineV*lineH,texCol2.a,texCol2.a));
}

二、色调映射(Tone Mapping)

2.1 背景

​ ​​  色调映射就是让亮的场景变暗,暗的场景变亮,并且保存尽可能多的细节。如下图所示,右上角的图像曝光大,亮度高而右下角图像曝光少,亮度低,通过色调映射算法可以将两者亮度范围综合到一起,显示如左侧图像一样,细节看得更清楚。

2.2 Reinhard tone mapping

​ ​​  经验公式如下:

float3 ReinhardToneMapping(float3 color, float adapted_lum) 
{
    const float MIDDLE_GREY = 1;
    color *= MIDDLE_GREY / adapted_lum;
    return color / (1.0f + color);
}

​ ​​  解释为输入一个较小亮度0.1时,输出为0.091,当输入一个较大的亮度10时,输出为0.91。也就是归一化到了0到1区间,但是原本的亮度都变暗了。

2.3 Filmic tone mapping

​ ​​  拟合的公式如下:

float3 F(float3 x)
{
	const float A = 0.22f;
	const float B = 0.30f;
	const float C = 0.10f;
	const float D = 0.20f;
	const float E = 0.01f;
	const float F = 0.30f;

	return ((x * (A * x + C * B) + D * E) / (x * (A * x + B) + D * F)) - E / F;
}

float3 Uncharted2ToneMapping(float3 color, float adapted_lum)
{
	const float WHITE = 11.2f;
	return F(1.6f * adapted_lum * color) / F(WHITE);
}

​ ​​  大部分游戏中用的方法,优点是相比较Reinhard有更大的对比度,颜色更鲜艳一些,缺点是运算量比较大。

三、伽马校正(gamma correction)

3.1 背景

​ ​​  早期的CRT显示器输入0.5的值,输出显示的并不是0.5,而是约等于0.218,进行了伽马系数2.2的幂次运算,这称为伽马校正。为了得到正确的输出,需要先乘以1/2.2的补偿运算。伽马校正除了解决早期CRT显示器的非线性输出问题,同时可以帮我们改善输出的图像质量,因为人眼对较暗的亮度值比较敏感,因此现在仍然保留这一过程。

​​  假如我们要存储0.24和0.243这两个亮度值,如果不进行伽马校正则有\(0.24*255=61 0.243*255=61\),输出结果一样;而使用伽马校正后有

\[0.24^{\frac{1}{2.2}}*255=133 \\ 0.243^{\frac{1}{2.2}}*255=134 \]

​ ​​  伽马校正增大了较暗数值的表示精度,而减小了较亮数值的表示精度, 人眼又恰好对较暗数值比较敏感,对较亮数值不太敏感,于是从视觉角度讲,输出的图像质量就被伽马校正”改善”了

标签:return,渲染,float,0.5,实用,x2,原理,1.0,const
From: https://www.cnblogs.com/wangxydela/p/18559436

相关文章

  • OpenLayers教程11_在OpenLayers中启用WebGL渲染
    在OpenLayers中启用WebGL渲染:提高地图渲染性能的完整指南目录一、引言二、WebGL渲染在WebGIS中的作用WebGL的优势WebGL与Canvas渲染的区别三、在OpenLayers中启用WebGL的方法四、代码实现步骤1.初始化地图和基本WebGL渲染2.加载大规模点数据3.自......
  • OpenLayers教程12_WebGL自定义着色器:实现高级渲染效果
    在OpenLayers中使用WebGL自定义着色器实现高级渲染效果目录一、引言二、WebGL自定义着色器的优势三、示例应用:实现动态渲染效果1.项目结构2.主要代码实现3.运行与效果四、代码讲解与扩展1.动态圆的半径和填充颜色2.动态透明度与边框效果五、总结六、参考资......
  • 开源模型应用落地-LangChain实用小技巧-检索器-集成多种检索器(十八)
    一、前言   在LangChain中,检索器是一个重要模块,主要用于从数据源中检索与查询相关的文档或片段。它能高效进行信息检索,通过快速筛选和语义理解从大规模文本数据中找到相关内容,支持复杂应用场景如检索增强生成和多源数据整合,还具有可定制性和灵活性,可选择不同嵌入模型和索......
  • 如何快速开发一个简单实用的MES系统?
    如题「如何快速开发一个简单实用的MES系统?」,根据问题背景,题主所在光伏组件工厂做生产管理,需开发一个简单的MES系统,希望可实现对生产计划下的产品追踪生产状态,位于的工序,非专业IT,想问选什么工具可以实现快速开发。看了一些回答,大部分回答开发需要有IT经验和充足预算,需要有编......
  • 按键原理
    单片机最小系统解析电源我们要使用STC89C52RC单片机的时候,找到它的数据手册第11页,看第二项--工作电压:5.5V~3.4V(5V单片机),这个地方就说明这个单片机正常的工作电压是个范围值,只要电源VCC在5.5V~3.4V之间都可以正常工作,电压超过5.5V是绝对不允许的,会烧坏单片机,电压如果低于3......
  • 深入解析 PyTorch 的 BatchNorm2d:原理与实现
    在深度学习中,BatchNormalization是一种常用的技术,用于加速网络训练并稳定模型收敛。本文将结合一个具体代码实例,详细解析PyTorch中BatchNorm2d的实现原理,同时通过手动计算验证其计算过程,帮助大家更直观地理解BatchNorm的工作机制。1.BatchNormalization的基本原理1.......
  • 深入解析 ResNet:实现与原理
    ResNet(ResidualNetwork,残差网络)是深度学习领域中的重要突破之一,由KaimingHe等人在2015年提出。其核心思想是通过引入残差连接(skipconnections)来缓解深层网络中的梯度消失问题,使得网络可以更高效地训练,同时显著提升了深度网络的性能。本文以一个ResNet的简单实现为例,详细......
  • 想要给文件加密?这8款实用的文件加密软件2024办公必备
    在当今信息化的社会中,数据安全越来越受到重视,无论是企业用户还是个人用户,都希望通过加密来保护文件的隐私和安全。以下为您整理了8款实用的文件加密软件,每款工具都功能强大,使用便捷,助您在2024年轻松保障数据安全。1.安秉网盾适合人群:企业用户安秉网盾文件加密是一款高效、......
  • 【Java】使用Socket手搓三次握手 从原理到实践
    【Java】使用Socket手搓三次握手从原理到实践本身这次打算将三次握手、四次挥手都做出来。但发现内容越来越多了,所以就只实现了三次握手。但依然为后续操作做了大量的铺垫。系列文章:使用Socket在局域网中进行广播【Java】使用Socket实现查找IP并建立连接?手把手教你【J......
  • Spring AOP原理
     博主主页: 码农派大星.  数据结构专栏:Java数据结构 数据库专栏:MySQL数据库JavaEE专栏:JavaEE软件测试专栏:软件测试关注博主带你了解更多知识 目录前言:SpringAOP是基于动态代理来实现AOP的1.代理模式代理模式的主要角色 代理模式的类型动态代理......