NeRD反射率分解是怎样分离漫反射与高光的?

来源:站长查询作者:向日葵头衔:草根站长
导读:本期聚焦于向日葵创作的《NeRD反射率分解是怎样分离漫反射与高光的?》,敬请观看详情。同一张照片里物体表面往往既有一层稳定的基底颜色,又有随视角移动的亮斑。前者来自漫反射,后者来自高光反射。想把三维场景材质编辑得干净,就需要把这两类信号拆开。NeRD的做法不是先重建网格再逐像素优化BRDF,而是用神经反射场同时表达几何、反照率、粗糙度和法线。网络对每个空间点输出漫反射反照率,对每个观察方向计算镜面高光项,再通过体积渲染合成像素颜色。训练时多视角图像的光度损失会自然驱动漫反射负责低频颜色、高光负责视角相关亮斑。分离后可以得到无高光污染的反照率贴图,也能独立修改粗糙度或重新打光。相比传统方法,它不需要高精度网格和复杂的光源标定,更适合真实拍摄数据。

在多视角三维重建里,很多系统最终交付的是一张带颜色的网格或点云。但这个颜色并不是材质本身,而是材质在特定光照和视角下的综合结果。如果场景里有一盏灯在金属表面留下高光,重建结果往往会把这块亮斑直接烘焙到纹理中,一旦换到新光照环境,高光不会跟着视线移动,反而变成一块发白的污渍。解决这个问题的关键是反射率分解,也就是把表面出射光拆成漫反射部分和高光部分。NeRD在这条路上引入了神经反射场的思路,让漫反射反照率与视角相关高光可以在没有显式网格的情况下被分离出来。

NeRD反射率分解是怎样分离漫反射与高光的?

反射率分解为什么不能只靠颜色

从物理上看,漫反射和镜面反射遵循完全不同的规律。漫反射可以粗略理解为光进入表面浅层后发生多次散射,再以接近均匀的角度分布射出,因此从不同方向观察时颜色变化很小。它主要由表面反照率决定,也就是物体本来的颜色。镜面反射则发生在空气与材质的分界面上,入射光的一部分直接按反射方向弹出。对光滑表面,这个反射能量集中在一个很窄的角度范围内,观察者只有在特定位置才能看到高光;对粗糙表面,高光会被散射到更宽的范围,看起来更柔和。BRDF用函数描述这种方向相关行为,通常写作入射方向和出射方向的四维函数。

普通相机拍摄的图像没有直接记录哪部分能量来自漫反射,哪部分来自高光。像素值只是两者的线性叠加。若没有额外约束,仅凭几张照片做逆渲染会遇到严重的歧义:一个白色亮斑可能是浅色漫反射表面,也可能是深色光滑表面的镜面高光。过去的方法往往依赖受控光源、交叉偏振镜或者大量采样来降低歧义。NeRD的核心贡献之一,就是把这种物理先验写进网络结构,让模型在没有复杂采集设备的条件下也能完成稳定分解。

对下游应用来说,漫反射和高光分离的直接价值非常明显。重光照时漫反射项需要保留,而高光项要根据新光源位置重新计算;材质编辑时如果只改反照率而高光里仍混着旧颜色,结果就会不真实。因此分离质量直接决定三维资产能否跨光照复用。

NeRD的神经反射场结构

NeRD并没有先重建一个完整网格再做逐面片优化,而是采用类似神经辐射场的隐式场景表示。模型接收一个空间坐标和一个观察方向,先通过MLP提取该点的几何特征,再预测该点的漫反射反照率、镜面粗糙度等材质参数。法线不直接由材质网络输出,而是通过体积密度关于空间坐标的梯度计算得到。这样法线与几何保持一致性,不会出现材质网络随意输出一个法线导致高光方向错误的情况。

材质预测部分通常会把反照率限制在0到1之间,粗糙度也通过Sigmoid压缩到合理区间。镜面高光采用微表面BRDF模型计算,比如GGX分布。与直接预测颜色的NeRF变体相比,NeRD的中间表示具有明确物理含义,因此即使训练视角有限,也更容易泛化到新光照。

import torch
import torch.nn as nn

class NeRDMaterial(nn.Module):
    def __init__(self, pos_dim=63, dir_dim=27, hidden=256):
        super().__init__()
        self.geo_net = nn.Sequential(
            nn.Linear(pos_dim, hidden),
            nn.ReLU(),
            nn.Linear(hidden, hidden),
            nn.ReLU(),
            nn.Linear(hidden, hidden),
            nn.ReLU(),
        )
        self.mat_head = nn.Sequential(
            nn.Linear(hidden, hidden),
            nn.ReLU(),
            nn.Linear(hidden, 4),
        )
        self.dir_net = nn.Sequential(
            nn.Linear(dir_dim + hidden, hidden),
            nn.ReLU(),
            nn.Linear(hidden, hidden),
        )

    def forward(self, pos_enc, dir_enc):
        geo_feat = self.geo_net(pos_enc)
        mat_raw = self.mat_head(geo_feat)
        albedo = torch.sigmoid(mat_raw[:, :3])
        roughness = torch.sigmoid(mat_raw[:, 3:4])
        view_feat = self.dir_net(torch.cat([dir_enc, geo_feat], dim=-1))
        return albedo, roughness, view_feat, geo_feat

上面的代码只是网络主干示意。NeRD在输入层使用位置编码,让MLP更容易表达高频几何和材质变化。geo_net输出的特征会同时用于体积密度预测和材质预测,促使共享表示既尊重表面位置,也尊重表面属性。dir_net则把观察方向与几何特征融合,为后续视角相关高光计算提供基础。

这个结构的关键好处是,反照率不接收观察方向输入,因此它天然被约束为视角无关量;而高光相关计算必须依赖观察方向。通过这种输入设计,网络在训练开始前就已经被诱导成正确的分解形式,后续光度损失只需要进一步细化数值。

渲染方程中的显式分离

NeRD最终的像素颜色需要经过体积渲染。沿一条光线采样若干空间点,先由密度场计算每个点的占据权重,然后对各个点的出射辐射加权求和。出射辐射由漫反射项和镜面反射项组成。漫反射项可以近似为反照率除以圆周率再乘以入射辐照度。在自然光照或简单点光源假设下,入射辐照度可以用球面谐波或者直接对光源方向积分得到。镜面反射项则使用微表面BRDF,包含法线、视角方向、光源方向和粗糙度。

下面的计算示意展示了一个点光源场景中的颜色合成。漫反射部分只与法线和光源方向有关,与观察方向无关;镜面部分同时依赖法线、光源方向和观察方向。

import torch

def safe_normalize(x, eps=1e-8):
    return x / (torch.norm(x, dim=-1, keepdim=True) + eps)

def ggx_specular(normal, view_dir, light_dir, roughness):
    half = safe_normalize(view_dir + light_dir)
    n_dot_h = torch.clamp(torch.sum(normal * half, dim=-1, keepdim=True), min=0.0)
    n_dot_v = torch.clamp(torch.sum(normal * view_dir, dim=-1, keepdim=True), min=0.0)
    n_dot_l = torch.clamp(torch.sum(normal * light_dir, dim=-1, keepdim=True), min=0.0)
    alpha = roughness * roughness
    alpha2 = alpha * alpha
    denom = n_dot_h * n_dot_h * (alpha2 - 1.0) + 1.0
    d = alpha2 / (3.1415926 * denom * denom + 1e-8)
    f = 0.04 + 0.96 * (1.0 - n_dot_v) ** 5
    g = 0.5 / (n_dot_v * (1.0 - roughness) + roughness)
    specular = d * f * g / (4.0 * n_dot_v * n_dot_l + 1e-8)
    return specular

def shading(albedo, normal, view_dir, light_dir, roughness, light_intensity):
    diffuse = albedo / 3.1415926
    diffuse_term = diffuse * torch.clamp(torch.sum(normal * light_dir, dim=-1, keepdim=True), min=0.0)
    specular_term = ggx_specular(normal, view_dir, light_dir, roughness)
    color = light_intensity * (diffuse_term + specular_term)
    return color

实际训练时,NeRD通常会把场景光照表示为一组可学习的球面高斯或一个环境图,而不是简单点光源。这样能处理真实拍摄中来自窗户、天空和室内灯的复杂光照。无论光照表示如何变化,漫反射与高光的分离逻辑保持一致:漫反射分支对观察方向不敏感,高光分支则显式建模视角相关反射。

在体积渲染阶段,每个采样点计算一次颜色和密度,再按透明度混合。由于高光项在单个点上可能数值很大,网络需要学会把大亮度分配给高光分支而不是反照率。否则输出颜色虽然也能拟合训练图像,但反照率贴图会被高光污染。

训练损失与正则化约束

仅靠像素颜色重建损失并不总能保证分离干净。比如一个纯白色表面在固定光照下某处亮度很高,网络可以把该点反照率设为0.8、高光设为0.2,也可以把反照率设为1.0、高光设为0.0,两者渲染结果相同。为了消除这类歧义,NeRD引入了几类正则项。

第一项是反照率平滑损失,鼓励相邻表面点的漫反射颜色变化缓慢。真实材质中反照率通常具有局部连续性,而高光可以随曲率快速变化。第二项是粗糙度先验,防止网络把所有表面都预测成极端镜面或极端漫反射。第三项有时会对高光残差施加稀疏约束,只允许少数区域出现强高光,而不是整个场景平均分摊高光能量。部分实现还会对法线方向与密度梯度方向做一致性约束,保证材质和几何不脱节。

def total_loss(render_pred, pixel_gt, albedo, roughness, normal, grad_normal):
    color_loss = torch.mean((render_pred - pixel_gt) ** 2)
    albedo_smooth = torch.mean((albedo[1:] - albedo[:-1]) ** 2)
    normal_consist = torch.mean((normal - grad_normal) ** 2)
    roughness_reg = torch.mean((roughness - 0.5) ** 2)
    loss = color_loss + 0.01 * albedo_smooth + 0.05 * normal_consist + 0.001 * roughness_reg
    return loss

这些权重需要根据场景规模调整。如果平滑项过强,反照率会丢失纹理细节;如果粗糙度正则过强,金属和塑料的差异会被抹平。这种平衡是NeRD类方法在实际部署时的主要调参工作。

与直接使用NeRF颜色场的方法相比,NeRD的损失函数要求网络在中间层就满足物理结构,因此对训练视角数量的要求更低。即使某些高光只在极少数输入视图中出现,只要几何和材质先验足够,网络也能推断出合理的漫反射基底。

实际效果与限制

经过训练后,NeRD可以输出每个空间点的反照率、粗糙度和法线。把反照率单独可视化时,高光亮斑会消失,剩下干净的基底颜色。把粗糙度降低会让高光范围变窄、材质看起来更光滑;旋转光源时,高光会根据新光照方向重新出现,而漫反射阴影也随之更新。这种编辑能力在增强现实、电影虚拟资产和游戏材质生成中非常实用。

不过NeRD也有明显限制。首先是输入要求多视角图像覆盖足够的观察方向和光照变化,如果所有照片都来自同一角度或同一光照,高光和漫反射仍然难以区分。其次,对于非常复杂的半透明材质、各向异性材质或多次散射明显的材质,当前模型假设的BRDF形式不够灵活。最后,体积渲染的训练和推理成本比传统网格纹理高得多,移动端实时运行还需要进一步蒸馏或烘焙。

即便如此,NeRD代表的方向很清晰:与其让网络黑箱预测颜色,不如把物理反射模型嵌入神经渲染框架。这样既能利用深度学习的表达能力处理真实图像,又能保留可解释、可编辑的材质参数。漫反射与高光分离不再依赖实验室级采集,普通多视角照片也能成为材质重建的输入来源。

NeRD反射率分解漫反射与高光分离修改时间:2026-10-03 05:56:22

免责声明:已尽一切努力确保本网站所含信息的准确性。网站作品多为原创整理与精心创作,观点力求客观中立。本站旨在免费分享,内容仅供个人学习、研究或参考使用。若引用了第三方作品,版权归原作者所有。如内容涉及您的权益,请联系我们进行处理Email:chomcom@qq.com。
引用或转载本作品时,请注明当前出处:https://www.ipipp.com/html/1003/64978.html,基于非商业用途的前提下,欢迎转载或二创本作品。
内容垂直聚焦
专注技术核心技术栏目,确保每篇文章深度聚焦于实用技能。从代码技巧到架构设计,为用户提供无干扰的纯技术知识沉淀,精准满足专业提升需求。
知识结构清晰
覆盖从开发到部署的全链路。AI、前端、编程、数据库、服务器、建站、系统层层递进,构建清晰学习路径,帮助用户系统化掌握开发与运维所需的核心技术。
深度技术解析
拒绝泛泛而谈,深入技术细节与实践难点。无论是数据库优化还是服务器配置,均结合真实场景与代码示例进行剖析,致力于提供可直接应用于工作的解决方案。
专业领域覆盖
精准对应开发生命周期。从前端界面到后端编程,从数据库操作到服务器运维,形成完整闭环,一站式满足全栈工程师和运维人员的技术需求。
即学即用高效
内容强调实操性,步骤清晰、代码完整。用户可根据教程直接复现和应用于自身项目,显著缩短从学习到实践的距离,快速解决开发中的具体问题。
持续更新保障
专注既定技术方向进行长期、稳定的内容输出。确保各栏目技术文章持续更新迭代,紧跟主流技术发展趋势,为用户提供经久不衰的学习价值。