WebGL着色器和Three.js自己定义后期处理着色器

版权声明:本文为作者的原创文章,未经允许不得转载。 https://blog.csdn.net/lin5165352/article/details/83011361

WebGL着色器和Three.js自己定义后期处理着色器

为了渲染出一个网格的最终图像,开发者需要准确的定义顶点、变换、材质、光源以及相机是如何相互作用并最终生成图像的。而承担这个工作的就是着色器(shader)。着色器又称作可编程着色器,它是一段源码,它实现了将网格像素点投影到屏幕上的算法。图形硬件能够解析顶点、纹理以及其他底层的东西,但是并不能处理材质、光源、变换以及相机。这些高级的结构由着色器程序来处理。
着色器通常使用类C的高级语言编写,并被编译成可以被图形处理单元(GPU)执行的代码。所以着色器是运行在GPU上的程序。
创建着色器的时候需要使用OpenGL着色器语言(OpenGL Shading language,简称GLSL)。

相关网站:

WebGL规范: www.khronos.org/webgl
着色器资源网站:Shadertoy

着色器的数据类型

类型 描述
void 表示一个空值
bool 接受true或false
int 这是一个有符号整数数据类型
float 这是一个浮点标量数据类型
vec2, vec3, vec4 正分量浮点矢量
bvec2, bvec3, bvec4 布尔矢量
ivec2, ivec3, ivec4 有符号整数矢量
mat2, mat3, mat4 2x2, 3x3, 4x4 浮点矩阵
sampler2D 访问2D纹理
samplerCube 访问立方体映射纹理

修饰符

修饰符 描述
attribute 这个修饰符充当每个顶点数据的顶点着色器和OpenGL ES之间的链接。此顶点着色器属性的值在每次执行时变化
uniform 这修饰符链接着色器程序及其WebGL的应用程序。不同属性修饰词,制服(uniforms)的值不会改变。制服(uniforms)是只读的; 可以用它们与任何基本数据类型来声明一个变量。
varying 这个修饰符形成顶点着色器的内插数据和片段着色器之间的联系。它可用于下列数据类型- float, vec2, vec3, vec4, mat2, mat3, mat4, 或数组。

three.js官方自带的shader

通过THREE.ShaderPass通道可以传入一个自定义的着色器,通过这种方式来实现自定义的着色器效果。在官方文档中提供了48个自定义的shader:

名称 描述 名称 描述
AfterimageShader.js BasicShader.js
BleachBypassShader.js BlendShader.js
BokehShader.js BokehShader2.js
BrightnessContrastShader.js ColorCorrectionShader.js 调整颜色分布
ColorifyShader.js ConvolutionShader.js
CopyShader.js 不添加任何效果,只是将最后一个通道的输出结果复制到屏幕上,用处很多 DepthLimitedBlurShader.js
DigitalGlitch.js DOFMipMapShader.js
DotScreenShader.js FilmShader.js
FocusShader.js FreiChenShader.js
FresnelShader.js FXAAShader.js
GammaCorrectionShader.js HalftoneShader.js
HorizontalBlurShader.js HorizontalTiltShiftShader.js
HueSaturationShader.js 改变颜色的色调和饱和度 KaleidoShader.js
LuminosityHighPassShader.js LuminosityShader.js
MirrorShader.js 可以为部分屏幕创建镜面效果 NormalMapShader.js
OceanShaders.js ParallaxShader.js
PixelShader.js RGBShiftShader.js
SAOShader.js SepiaShader.js
SMAAShader.js SobelOperatorShader.js
SSAOShader.js TechnicolorShader.js
ToneMapShader.js TriangleBlurShader.js
UnpackDepthRGBAShader.js VerticalBlurShader.js
VerticalTiltShiftShader.js VignetteShader.js 添加晕映效果,可以在图片中央周围显示黑色边框
VolumeShader.js WaterRefractionShader.js

上面的shader可以直接放在shaderpass中使用,下面演示创建一个自己定义的灰度着色器。

three.js自定义灰度着色器

下面是自定义的shader代码:

THREE.CustomGrayScaleShader = {
    uniforms: {
        "tDiffuse": {type: "t", value: null},
        "rPower": {type: "f", value: 0.2126},
        "gPower": {type: "f", value: 0.7152},
        "bPower": {type: "f", value: 0.0722}
    },

    // 0.2126 R + 0.7152 G + 0.0722 B 图像灰度化加权平均法
    // 对于后期处理步骤,vertexshader始终是相同的
    vertexShader: [
        "varying vec2 vUv;",
        "void main() {",
        "vUv = uv;",
        "gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );",
        "}"

    ].join("\n"),

    fragmentShader: [
        "uniform float rPower;",
        "uniform float gPower;",
        "uniform float bPower;",
        "uniform sampler2D tDiffuse;",

        "varying vec2 vUv;",
        "void main() {",

        // 获取对应顶点的像素
        "vec4 texel = texture2D( tDiffuse, vUv );",

        // 计算灰度值
        "float gray = texel.r*rPower + texel.g*gPower + texel.b*bPower;",

        // 返回灰度化的顶点颜色
        "gl_FragColor = vec4( vec3(gray), texel.w );",

        "}"

    ].join("\n")

};

上面的代码采用GLSL语言写的,有点类似于C语言。其原理是采用:图像灰度化中的加权平均法
要创建自定义的着色器,需要实现两个部分,顶点着色器(vertexSh)和片元着色器(fragmentShader)。顶点着色器用于改变顶点的位置,片元着色器用于定义每个像素的颜色。对于后期处理,我们只需要改变片元着色器就可以,然后使用默认的顶点着色器。
代码中的uv,它表示的是Texel(纹理上的像素对应的坐标),该值会通过“varying vec2 vUv”变量传递到片元着色器。tDiffuse是纹理,它是THREE.EffectComppser组合器中前一个通道处理的结果。
片元着色器的作用是在传递过来的纹理上获取正确的像素。实现的方式是调用texture2D方法,第一个参数是获取的纹理,第二个参数是顶点着色器传递来的uv坐标。通过该方法就获取了每个顶点的像素值,包含rgbw(红绿蓝透明度)四个参数。然后根据加权平均法计算出灰度值,将该点的颜色变成该灰度。这样整个画面就变成了灰度图了。vec4( vec3(gray), texel.w )返回的就是每个彩色点的灰度值。整个过程解释起来有点困难,多回味一下就懂了。

配置THREE.RffectComposer。需要引入一些必要的js文件。

    <script type="text/javascript" src="./js/postprocessing/EffectComposer.js"></script>
    <script type="text/javascript" src="./js/postprocessing/RenderPass.js"></script>
    <script type="text/javascript" src="./js/postprocessing/ShaderPass.js"></script>
    <script type="text/javascript" src="./js/shaders/CopyShader.js"></script>

主要代码:

    var renderer = new THREE.WebGLRenderer();
    renderer.setClearColor(0xffffff);
    renderer.shadowMap.enabled = true;
    renderer.setSize(window.innerWidth, window.innerHeight);//setSize一定要放在前面,否则场景会模糊

    var compose = new THREE.EffectComposer(renderer);

    var renderPass = new THREE.RenderPass(scene, camera);
    var effectCopy = new THREE.ShaderPass(THREE.CopyShader);
    effectCopy.renderToScreen = true;
    var shaderPass = new THREE.ShaderPass(THREE.CustomGrayScaleShader);
    compose.addPass(renderPass);
    compose.addPass(shaderPass);
    compose.addPass(effectCopy);

我理解为,通道类似于PS的图层。每个图层都有自己的处理效果,比如二值化、增加饱和度、反转、高斯模糊等操作,其中shaderposs通道类似一个特殊的图层,可以自定义后期效果。
PS的图层都可以叠加显示,但是three.js中有的通道不能输出到屏幕,需要借助copyshader来实现,copyshader又是定义在shaderposs通道上。上面自己定义的灰度化shader也是定义到该通道上。

猜你喜欢

转载自blog.csdn.net/lin5165352/article/details/83011361
今日推荐