将光照贴图与漫反射贴图混合

时间:2013-09-04 13:27:03

标签: opengl blending

我正在使用c ++,opengl 4.0和glsh着色器语言。

我想知道如何正确地将漫反射纹理与光照贴图纹理混合。

我们假设我们有一个房间。每个对象都有漫反射纹理和光照贴图。在像gamedev.net或stackoverflow这样的论坛中,人们会说,这些纹理应该成倍增加。并且在大多数情况下它会产生良好的效果,但有时某些物体非常接近光源(例如白色灯泡)。近光对象的光源生成白色光照贴图。但是当我们将漫反射纹理与白色光照贴图相乘时,我们就会得到原始的漫反射纹理颜色。

但如果光源靠近某个物体,那么光的颜色应占主导地位

这意味着,如果白色,强光靠近红墙,那么这面墙的某些部分应该是白色,而不是红色!

我认为我需要的不仅仅是一个光照贴图。光照贴图没有关于光强度的信息。这意味着,最闪亮的颜色只是最大的漫反射颜色。

也许我应该有2个纹理 - shadowmap和lightmap?方程式应如下所示:

vec3 color = shadowmapColor * diffuseTextureColor + lightmapColor;

这是好方法吗?

2 个答案:

答案 0 :(得分:3)

一般来说,如果您仍在使用光照贴图,则可能还没有使用HDR渲染。没有它,你想要的并不是特别合理。除非您的光照贴图将光强度作为HDR浮点值(可能采用GL_R11F_G11F_B10FGL_RGBA16F格式),否则效果不会很好。

当然,你必须做与HDR相关的常用工作,例如色调映射等。

最后,你的加法方程毫无意义。如果光照贴​​图颜色表示光与表面之间的漫反射,则只需添加光照贴图颜色并不意味着什么。标准漫反射光方程是C * (dot(N, L) * I * D),其中I是光强度,D是距离衰减因子,C是漫反射颜色。光照贴图的值可能是带括号的数量。所以添加它没有意义。

它仍然需要与曲面的漫反射颜色相乘。任何过度增亮都将归因于光的有效强度与D的函数关系。

答案 1 :(得分:0)

您需要的是光源与被照射片段的距离(或保存一些平方,平方距离)。然后,在最简单的情况下,您可以在光照贴图和光源贡献之间进行线性插值:

距离是一个简单的计算,可以在顶点着色器中按顶点完成:

in      vec4  VertexPosition; // let's assume world space for simplicity
uniform vec4  LightPosisiton; // world-space - might also be part of a uniform block etc.
out     float LightDistance;  // pass the distance to the fragment shader

// other stuff you need here ....

void main()
{
  // do stuff 
  LightDistance = length(VertexPosition - LightPosisiton);
}

在片段着色器中,您使用距离来计算光源和光照贴图之间的插值因子:

in      float     LightDistance;
const   float     MAX_DISTANCE = 10.0;
uniform sampler2D LightMap;

// other stuff ...

out vec4 FragColor;

void main()
{
  vec4 LightContribution;
  // calculate illumination (including shadow map evaluation) here
  // store in LightContribution

  vec4 LightMapConstribution = texture(LightMap, /* tex coords here */);

  // The following DistanceFactor will map distances in the range [0, MAX_DISTANCE] to
  // [0,1]. The idea is that at LightDistance >= MAX_DISTANCE, the light source
  // doesn't contribute anymore.
  float DistanceFactor  = min(1.0, LightDistance / MAX_DISTANCE); 

  // linearly interpolat between LightContribution and LightMapConstribution 
  vec4 FinalContribution = mix(LightContribution, LightMapConstribution, DistanceFactor);

  FragColor = WhatEverColor * vec4(FinalContribution.xyz, 1.0);
}

HTH。

编辑:为了考虑Nicol Bolas的评论,我假设LightMap存储编码为RGB颜色的贡献,存储每个频道的贡献。如果你实际上有一个只存储单色贡献的单通道光照贴图,你必须使用表面颜色,使用光源的颜色或减少光源对单个通道的贡献。

EDIT2 :虽然这在数学上有效,但它绝对不是物理上的声音。您可能需要对最终贡献进行一些修正,以使其至少在物理上合理。如果你的唯一目标是效果,你可以简单地使用修正因子,直到你对结果感到满意为止。