风格化shader:热成像
已经过去的2020是一个不怎么顺遂的一年,出入公共场所都需要体温监测,而人流量密集的商场,一般会采用热成像技术来快速测量体温。那么今天我们就来说说如何让一张普通图片变成具有热成像的效果。
本期代码使用javascript编写,涉及一些webgl,glsl相关知识。从本文中你可以了解到:
如何colorRamp实现gameboy效果 如何对图片进行模糊处理 如何实现简单的高亮效果 如何结合以上技术实现热成像效果
colorRamp

什么ColorRamp


color = texture2D(u_img, uv);

var val ;
if(condition){
val = gl.LINEAR;
}else{
val = gl.NEAREST
}
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, val);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, val);



Gameboy风格
uniform float u_colorRampLuminosity;
uniform sampler2D u_img0;
uniform sampler2D u_img1;
float saturate(float x){
return clamp(x,0.,1.);
}
void main() {
vec4 color = texture2D(u_img0, uv);
float luminance = 0.;
luminance = dot(vec3(.3,.6,.1) , color.rgb);
luminance = saturate(luminance + u_colorRampLuminosity);
color.rgb = texture2D(u_img1, vec2(luminance, .0)).rgb;
gl_FragColor = color;
}


Blur
vec4 Blur(vec2 uv, sampler2D source, float Intensity)
{
float step = 0.00390625 * Intensity;
vec4 result = vec4 (0, 0, 0, 0);
vec2 texCoord = vec2(0, 0);
texCoord = uv + vec2(-step, -step);
result += texture2D(source, texCoord);
texCoord = uv + vec2(-step, 0);
result += 2.0 * texture2D(source, texCoord);
texCoord = uv + vec2(-step, step);
result += texture2D(source, texCoord);
texCoord = uv + vec2(0, -step);
result += 2.0 * texture2D(source, texCoord);
texCoord = uv;
result += 4.0 * texture2D(source, texCoord);
texCoord = uv + vec2(0, step);
result += 2.0 * texture2D(source, texCoord);
texCoord = uv + vec2(step, -step);
result += texture2D(source, texCoord);
texCoord = uv + vec2(step, 0);
result += 2.0* texture2D(source, texCoord);
texCoord = uv + vec2(step, -step);
result += texture2D(source, texCoord);
result = result * 0.0625;
return result;
}


float BlurHD_G(float bhqp, float x)
{
return exp(-(x * x) / (2.0 * bhqp * bhqp));
}
vec4 BlurHD(vec2 uv, sampler2D source, float Intensity){
const int iterations = 16;
int halfIterations = iterations / 2;
float sigmaX = 0.1 + Intensity * 0.5;
float sigmaY = sigmaX;
float total = 0.0;
vec4 ret = vec4(0., 0., 0., 0.);
for (int iy = 0; iy < iterations; ++iy)
{
float fy = BlurHD_G(sigmaY, float(iy - halfIterations));
float offsety = float(iy - halfIterations) * 0.00390625;
for (int ix = 0; ix < iterations; ++ix)
{
float fx = BlurHD_G(sigmaX, float(ix - halfIterations));
float offsetx = float(ix - halfIterations) * 0.00390625;
total += fx * fy;
vec4 a = texture2D(source, uv + vec2(offsetx, offsety));
a.rgb *=a.a;
ret += a * fx * fy;
}
}
将取值点由33增加到了1616; 采用递减的指数函数:exp(-(x x)/(2.0 bhqp * bhqp)); 控制了偏移的范围(float(iy - halfIterations)*0.00390625);


Glow
vec4 emission = color;
float low = .5;
vec3 glowColor = vec3(1.,1.,1.);
emission.rgb *= glow * glowColor;
color.rgb += emission.rgb;


热成像
void main() {
vec4 color = vec4(1.,1.,1.,1.);
// 模糊
color = BlurHD(fragColor, u_image0, u_blurIntensity);
// 负片
color.rgb = 1.0 - color.rgb;
// colorRamp
float luminance = 0.;
luminance = dot(vec3(u_r,u_g,u_b) , color.rgb);
luminance = saturate(luminance + u_colorRampLuminosity);
color.rgb = texture2D(u_image1, vec2(luminance, .0)).rgb;
// 发光
vec4 emission = color;
float glow = 0.5;
vec3 glowColor = vec3(1.,1.,.1);
emission.rgb *= glow * glowColor;
color.rgb += emission.rgb;
color.rgb *= color.a;
gl_FragColor = color;
}
float saturate(float x){
return clamp(x,0.,1.);
}


评论