【发布时间】:2022-11-01 10:41:57
【问题描述】:
我正在编写一个在 Windows 上运行的 CPU 光线追踪器。不幸的是,当前的输出似乎太暗了,就像我缺少全局照明一样。
这是一个内部房间,照明来自 2 个窗户。只有一种定向光。光反弹次数设置为 8。
这是我的路径跟踪器输出:
搅拌机循环输出:
虽然直接照明很好,但感觉就像我缺少全局照明。但为什么?
这是示例代码:
RGBColor pathTracing(const Math::Ray& ray, nbUint32 depth)
{
// Find intersection using intel's Embree
Intersector::IntersectionInfo isectInfo;
m_intersector->intersect(ray, isectInfo);
// Check if an intersection occured
if (isectInfo.object == nullptr)
{
return BlackRGBColor;
}
// Get intersection properties
const auto isectProps = buildIntersectionProperties(ray, isectInfo, m_currentScene);
// The scene model
const auto& model = m_currentScene->getModel();
// Read the material
const DatabaseMaterialPtr material = model->getMaterialPtr_FromEntity(isectInfo.object->getMaterialId());
// Compute direct lighning
RGBColor directCont = BlackRGBColor;
{
for (const EntityIdentifier& lightId : m_currentScene->getLights())
{
// Generate light sample
const auto light = Entity::EntityDatabaseSingleton::instance()->getEntity<Light::BaseLight>(lightId);
const auto sampleToLight = light->generateSampleToLight(isectProps.P);
const nbFloat32 NoL = glm::dot(isectProps.BsdfProps.N, sampleToLight.L);
if (NoL <= 0.0f)
continue;
// Compute occlusion
Math::Ray shadowRay(isectProps.deltaP, sampleToLight.L, sampleToLight.length);
const nbFloat32 occlusionStrength = m_intersector->occlusion(shadowRay);
if (occlusionStrength != 1.0f)
{
// Build the bsdf sample struture
Material::BaseMaterial::SampleBsdfData bsdfSample;
bsdfSample.L = sampleToLight.L;
bsdfSample.V = isectProps.V;
bsdfSample.NoL = NoL;
bsdfSample.geoProps = &isectProps.BsdfProps;
// Sample the brdf to get the scale
auto sampledBrdf = material.sampleBsdf(bsdfSample);
// Multiply by light radiance
sampledBrdf *= light->getColor();
// Multiply by visibility
sampledBrdf *= (1.0f - occlusionStrength);
// Finally add light contribution
directCont += sampledBrdf;
}
}
}
// Compute indirect lighning
RGBColor indirectCont;
if (++depth <= m_settings.m_maxDepth)
{
BaseMaterial::SpawnRayResult newRayData;
newRayData = material->spawnRay(/* some parameters*/);
// Build the bsdf sample struture
Material::BaseMaterial::SampleBsdfData bsdfSample;
bsdfSample.L = newRayData.ray.getDirection();
bsdfSample.V = isectProps.V;
bsdfSample.NoL = glm::dot(newRayData.ray.getDirection(), isectProps.BsdfProps.N);
bsdfSample.geoProps = &isectProps.BsdfProps;
// Indirect raytracing
const Spectrum sampledBrdf = material->sampleBsdf(bsdfSample);
const Spectrum sampledRadiance = sampledBrdf * pathTracing(newRayData.ray, depth);//recursion
static const float normalizationFactor = 2.0f * Math::Pi.getValue();
indirectCont = sampledRadiance * normalizationFactor;
}
return directCont + indirectCont;
}
这里还有更多代码 sn-ps。
sampleBsdf 方法
RGBColor BaseMaterial::sampleBsdf(const SampleBsdfData& data) const
{
DistributionFunction::SampleInput distSampleInput;
distSampleInput.L = data.L;
distSampleInput.V = data.V;
distSampleInput.N = data.geoProps->N;
distSampleInput.T = data.geoProps->T;
distSampleInput.B = data.geoProps->B;
distSampleInput.H = glm::normalize(data.L + data.V);
distSampleInput.HoN = std::abs(glm::dot(data.geoProps->N, distSampleInput.H));
distSampleInput.NoV = std::abs(glm::dot(data.geoProps->N, data.V));
distSampleInput.NoL = data.NoL;
return sampleBrdf(distSampleInput) * distSampleInput.NoL;
}
sampleBrdf 方法
inline nbFloat32 lambert(const SampleInput& input)
{
return Math::InvPi.getValue();
}
nbFloat32 blinnPhong(const SampleInput& input, nbFloat32 shininess)
{
const nbFloat32 HoN = std::min(input.HoN, 0.999f);
nbFloat32 normalizationFactor = (shininess + 8.0f) * Math::InvPi8.getValue();
normalizationFactor = glm::clamp(normalizationFactor, 0.0f, 1.0f);
return std::pow(HoN, shininess) * normalizationFactor;
}
#define NO_FRESNEL_VALUE 0.4f
nbFloat32 DefaultDielectric::sampleFresnel(nbFloat32 HoN) const
{
if (m_fresnelEnabled)
{
// Schlick approximation.
return glm::clamp(m_fresnel0 + (1.0f - m_fresnel0) * pow(1.0f - HoN, 5.0f), 0.0f, 1.0f);
}
return NO_FRESNEL_VALUE;
}
RGBColor DefaultDielectric::sampleBrdf(DistributionFunction::SampleInput& distSampleInput) const
{
nbFloat32 fresnelFactor = sampleFresnel(distSampleInput.HoN);
// Diffuse
nbFloat32 diffuseFactor = lambert(distSampleInput) * (1.0f - fresnelFactor);
auto diffuseLightning = m_diffuse * diffuseFactor;
// Specular
nbFloat32 specularFactor = blinnPhong(distSampleInput, m_glossiness) * fresnelFactor;
auto specLightning = m_specular * specularFactor;
return m_opacity * (diffuseLightning + specLightning);
}
【问题讨论】:
-
即使是图片中的黑暗区域也看起来像半灰色。我会先解决这个问题——为什么最暗的部分不是黑色的?即使您的程序使错误的事物变得明亮和黑暗,仍然应该有黑暗的事物。
-
感谢您的帮助。我的光线追踪器场景有一个环境术语。但是当我将它设置为零时,它是完全黑暗的:imgur.com/a/vbp1Gg6
-
我希望光线追踪场景具有直接和反射光以及非常少的环境光。如果你看你的第一张照片,它看起来环境光只是为了让整个图像更亮——就好像你只是给所有的 RGB 值添加了相同的数字。最后一张照片显示来自太阳的直接照明正在工作。问题是为什么反射光如此暗。
-
我不是光线追踪方面的专家。我猜你已经尝试过让 BSDF 有更大的数字?这似乎太明显了
-
我刚试过。向 bsdf 添加一个因子肯定会使场景更亮。我将发布缺失部分的代码。
标签: c++ rendering raytracing