700字范文,内容丰富有趣,生活中的好帮手!
700字范文 > webgl通过shader实现逼真水面

webgl通过shader实现逼真水面

时间:2020-10-27 07:28:04

相关推荐

webgl通过shader实现逼真水面

webgl水面的实现,最简单的方法就是通过贴图置换,顶点的计算可通过简单的正弦曲线公式计算,但效果不是狠逼真,于是有了另一种的实现方法:基于opengl着色器语言,编写shader程序,使用frameBuffer离屏不停的切换多个program,最终绘制出一张纹理图,使用该纹理图进行屏幕绘制,对于光在水面的折射和反射利用texture进行map映射,r通道的值的大小用于计算法向量和波的高度,方便计算折射反射光方向向量,最终显示的颜色是漫反射颜色和环境光反射颜色通过菲涅尔公式做线性插值。然后通过线与面求交判断光线是否投射到水面上。由于重点是shader的实现,所以接下来着重减少shader的实现,效果示例请访问水面demo。

wave.glsl渲染水花和波浪。

如下是为了渲染出波浪效果,当然麻烦的话还可直接用一张水面波texture绘制。

void createRipple(inout vec4 info){float dy=swing*len/2.;float lineWidth=lineWidth;vec2 endP=startP+vec2(len, dy+lineWidth);if (coord.x>=startP.x&&coord.x<=endP.x&&coord.y>=startP.y&&coord.y<=endP.y){float r=sin(startAngle+(coord.x-startP.x)/len*PI*period)*dy+startP.y;lineWidth-=(1.-(r-startP.y))*lineWidth;//两端宽度随cos曲线变小if ((coord.y<r||coord.y>r+lineWidth)){//把coord坐标限制到曲面上if (info.r==0.){discard;}} else {r=cos(((coord.y-r)/lineWidth-0.5)*PI);//lineWidth渐变r*=strength;info.r+=r;//info.a+=r;}}}

对于浪花的实现如下:

void main() {/* get vertex info */vec4 info = texture(u_sampler, coord);/* add the drop to the height */float dot =max(0.0, 1.0 - length(center - coord) / radius);dot = 0.5 - cos(drop * PI) * 0.5;info.r +=dot*strength;fragColor = info;}

uniform变量center是vec2类型,表示要在水面某二维坐标处绘制一个浪花起始点。

updateWave.glsl更新水花和波浪。

void main() {vec4 info = texture(u_sampler, coord);vec4 origin=texture(u_samplerOrigin, coord);vec2 dx = vec2(u_delta.x, 0.0);vec2 dy = vec2(0.0, u_delta.y);float average = (texture(u_sampler, coord - dx).r +texture(u_sampler, coord - dy).r +texture(u_sampler, coord + dx).r +texture(u_sampler, coord + dy).r) /4.;info.g += average-info.r;info.g *= .995;info.r+=info.g;fragColor =info;}

normal.glsl计算出水面法向量。

根据纹理图中当前像素处r通道值计算出法向量。

void main() {/* get vertex info */vec4 info = texture(u_sampler, coord);/* update the normal 根据二维图片的坐标,构造出三维坐标y高度,从而计算出normal*/vec3 dx = vec3(u_delta.x, texture(u_sampler, vec2(coord.x + u_delta.x, coord.y)).r - info.r, 0.0);vec3 dy = vec3(0.0, texture(u_sampler, vec2(coord.x, coord.y + u_delta.y)).r - info.r, u_delta.y);info.ba =normalize(cross(dy, dx)).xz;/*info.ba=normalize(vec3(-u_delta.y*(texture(u_sampler, vec2(coord.x + u_delta.x, coord.y)).r - info.r),u_delta.y*u_delta.x,-(texture(u_sampler, vec2(coord.x, coord.y + u_delta.y)).r - info.r)*u_delta.x)).xz;*/fragColor = info;}

render.glsl进行屏幕绘制。

#version 300 esprecision highp float;uniform vec3 eye;in vec3 position;in vec2 v_uv;uniform samplerCube skySampler;out vec4 fragColor;vec3 getSurfaceRayColor(vec3 origin, vec3 ray, vec3 waterColor,bool isRefract) {vec3 color;vec2 t = intersectCube(origin, ray, minBox, maxBox);vec3 hit = origin + ray * t.y;if (hit.y < 2.0 / 12.0) {//是折射还是反射,若折射则墙颜色color = getWallColor(hit);} else {color = texture(skySampler, ray).rgb;//color *=dot(eye, ray); //vec3(pow((dot(eye, ray)), 500000.0))/** vec3(10.0, 8.0, 6.0)*/;}if (ray.y < 0.0) color *= waterColor;return color;}void main() {vec2 coord =v_uv; //position.xz * 0.5 + 0.5;vec4 info = texture(waterSampler, coord);for (int i = 0; i < 5; i++) {coord += info.ba * 0.005;info = texture(waterSampler, coord);}/*if(position.y==0.||position.y!=0.){info.ba*=0.;}*/vec3 normal = vec3(info.b, sqrt(1.0 - dot(info.ba, info.ba)), info.a);vec3 incomingRay = normalize(position - eye);//above watervec3 reflectedRay = reflect(incomingRay, normal);vec3 refractedRay = refract(incomingRay, normal, IOR_AIR / IOR_WATER);float fresnel = mix(0.25, 1.0, pow(1.0 - dot(normal, -incomingRay), 3.0));vec3 reflectedColor = getSurfaceRayColor(position, reflectedRay, abovewaterColor,false);vec3 refractedColor = getSurfaceRayColor(position, refractedRay, underwaterColor,true);fragColor = vec4(mix(refractedColor, reflectedColor, fresnel)/**vec3(1.,1.,1.)*dot(light,normal)*/, 1.0);//fragColor=vec4(refractedColor,1.0);}

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。