视差贴图 parallax map

来源:互联网 发布:sql group by 多列 编辑:程序博客网 时间:2024/05/16 07:29

视差贴图,不同于法线贴图的是,会根据视角调整纹理映射的偏移,从而产生遮挡效果

但在多边形的边缘仍然是平的。

(这个需要用浮雕映射来解决,利用gs阶段,输出更多的顶点,从而产生新的多边形,
需要硬件能支持相应的渲染管线,题外话,此处略过不表,
笔者认为如果边缘一般距离视点较远的话,一般情况下影响的效果有限)

首先要有一个高度图

根据视角,以观察到的点为终点,以纹理的最大高度(1*height_scale),根据视线向量,倒退到起点
可以设定一个step(可配置,step越小,采样次数越多,准确率越高,但帧率也会下降)
每隔一个step,采样出当前纹理的高度值tex_h,与当前视点的高度view_h比较,
如果view_h > tex_h 查找继续.否则停止.

为了更精细查找,nvidia还会在找到的step区间更进一步细分,但过程同上述一样,不表.


光照:

光线变换至切空间之后,法线与光线做个点积即可得到光照强度与颜色


阴影:

根据修正后的采样位置,顺着光线的方向,取高度纹理采样,与视点高度比较,计算对阴影的贡献。


glsl顶点着色器代码:

attribute vec3 attr_ant_tangent;attribute vec3 attr_ant_binormal;attribute vec3 attr_ant_normal;uniform vec4 uni_light_pos;/* 此处假设光源已转换至局部坐标系 */uniform vec3 uni_eye_local_pos;/* 视点位置也需要变换至局部坐标系 */varying vec3 tangent_light_dir;varying vec3 tangent_eye_dir;varying vec3 tangent_light_dir_shadow;varying vec3 local_pos;/* 局部坐标系 */void main(){vec3 light_dir = normalize(uni_light_pos.xyz - gl_Vertex.xyz);/* 如果是平行光,则光线方向不变,w=1说明是点光源,根据光源与顶点,得到光线向量 */mat3 rotation            = mat3(attr_ant_binormal, attr_ant_tangent, attr_ant_normal);tangent_light_dir        = normalize(rotation * light_dir);mat3 rotation_shadow     = mat3(attr_ant_tangent, attr_ant_binormal, attr_ant_normal);tangent_light_dir_shadow = normalize(rotation_shadow * light_dir);vec3 eye_dir   = uni_eye_local_pos - gl_Vertex.xyz;mat3 rotation_eye = mat3(attr_ant_tangent, attr_ant_binormal, attr_ant_normal);tangent_eye_dir = normalize(rotation_eye * eye_dir);local_pos = gl_Vertex.xyz;gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;gl_TexCoord[0] = gl_MultiTexCoord0;}


片元着色器代码:
uniform sampler2D uni_tex_color1;uniform sampler2D uni_tex_color2;uniform sampler2D uni_tex_normal;uniform vec3 uni_eye_local_pos;/* 视点位置也需要变换至局部坐标系 */uniform vec4 uni_light_pos;/* 此处假设光源已转换至局部坐标系 */varying vec3 local_pos;/* 局部坐标系 */varying vec3 tangent_light_dir;varying vec3 tangent_eye_dir;varying vec3 tangent_light_dir_shadow;float step_count = 4.0;float step_count_detail = 16.0;float height_scale = 10.0 / 255.0;void main(){/* 根据view_pos */vec3 eye_dir = tangent_eye_dir / tangent_eye_dir.z;vec2 tex_sample_step = eye_dir.xy * (height_scale / step_count);vec2 tex_sample_start = gl_TexCoord[0].st + eye_dir.xy * height_scale;float eye_height = height_scale;float height_step = eye_height / step_count;vec4 tex_sample;vec4 tex_color;vec2 tex_sample_last = tex_sample_start;float eye_height_last = eye_height;for(int i = 0; i < step_count; i ++){tex_sample = texture2D(uni_tex_normal, tex_sample_start);if(tex_sample.a * height_scale >= eye_height)break;tex_sample_last = tex_sample_start;eye_height_last = eye_height;eye_height -= height_step;tex_sample_start -= tex_sample_step;}{height_step = height_step / step_count_detail;tex_sample_step = tex_sample_step / step_count_detail;tex_sample_start = tex_sample_last;eye_height = eye_height_last;for(int j = 0; j < step_count_detail; j ++){tex_sample = texture2D(uni_tex_normal, tex_sample_start);if(tex_sample.a * height_scale >= eye_height)break;eye_height -= height_step;tex_sample_start -= tex_sample_step;}}/* cal shadow */float shadow = 0.0;{float light_sample_count = 32;vec3 light_dir = tangent_light_dir_shadow / tangent_light_dir_shadow.z;vec2 light_sample_start = gl_TexCoord[0].st + light_dir.xy * height_scale;vec2 light_sample_step = light_dir.xy * (height_scale / light_sample_count);float light_height = height_scale;float light_step = light_height / light_sample_count;float real_h = tex_sample.a * height_scale;for(int k = 0; k < light_sample_count; k ++){float tex_h = texture2D(uni_tex_normal, light_sample_start).a * height_scale;if(tex_h >= real_h){shadow += min((tex_h - real_h)/(height_scale * 0.3), 1.0);}light_height -= light_step;light_sample_start -= light_sample_step;}shadow = (1- shadow / light_sample_count) * 0.8;}tex_color = texture2D(uni_tex_color1, tex_sample_start);vec3 normal = tex_sample.xyz;normal = (normal - 0.5) * 2.0;normal = normalize(normal);float dis = length(uni_light_pos.xyz - local_pos);float dis_factor = 1.0 / (1.0 + max(dis - 50, 0));vec3 local_light = normalize(tangent_light_dir);float normal_factor = clamp(dot(normal, local_light), 0.0, 1.0);gl_FragColor = dis_factor * normal_factor * tex_color * shadow;//gl_FragColor = shadow * tex_color;//gl_FragColor = dis_factor * normal_factor * shadow * vec4(1,1,1,1);gl_FragColor.a = 1.0f;/*vec3 vtmp = normalize(tangent_eye_dir);gl_FragColor.r = abs(vtmp.x);gl_FragColor.g = abs(vtmp.y);gl_FragColor.b = abs(vtmp.z);*/}




笔者实现的效果


0 0
原创粉丝点击