学习threejs,使用自定义GLSL 着色器,实现抽象艺术特效

👨‍⚕️ 主页: gis分享者

👨‍⚕️ 感谢各位大佬 点赞👍 收藏⭐ 留言📝 加关注✅!

👨‍⚕️ 收录于专栏:threejs gis工程师


文章目录

  • 一、🍀前言
    • [1.1 ☘️GLSL着色器](#1.1 ☘️GLSL着色器)
      • [1.1.1 ☘️着色器类型](#1.1.1 ☘️着色器类型)
      • [1.1.2 ☘️工作原理](#1.1.2 ☘️工作原理)
      • [1.1.3 ☘️核心特点](#1.1.3 ☘️核心特点)
      • [1.1.4 ☘️应用场景](#1.1.4 ☘️应用场景)
      • [1.1.5 ☘️实战示例](#1.1.5 ☘️实战示例)
  • [二、🍀使用自定义GLSL 着色器,实现抽象艺术特效](#二、🍀使用自定义GLSL 着色器,实现抽象艺术特效)
    • [1. ☘️实现思路](#1. ☘️实现思路)
    • [2. ☘️代码样例](#2. ☘️代码样例)

一、🍀前言

本文详细介绍如何基于threejs在三维场景中使用自定义GLSL 着色器,实现抽象艺术特效。亲测可用。希望能帮助到您。一起学习,加油!加油!

1.1 ☘️GLSL着色器

GLSL(OpenGL Shading Language)是OpenGL的核心编程语言,用于编写图形渲染管线中可定制的计算逻辑。其核心设计目标是通过GPU并行计算实现高效的图形处理,支持从基础几何变换到复杂物理模拟的多样化需求。

1.1.1 ☘️着色器类型

顶点着色器(Vertex Shader)

  • 功能:处理每个顶点的坐标变换(如模型视图投影矩阵变换)、法线计算及顶点颜色传递。
  • 输出:裁剪空间坐标gl_Position,供后续光栅化阶段使用。

片段着色器(Fragment Shader)

  • 功能:计算每个像素的最终颜色,支持纹理采样、光照模型(如Phong、PBR)及后处理效果(如模糊、景深)。
  • 输出:像素颜色gl_FragColor或gl_FragColor(RGBA格式)。

计算着色器(Compute Shader,高级)

  • 功能:执行通用并行计算任务(如物理模拟、图像处理),不直接绑定渲染管线。
  • 特点:通过工作组(Work Group)实现高效数据并行处理。

1.1.2 ☘️工作原理

渲染管线流程

  • 顶点处理:CPU提交顶点数据(位置、颜色、纹理坐标),GPU并行执行顶点着色器处理每个顶点。
  • 光栅化:将顶点数据转换为像素片段,生成片段着色器输入。
  • 片段处理:GPU并行执行片段着色器计算每个像素颜色。
  • 输出合并:将片段颜色与帧缓冲区混合,生成最终图像。

数据流动

  • 顶点属性:通过glVertexAttribPointer传递位置、颜色等数据,索引由layout(location=N)指定。
  • Uniform变量:CPU通过glGetUniformLocation传递常量数据(如变换矩阵、时间),在渲染循环中更新。
  • 内置变量: gl_Position(顶点着色器输出):裁剪空间坐标。 gl_FragCoord(片段着色器输入):当前像素的窗口坐标。
    gl_FrontFacing(片段着色器输入):判断像素是否属于正面三角形。

1.1.3 ☘️核心特点

语法特性

  • C语言变体:支持条件语句、循环、函数等结构,天然适配图形算法。
  • 向量/矩阵运算:内置vec2/vec3/vec4及mat2/mat3/mat4类型,支持点乘、叉乘等操作。
  • 精度限定符:如precision mediump float,控制计算精度与性能平衡。

硬件加速

  • 并行计算:GPU数千个核心并行执行着色器代码,适合处理大规模数据(如粒子系统、体素渲染)。
  • 内存模型:支持常量内存(Uniform)、纹理内存(Sampler)及共享内存(计算着色器),优化数据访问效率。

灵活性

  • 可编程管线:完全替代固定渲染管线,支持自定义光照、阴影、后处理效果。
  • 跨平台兼容性:OpenGL ES(移动端)与WebGL(Web)均支持GLSL,代码可移植性强。

1.1.4 ☘️应用场景

游戏开发

  • 实时渲染:实现PBR材质、动态阴影、屏幕空间反射。
  • 特效系统:粒子火焰、流体模拟、布料物理。
  • 性能优化:通过计算着色器加速AI计算、碰撞检测。

数据可视化

  • 科学计算:将多维数据映射为颜色/高度图(如气象数据、流场可视化)。
  • 信息图表:动态生成3D柱状图、热力图,增强数据表现力。

艺术创作

  • 程序化生成:使用噪声函数(如Perlin、Simplex)生成地形、纹理。
  • 交互式装置:结合传感器数据实时修改着色器参数,创造动态艺术作品。

教育与研究

  • 算法实验:实时调试光线追踪、路径追踪算法。
  • 教学工具:可视化线性代数运算(如矩阵变换、向量投影)。

1.1.5 ☘️实战示例

顶点着色器(传递法线与世界坐标):

javascript 复制代码
#version 330 core
layout(location=0) in vec3 aPos;
layout(location=1) in vec3 aNormal;
out vec3 FragPos;
out vec3 Normal;
uniform mat4 model;
uniform mat4 view;
uniform mat4 projection;
void main() {
    FragPos = vec3(model * vec4(aPos, 1.0));
    Normal = mat3(transpose(inverse(model))) * aNormal; // 模型空间到世界空间的法线变换
    gl_Position = projection * view * vec4(FragPos, 1.0);
}

片段着色器(实现Blinn-Phong光照):

javascript 复制代码
#version 330 core
in vec3 FragPos;
in vec3 Normal;
out vec4 FragColor;
uniform vec3 lightPos;
uniform vec3 viewPos;
uniform vec3 lightColor;
uniform vec3 objectColor;
void main() {
    // 环境光
    vec3 ambient = 0.1 * lightColor;
    // 漫反射
    vec3 norm = normalize(Normal);
    vec3 lightDir = normalize(lightPos - FragPos);
    float diff = max(dot(norm, lightDir), 0.0);
    vec3 diffuse = diff * lightColor;
    // 镜面反射
    vec3 viewDir = normalize(viewPos - FragPos);
    vec3 reflectDir = reflect(-lightDir, norm);
    float spec = pow(max(dot(viewDir, reflectDir), 0.0), 32);
    vec3 specular = 0.5 * spec * lightColor;
    // 最终颜色
    vec3 result = (ambient + diffuse + specular) * objectColor;
    FragColor = vec4(result, 1.0);
}

官方文档

二、🍀使用自定义GLSL 着色器,实现抽象艺术特效

1. ☘️实现思路

使用自定义GLSL 着色器定义THREE.ShaderMaterial材质material,定义THREE.PlaneGeometry作为颜色渲染平面,实现抽象艺术特效。具体代码参考代码样例。可以直接运行。

2. ☘️代码样例

html 复制代码
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>glsl颜色_抽象艺术作品</title>
    <style>
        body {
            margin: 0;
            overflow: hidden;
            background: #020010;
        }
        canvas {
            display: block;
            width: 100vw;
            height: 100vh;
        }
    </style>

</head>
<body>

</body>
<script type="importmap">
    {
        "imports": {
            "three": "https://cdn.jsdelivr.net/npm/three@0.160.0/build/three.module.js"
        }
    }
    </script>

<script type="module">
  import * as THREE from 'three';

  const scene = new THREE.Scene();
  scene.background = new THREE.Color(0x000000);
  const camera = new THREE.OrthographicCamera(-1, 1, 1, -1, 0, 1);
  const renderer = new THREE.WebGLRenderer({ antialias: true });
  renderer.setSize(window.innerWidth, window.innerHeight);
  document.body.appendChild(renderer.domElement);

  const material = new THREE.ShaderMaterial({
    uniforms: {
      time: { value: 0 },
      resolution: { value: new THREE.Vector2(window.innerWidth, window.innerHeight) },
      mouse: { value: new THREE.Vector2(0.5, 0.5) }
    },
    vertexShader: `
                varying vec2 vUv;
                void main() {
                    vUv = uv;
                    gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
                }
            `,
    fragmentShader: `
                uniform float time;
                uniform vec2 resolution;
                uniform vec2 mouse;
                varying vec2 vUv;

                mat2 rot(float a) {
                    float s = sin(a);
                    float c = cos(a);
                    return mat2(c, -s, s, c);
                }

                void main() {
                    vec2 FC = gl_FragCoord.xy;
                    vec2 r = resolution;
                    float t = time;
                    vec4 o = vec4(0.0);

                    vec2 uv = (FC * 2.0 - r.xy) / r.y;
                    vec3 rayDir = normalize(vec3(uv, 1.0));

                    for(float i = 0.0; i < 20.0; i++) {
                        float z = i * 0.5 + 0.1;

                        vec3 p = z * rayDir;
                        vec2 mouseOffset = (mouse - 0.5) * 1.0;

                        p.xz *= rot(t * 0.2 + mouseOffset.x);
                        p.yz *= rot(t * 0.15 + mouseOffset.y);
                        vec3 a = p;

                        float d;
                        for(d = 1.0; d < 4.0; d += 1.0) {
                            a -= sin(a * d + t + i*0.1).yzx / (d * 0.8);
                        }

                        vec3 q = abs(a);
                        float mx = max(max(q.x, q.y), q.z);
                        float s = a.z + a.y - t;

                        d = abs(2.0 - mx) + abs(cos(s)) / 7.0;

                        float z_col = z + d;

                        vec4 colorPhase = vec4(0.0, 2.0 + mouse.y * 2.0, 4.0 - mouse.y * 2.0, 0.0);

                        o += (cos(s - z_col + colorPhase) + 1.0) / (d*0.5 + 0.01);
                    }

                    o = o / 20.0;
                    o = o / (1.0 + o);

                    o = smoothstep(0.15, 0.85, o);

                    gl_FragColor = o;
                    gl_FragColor.a = 1.0;
                }
            `
  });

  const geometry = new THREE.PlaneGeometry(2, 2);
  const mesh = new THREE.Mesh(geometry, material);
  scene.add(mesh);

  window.addEventListener('resize', () => {
    const width = window.innerWidth;
    const height = window.innerHeight;
    renderer.setSize(width, height);
    material.uniforms.resolution.value.set(width, height);
  });
  window.addEventListener('mousemove', (event) => {
    material.uniforms.mouse.value.x = event.clientX / window.innerWidth;
    material.uniforms.mouse.value.y = 1.0 - (event.clientY / window.innerHeight);
  });

  function animate() {
    requestAnimationFrame(animate);
    material.uniforms.time.value += 0.02;
    renderer.render(scene, camera);
  }

  window.onload = function () {
    animate();
  }
</script>
</html>

效果如下

参考:源码

相关推荐
熊猫悟道3 天前
Unity shader 之,Shader内部时间离散处理
unity·游戏引擎·材质·着色器
allenjiao10 天前
WebGPU vs WebGL:WebGPU什么时候能完全替代WebGL?Web 图形渲染的迭代与未来
前端·图形渲染·webgl·threejs·cesium·webgpu·babylonjs
二川bro10 天前
第59节:常见问题汇编 - 60个典型问题解答
javascript·3d·threejs
孪生引擎观星台14 天前
数字孪生如何破解效率、性能与安全困局?
安全·数字孪生·threejs
gis分享者16 天前
学习threejs,添加ECharts图表
echarts·threejs·material·图表·canvastexture·planegeometry
二川bro19 天前
第40节:AR基础:Marker识别与跟踪
ar·threejs
二川bro21 天前
第33节:程序化生成与无限地形算法
前端·算法·3d·threejs
二川bro22 天前
第30节:大规模地形渲染与LOD技术
前端·threejs
患得患失9491 个月前
【threejs】材质共享导致的典型问题
材质·threejs