非浮点纹理HDR实现

1.  引言

该例子讲解了一个由普通纹理格式GL_RGBA来模拟HDR效果。

2.关键技术

不使用浮点纹理,所以必须用一种方法让低精度数据代表高亮度颜色。那就用第四通道A来做为RGB的乘法因子。好象与RGBS编码方法类似。具体编码是,如果RGB大于1.0,则RGB除以它们的最大值,设最大值为MAX,则令

A=MAX/CONST

CONST是一常量,我们可以取2的幂,我这里取64,当然不能大于255。除以64.0是为了将A影射到[01]区间。所以我们编码和解码规则

If(max(color.r,color.g,color.b)>1.0)

{

color.rgb /= max(color.r,color.g,color.b);

color.a = max/64.0;

}

3.场景建立

3.1渲染天空盒

这是我们的天空盒。分两次渲染进显寸中,第一次将RGB颜色传递到CUBEMAP,第二次把A传递进去。我使用的天空盒不是HDR格式,但可以使用HDR格式,只要稍做改变即可使用。

程序代码:

uniform samplerCube     cubeMap;

void main()

{

vec4 color = textureCube(cubeMap, gl_TexCoord[0].stp);

color.a = (color.a+1.0)/64.0;  

gl_FragColor = color;

}

如果天空盒是HDR格式,代码如下

RGBE格式为RGBA

fExp = Encoded.E - 128; color.r = color.r/255 * pow(2,fExp); color.g = color.g/255 * pow(2,fExp); color.b = color.b/255 * pow(2,fExp);

然后再用上面的代码转换为自定义格式。

3.2渲染场景的模型,主要是光照计算,并转换为自定义格式

uniform sampler2D tex;

uniform sampler2D average;

uniform float factor;

void main()

{

  vec4 color = texture2D(tex, gl_TexCoord[0].st); 

   vec4 ave = texture2D(average, vec2(0.5,0.5)); 

 float avelum = dot(ave.rgb,vec3(0.3,0.59,0.11))*factor;

 vec3 final = vec3(0.0,0.0,0.0);  color.rgb *=color.a*64.0 ;

 float lum = dot(color.rgb, vec3(0.3,0.59,0.11));  

color.rgb /= (vec3(1.0,1.0,1.0)+color.rgb);

 if(lum>avelum) final = color.rgb; 

 gl_FragColor = vec4(final, 1.0);

}

4.渲染到离屏缓冲器FBO

我们这里一共用了6FBO10个纹理单元

GLuint FrameBufferObject::AddTexture(    

   GLenum attachment,       

GLuint w,       

GLuint h,       

GLuint internalformat,       

GLenum type,       

GLuint format,       

GLuint level,       

GLuint target,       

GLuint filter      

 )

{

 GLuint texID;  

  glGenTextures(1,&texID);  

 glBindTexture(target, texID);  

glTexParameteri(target, GL_TEXTURE_MIN_FILTER, filter);  

glTexParameteri(target, GL_TEXTURE_MAG_FILTER, filter);  

glTexParameteri(target, GL_TEXTURE_WRAP_S, GL_CLAMP);  

glTexParameteri(target, GL_TEXTURE_WRAP_T, GL_CLAMP);  

glTexImage2D(target, 0,internalformat, w, h, 0, format, type, 0);  

glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, attachment, target, texID, 0);

 return texID; }

4.1 提取高亮度部分并下采样到64*64,并模糊

步骤1将场景高亮部分提出,渲染到64*64纹理;

uniform sampler2D tex;

uniform sampler2D average;

 uniform float factor;

void main()

 {

  vec4 color = texture2D(tex, gl_TexCoord[0].st);   

 vec4 ave = texture2D(average, vec2(0.5,0.5));  

float avelum = dot(ave.rgb,vec3(0.3,0.59,0.11))*factor;

 vec3 final = vec3(0.0,0.0,0.0);  color.rgb *=color.a*64.0 ;

 float lum = dot(color.rgb, vec3(0.3,0.59,0.11)); 

 color.rgb /= (vec3(1.0,1.0,1.0)+color.rgb);

 if(lum>avelum) final = color.rgb;  gl_FragColor = vec4(final, 1.0);

}

步骤2 横向模糊渲染到另一纹理;

步骤3 纵向模糊渲染到另一纹理;

uniform sampler2D tex;

#define dx 0.015625

void main()

{

  vec4 color = texture2D(tex, gl_TexCoord[0].st) * 0.375;  

color += texture2D(tex, vec2(gl_TexCoord[0].s+dx, gl_TexCoord[0].t)) * 0.3125;  

color += texture2D(tex, vec2(gl_TexCoord[0].s-dx, gl_TexCoord[0].t)) * 0.3125; 

 gl_FragColor =color;

}

 

4.3 与原场景混合,色调映射。

4.4 暴光控制

4.4.1 求亮度平均值

步骤1 将场景下采样到64*64纹理;

步骤2 再下采样到16*16纹理;

步骤3 再下采样到4*4纹理;

步骤4 再下采样到1*1纹理;

uniform sampler2D tex; uniform float dx;

void main()

{  

vec4 color = texture2D(tex, gl_TexCoord[0].st+vec2(dx*1.5, dx*1.5));  

color += texture2D(tex,gl_TexCoord[0].st+vec2( dx*0.5, dx*1.5)); 

 color += texture2D(tex,gl_TexCoord[0].st+vec2(-dx*0.5, dx*1.5)); 

 color += texture2D(tex,gl_TexCoord[0].st+vec2(-dx*1.5, dx*1.5)); 

   color += texture2D(tex,gl_TexCoord[0].st+vec2( dx*1.5, dx*0.5));

  color += texture2D(tex,gl_TexCoord[0].st+vec2( dx*0.5, dx*0.5));  

color += texture2D(tex,gl_TexCoord[0].st+vec2(-dx*0.5, dx*0.5)); 

 color += texture2D(tex,gl_TexCoord[0].st+vec2(-dx*1.5, dx*0.5));  

  color += texture2D(tex,gl_TexCoord[0].st+vec2( dx*1.5,-dx*0.5)); 

 color += texture2D(tex,gl_TexCoord[0].st+vec2( dx*0.5,-dx*0.5));  

color += texture2D(tex,gl_TexCoord[0].st+vec2(-dx*0.5,-dx*0.5)); 

 color += texture2D(tex,gl_TexCoord[0].st+vec2(-dx*1.5,-dx*0.5)); 

   color += texture2D(tex,gl_TexCoord[0].st+vec2( dx*1.5,-dx*1.5));

  color += texture2D(tex,gl_TexCoord[0].st+vec2( dx*0.5,-dx*1.5));  

color += texture2D(tex,gl_TexCoord[0].st+vec2(-dx*0.5,-dx*1.5));  

color += texture2D(tex,gl_TexCoord[0].st+vec2(-dx*1.5,-dx*1.5));   

  color /= 16.0;  

gl_FragColor =color;

}

步骤5 采样该1*1纹理,其亮度便是平均亮度

4.4.2 利用乒乓技术求暴光度

利用两个渲染对象,分别绑定1*1纹理。渲染过程中两个纹理没次都轮流渲染到其中的一个。

公式如下

float fNewAdaptation = fAdaptedLum + (fCurrentLum - fAdaptedLum) * ( 1 - pow( 0.98f , 30 * g_fElapsedTime ) );

另外为方便计算,我直接使用如下GLSL代码

uniform sampler2D tex1;

 uniform sampler2D tex2;

uniform float time; void main()

{  

vec4  average = texture2D(tex1, vec2(0.5,0.5)); 

 float oldExp = texture2D(tex2, vec2(0.5,0.5)).r ; 

 float newExp = dot(average.rgb, vec3(0.3,0.59,0.11)); 

 gl_FragColor.x = mix(oldExp, newExp, 0.001); }

如果麻烦,该技术去掉,直接在最后的图象生成阶段访问包含亮度平均值的纹理来计算暴光度。

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值