学习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>

效果如下

参考:源码

相关推荐
WarPigs3 天前
着色器multi_compile笔记
unity·着色器
gis分享者3 天前
学习threejs,实现山谷奔跑效果
threejs·着色器·glsl·shadermaterial·unrealbloompass·山谷奔跑·simplex
ct9784 天前
ThreeJs材质、模型加载、核心API
webgl·材质·threejs
a1117765 天前
飞机躲避炸弹 网页游戏
前端·开源·html·threejs
a1117766 天前
3D赛车躲避游戏(html threeJS开源)
前端·游戏·3d·开源·html·threejs
a1117766 天前
水体渲染系统(html开源)
前端·开源·threejs·水体渲染
HJHoMFoavQSO18 天前
基于Prescan、CarSim和Simulink的弯道超车避撞联合仿真
着色器
Chary201618 天前
opengl 着色器
opengl·着色器
三年模拟五年烧烤23 天前
easy-threesdk快速一键搭建threejs3d可视化场景
3d·threejs
loriloy23 天前
Three.js 光照教程 - 第四部分:Lighting详解
threejs