当前位置: 首页 > news >正文

学习threejs,使用自定义GLSL 着色器,生成艺术作品

👨‍⚕️ 主页: gis分享者
👨‍⚕️ 感谢各位大佬 点赞👍 收藏⭐ 留言📝 加关注✅!
👨‍⚕️ 收录于专栏:threejs gis工程师


文章目录

  • 一、🍀前言
    • 1.1 ☘️GLSL着色器
      • 1.1.1 ☘️着色器类型
      • 1.1.2 ☘️工作原理
      • 1.1.3 ☘️核心特点
      • 1.1.4 ☘️应用场景
      • 1.1.5 ☘️实战示例
  • 二、🍀使用自定义GLSL 着色器,生成艺术作品
    • 1. ☘️实现思路
    • 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 ☘️实战示例

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

#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光照):

#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二维平面使用material材质生成艺术作品。具体代码参考代码样例。可以直接运行。

2. ☘️代码样例


<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8" /><meta name="viewport" content="width=device-width, initial-scale=1.0" /><title>glsl着色器,生成艺术作品</title><style>body {margin: 0;overflow: hidden;background-color: #111;}canvas {display: block;}</style>
</head>
<body>
<div id="container"></div>
<script type="module">import * as THREE from 'https://cdn.jsdelivr.net/npm/three@0.163.0/build/three.module.js';const fragmentShaderCode = `precision highp float;uniform vec2 u_resolution;uniform float u_time;varying vec2 vUv;#define EPSILON 1e-6#define PI 3.14159265359#define ITERATIONS 18.0mat2 rotate2d(float angle){return mat2(cos(angle), -sin(angle),sin(angle), cos(angle));}void main() {vec2 uv = (vUv * 2.0 - 1.0) * (u_resolution / max(u_resolution.x, u_resolution.y));vec2 u = uv * 0.25;vec4 o = vec4(0.5, 1.0, 1.5, 0.0);vec4 z = o;vec2 v_internal = vec2(0.0);float a = 0.6;float t = u_time * 0.8;for (float i = 0.0; i < ITERATIONS; i++){float u_dot = dot(u, u);float denom_u = 0.6 - u_dot;denom_u += sign(denom_u) * EPSILON;vec2 sin_arg = (1.4 * u / denom_u) - (7.0 * u.yx * cos(t*0.2)) + t * 1.1 + v_internal * 0.3;vec2 length_arg = (1.0 + i * 0.1 + a * 0.2) * sin(sin_arg);float len = length(length_arg);float safe_len_divisor = max(len, EPSILON);o += (1.0 + sin(z * 0.9 + t * 1.2 + i * 0.1)) / safe_len_divisor * (1.0 + i*0.02);v_internal = 0.9 * v_internal + 0.15 * sin(t * 1.5 + u * 4.0 - o.xy * 0.2);v_internal = clamp(v_internal, -1.0, 1.0);a += 0.035;float angle = i * 0.1 + t * 0.05 + a * 0.2;mat2 rot_mat = rotate2d(angle);u *= rot_mat;float o_dot = dot(o.xyz, o.xyz);float feedback_scale = 0.5 + 0.5 * sin(o_dot * 0.02 + t * 0.3);u += sin(60.0 * dot(u,u) * cos(80.0 * u.yx + t * 1.2)) / 2.5e2+ 0.15 * a * u * feedback_scale+ cos(o.xy * 0.5 + t * 1.1 + v_internal * 0.8) / 3.5e2;u += rotate2d(v_internal.x * 0.01) * vec2(0.0001, 0.0);}vec3 base_color = 0.5 + 0.5 * cos(o.xyz * 0.8 + t * 0.15 + vec3(0.0, PI * 0.66, PI * 1.33));vec2 detail_coord = u * 5.0 + v_internal * 1.0;float detail_pattern = smoothstep(0.3, 0.7, fract(detail_coord.x * cos(t*0.1) + detail_coord.y * sin(t*0.1)));vec3 detail_color = vec3(detail_pattern * 0.8 + 0.2);float mix_factor = clamp(length(o.xyz) * 0.1 - 0.1, 0.0, 1.0);vec3 final_color = mix(base_color, detail_color * base_color, mix_factor);final_color.rg += u.xy * 0.05;float dist_from_center = length(vUv - 0.5);final_color *= pow(1.0 - dist_from_center * 1.2, 2.0);gl_FragColor = vec4(clamp(final_color, 0.0, 1.0), 1.0);}
`;const vertexShaderCode = `varying vec2 vUv;void main() {vUv = uv;gl_Position = vec4( position, 1.0 );}
`;let scene, camera, renderer, mesh, material, clock;let container;const uniforms = {u_time: { value: 0.0 },u_resolution: { value: new THREE.Vector2() }};function init() {container = document.getElementById('container');clock = new THREE.Clock();renderer = new THREE.WebGLRenderer();renderer.setSize(window.innerWidth, window.innerHeight);renderer.setPixelRatio(window.devicePixelRatio);container.appendChild(renderer.domElement);scene = new THREE.Scene();camera = new THREE.OrthographicCamera(-1, 1, 1, -1, 0, 1);const geometry = new THREE.PlaneGeometry(2, 2);material = new THREE.ShaderMaterial({uniforms: uniforms,vertexShader: vertexShaderCode,fragmentShader: fragmentShaderCode});mesh = new THREE.Mesh(geometry, material);scene.add(mesh);uniforms.u_resolution.value.x = window.innerWidth;uniforms.u_resolution.value.y = window.innerHeight;window.addEventListener('resize', onWindowResize);renderer.setAnimationLoop(animate);console.log("Three.js setup complete. Starting animation loop.");}function onWindowResize() {renderer.setSize(window.innerWidth, window.innerHeight);uniforms.u_resolution.value.x = window.innerWidth;uniforms.u_resolution.value.y = window.innerHeight;material.uniforms.u_resolution.value.set(window.innerWidth, window.innerHeight);}function animate() {uniforms.u_time.value = clock.getElapsedTime();renderer.render(scene, camera);}init();
</script>
</body>
</html

效果如下
在这里插入图片描述
参考:源码

http://www.dtcms.com/a/263639.html

相关文章:

  • 电机参数测量
  • 自由学习记录(66)
  • JT808教程:消息的结构
  • react中在Antd3.x版本中 Select框在单选时 选中框的高度调整
  • Qt 实现Opencv功能模块切换界面功能
  • 【算法】动态规划:python实现 1
  • TensorFlow内核剖析:分布式TensorFlow架构解析与实战指南
  • mini-electron使用方法
  • 内部类与Lambda的衍生关系(了解学习内部类,Lambda一篇即可)
  • C# WPF + Helix Toolkit 实战:用两种方式打造“六面异色立方体”
  • QNN SDK学习笔记
  • 二十八、【环境管理篇】灵活应对:多测试环境配置与切换
  • python开发|yaml用法知识介绍
  • STM32F4操作内部FLASH简洁版
  • 【代码审计】安全审核常见漏洞修复策略
  • 位运算经典题解
  • 启用不安全的HTTP方法
  • 图像处理专业书籍以及网络资源总结
  • Java编程之状态模式
  • 《UE5_C++多人TPS完整教程》学习笔记40 ——《P41 装备(武器)姿势(Equipped Pose)》
  • 基于Socketserver+ThreadPoolExecutor+Thread构造的TCP网络实时通信程序
  • mac重复文件清理,摄影师同款清理方案
  • flv.js视频/直播流测试demo
  • 2025 推理技术风向标:DeepSeek-R1 揭示大模型从 “记忆” 到 “思考” 的进化路径
  • 【linux】基础开发工具(1)
  • Flink Savepoints 总结
  • js代码09
  • Spring Boot WebSocket方案终极指南:Netty与官方Starter对比与实践
  • MFC的List Control自适应主界面大小
  • Android Gradle 插件和 Android Studio 兼容性