我正在使用c ++,opengl 4.0和glsh着色器语言。
我想知道如何正确地将漫反射纹理与光照贴图纹理混合。
我们假设我们有一个房间。每个对象都有漫反射纹理和光照贴图。在像gamedev.net或stackoverflow这样的论坛中,人们会说,这些纹理应该成倍增加。并且在大多数情况下它会产生良好的效果,但有时某些物体非常接近光源(例如白色灯泡)。近光对象的光源生成白色光照贴图。但是当我们将漫反射纹理与白色光照贴图相乘时,我们就会得到原始的漫反射纹理颜色。
但如果光源靠近某个物体,那么光的颜色应占主导地位
这意味着,如果白色,强光靠近红墙,那么这面墙的某些部分应该是白色,而不是红色!
我认为我需要的不仅仅是一个光照贴图。光照贴图没有关于光强度的信息。这意味着,最闪亮的颜色只是最大的漫反射颜色。
也许我应该有2个纹理 - shadowmap和lightmap?方程式应如下所示:
vec3 color = shadowmapColor * diffuseTextureColor + lightmapColor;
这是好方法吗?
答案 0 :(得分:3)
一般来说,如果您仍在使用光照贴图,则可能还没有使用HDR渲染。没有它,你想要的并不是特别合理。除非您的光照贴图将光强度作为HDR浮点值(可能采用GL_R11F_G11F_B10F
或GL_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 :虽然这在数学上有效,但它绝对不是物理上的声音。您可能需要对最终贡献进行一些修正,以使其至少在物理上合理。如果你的唯一目标是效果,你可以简单地使用修正因子,直到你对结果感到满意为止。