【视觉基础篇】14 # 如何使用片元着色器进行几何造型?

news/2024/5/15 13:35:11/文章来源:https://blog.csdn.net/kaimo313/article/details/126834120

说明

【跟月影学可视化】学习笔记。

如何用片元着色器控制局部颜色?

把图片绘制为纯黑色:

const fragment = `#ifdef GL_ESprecision highp float;#endifvarying vec2 vUv;void main() {gl_FragColor = vec4(0, 0, 0, 1);}
`;

在这里插入图片描述
根据纹理坐标值来绘制,让某个图案的颜色,从左到右由黑向白过渡

const fragment = `#ifdef GL_ESprecision highp float;#endifvarying vec2 vUv;void main() {gl_FragColor.rgb = vec3(vUv.x);gl_FragColor.a = 1.0;}
`;

在这里插入图片描述
使用乘法创造一个 10*10 的方格,让每个格子左上角是绿色,右下角是红色,中间是过渡色。

const fragment = `#ifdef GL_ESprecision highp float;#endifvarying vec2 vUv;void main() {vec2 st = vUv * 10.0;gl_FragColor.rgb = vec3(fract(st), 0.0);gl_FragColor.a = 1.0;}
`;

在这里插入图片描述

通过 idx = floor(st) 获取网格的索引,判断网格索引除以 2 的余数(奇偶性),根据它来决定是否翻转网格内的 x、y 坐标。

<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8" /><meta http-equiv="X-UA-Compatible" content="IE=edge" /><meta name="viewport" content="width=device-width, initial-scale=1.0" /><title>如何用片元着色器控制局部颜色?</title><style>canvas {border: 1px dashed salmon;}</style></head><body><canvas width="512" height="512"></canvas><script src="./common/lib/gl-renderer.js"></script><script>const vertex = `attribute vec2 a_vertexPosition;attribute vec2 uv;varying vec2 vUv;void main() {gl_PointSize = 1.0;vUv = uv;gl_Position = vec4(a_vertexPosition, 1, 1);}`;// // 把图片绘制为纯黑色// const fragment = `//     #ifdef GL_ES//     precision highp float;//     #endif//     varying vec2 vUv;//     void main() {//         gl_FragColor = vec4(0, 0, 0, 1);//     }// `;// // 根据纹理坐标值来绘制,让某个图案的颜色,从左到右由黑向白过渡// const fragment = `//     #ifdef GL_ES//     precision highp float;//     #endif//     varying vec2 vUv;//     void main() {//         gl_FragColor.rgb = vec3(vUv.x);//         gl_FragColor.a = 1.0;//     }// `;// // 使用乘法创造一个 10*10 的方格,让每个格子左上角是绿色,右下角是红色,中间是过渡色。// const fragment = `//     #ifdef GL_ES//     precision highp float;//     #endif//     varying vec2 vUv;//     void main() {//         vec2 st = vUv * 10.0;//         gl_FragColor.rgb = vec3(fract(st), 0.0);//         gl_FragColor.a = 1.0;//     }// `;// 通过 idx = floor(st) 获取网格的索引,判断网格索引除以 2 的余数(奇偶性),根据它来决定是否翻转网格内的 x、y 坐标。const fragment = `#ifdef GL_ESprecision highp float;#endifvarying vec2 vUv;void main() {vec2 st = vUv * 10.0;vec2 idx = floor(st);vec2 grid = fract(st);vec2 t = mod(idx, 2.0);if(t.x == 1.0) {grid.x = 1.0 - grid.x;}if(t.y == 1.0) {grid.y = 1.0 - grid.y;}gl_FragColor.rgb = vec3(grid, 0.0);gl_FragColor.a = 1.0;}`;const canvas = document.querySelector("canvas");const renderer = new GlRenderer(canvas);// 加载片元着色器并创建程序const program = renderer.compileSync(fragment, vertex);renderer.useProgram(program);// 将顶点数据送入缓冲区renderer.setMeshData([{positions: [[-1, -1],[-1, 1],[1, 1],[1, -1],],attributes: {uv: [[0, 0],[0, 1],[1, 1],[1, 0],],},cells: [[0, 1, 2],[2, 0, 3],],},]);// 渲染renderer.render();</script></body>
</html>

在这里插入图片描述

如何用片元着色器绘制圆、线段和几何图形

绘制圆

绘制一个模糊的圆

const fragment = `#ifdef GL_ESprecision highp float;#endifvarying vec2 vUv;void main() {floatd = distance(vUv, vec2(0.5));gl_FragColor.rgb = d * vec3(1.0);gl_FragColor.a = 1.0;}
`;

在这里插入图片描述
绘制一个清晰的圆

const fragment = `#ifdef GL_ESprecision highp float;#endifvarying vec2 vUv;void main() {float d = distance(vUv, vec2(0.5));gl_FragColor.rgb = step(d, 0.2) * vec3(1.0);gl_FragColor.a = 1.0;}
`;

在这里插入图片描述
因为浮点数计算的精度导致的锯齿现象。用 smoothstep 代替 step 即可解决这种问题。smoothstep 在 step-start 和 step-end 之间有一个平滑过渡的区间。

在这里插入图片描述

<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8" /><meta http-equiv="X-UA-Compatible" content="IE=edge" /><meta name="viewport" content="width=device-width, initial-scale=1.0" /><title>片元着色器绘制圆</title><style>canvas {border: 1px dashed salmon;}</style></head><body><canvas width="512" height="512"></canvas><script src="./common/lib/gl-renderer.js"></script><script>const vertex = `attribute vec2 a_vertexPosition;attribute vec2 uv;varying vec2 vUv;void main() {gl_PointSize = 1.0;vUv = uv;gl_Position = vec4(a_vertexPosition, 1, 1);}`;// // 模糊的圆// const fragment = `//     #ifdef GL_ES//     precision highp float;//     #endif//     varying vec2 vUv;//     void main() {//         float d = distance(vUv, vec2(0.5));//         gl_FragColor.rgb = d * vec3(1.0);//         gl_FragColor.a = 1.0;//     }// `;// // 清晰的圆// const fragment = `//     #ifdef GL_ES//     precision highp float;//     #endif//     varying vec2 vUv;//     void main() {//         float d = distance(vUv, vec2(0.5));//         gl_FragColor.rgb = step(d, 0.2) * vec3(1.0);//         gl_FragColor.a = 1.0;//     }// `;// 清晰的圆无锯齿const fragment = `#ifdef GL_ESprecision highp float;#endifvarying vec2 vUv;void main() {float d = distance(vUv, vec2(0.5));gl_FragColor.rgb = smoothstep(d, d + 0.01, 0.2) * vec3(1.0);gl_FragColor.a = 1.0;}`;const canvas = document.querySelector("canvas");const renderer = new GlRenderer(canvas);// 加载片元着色器并创建程序const program = renderer.compileSync(fragment, vertex);renderer.useProgram(program);// 将顶点数据送入缓冲区renderer.setMeshData([{positions: [[-1, -1],[-1, 1],[1, 1],[1, -1],],attributes: {uv: [[0, 0],[0, 1],[1, 1],[1, 0],],},cells: [[0, 1, 2],[2, 0, 3],],},]);// 渲染renderer.render();</script></body>
</html>

在这里插入图片描述

实现图片的渐显渐隐效果

上一节我们实现了图片粒子化,下面利用绘制圆实现图片的渐显渐隐效果

<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8" /><meta http-equiv="X-UA-Compatible" content="IE=edge" /><meta name="viewport" content="width=device-width, initial-scale=1.0" /><title>片元着色器绘制圆实现图片的渐显渐隐效果</title><style>canvas {border: 1px dashed salmon;}</style></head><body><canvas width="1920" height="1080"></canvas><script src="./common/lib/gl-renderer.js"></script><script>const vertex = `attribute vec2 a_vertexPosition;attribute vec2 uv;varying vec2 vUv;void main() {gl_PointSize = 1.0;vUv = uv;gl_Position = vec4(a_vertexPosition, 1, 1);}`;const fragment = `#ifdef GL_ESprecision highp float;#endifuniform sampler2D tMap;uniform vec2 uResolution;uniform float uTime;varying vec2 vUv;float random (vec2 st) {return fract(sin(dot(st.xy, vec2(12.9898,78.233)))*43758.5453123);}void main() {vec2 uv = vUv;uv.y *= uResolution.y / uResolution.x;vec2 st = uv * 100.0;float d = distance(fract(st), vec2(0.5));float p = uTime + random(floor(st));float shading = 0.5 + 0.5 * sin(p);d = smoothstep(d, d + 0.01, 1.0 * shading);vec4 color = texture2D(tMap, vUv);gl_FragColor.rgb = color.rgb * clamp(0.5, 1.3, d + 1.0 * shading);gl_FragColor.a = color.a;}`;const canvas = document.querySelector("canvas");const renderer = new GlRenderer(canvas);// 加载片元着色器并创建程序const program = renderer.compileSync(fragment, vertex);renderer.useProgram(program);(async function () {const texture = await renderer.loadTexture('./assets/img/flower.jpg');renderer.uniforms.tMap = texture;renderer.uniforms.uResolution = [canvas.width, canvas.height];renderer.uniforms.uTime = 0;// 将顶点数据送入缓冲区renderer.setMeshData([{positions: [[-1, -1],[-1, 1],[1, 1],[1, -1],],attributes: {uv: [[0, 0],[0, 1],[1, 1],[1, 0],],},cells: [[0, 1, 2], [2, 0, 3]],}]);renderer.render();function update(t) {renderer.uniforms.uTime = t / 500;requestAnimationFrame(update);}update(0);}());</script></body>
</html>

在这里插入图片描述

绘制线

计算点到直线(向量)的距离即可。

<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8" /><meta http-equiv="X-UA-Compatible" content="IE=edge" /><meta name="viewport" content="width=device-width, initial-scale=1.0" /><title>片元着色器绘制圆</title><style>canvas {border: 1px dashed salmon;}</style></head><body><canvas width="512" height="512"></canvas><script src="./common/lib/gl-renderer.js"></script><script>const vertex = `attribute vec2 a_vertexPosition;attribute vec2 uv;varying vec2 vUv;void main() {gl_PointSize = 1.0;vUv = uv;gl_Position = vec4(a_vertexPosition, 1, 1);}`;// 画出一条斜线const fragment = `#ifdef GL_ESprecision highp float;#endifvarying vec2 vUv;void main() {vec3 line = vec3(1, 1, 0);float d = abs(cross(vec3(vUv,0), normalize(line)).z); gl_FragColor.rgb = (1.0 - smoothstep(0.0, 0.01, d)) * vec3(1.0);gl_FragColor.a = 1.0;}`;const canvas = document.querySelector("canvas");const renderer = new GlRenderer(canvas);// 加载片元着色器并创建程序const program = renderer.compileSync(fragment, vertex);renderer.useProgram(program);// 将顶点数据送入缓冲区renderer.setMeshData([{positions: [[-1, -1],[-1, 1],[1, 1],[1, -1],],attributes: {uv: [[0, 0],[0, 1],[1, 1],[1, 0],],},cells: [[0, 1, 2],[2, 0, 3],],},]);// 渲染renderer.render();</script></body>
</html>

在这里插入图片描述

用鼠标控制直线

<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8" /><meta http-equiv="X-UA-Compatible" content="IE=edge" /><meta name="viewport" content="width=device-width, initial-scale=1.0" /><title>用鼠标控制直线</title><style>canvas {border: 1px dashed salmon;}</style></head><body><canvas width="512" height="512"></canvas><script src="./common/lib/gl-renderer.js"></script><script>const vertex = `attribute vec2 a_vertexPosition;attribute vec2 uv;varying vec2 vUv;void main() {gl_PointSize = 1.0;vUv = uv;gl_Position = vec4(a_vertexPosition, 1, 1);}`;const fragment = `#ifdef GL_ESprecision highp float;#endifvarying vec2 vUv;uniform vec2 uMouse;uniform vec2 uOrigin;// 返回点到线段的距离float seg_distance(in vec2 st, in vec2 a, in vec2 b) {vec3 ab = vec3(b - a, 0);vec3 p = vec3(st - a, 0);float l = length(ab);float d = abs(cross(p, normalize(ab)).z);float proj = dot(p, ab) / l;if(proj >= 0.0 && proj <= l) return d;return min(distance(st, a), distance(st, b));}void main() {float d = seg_distance(vUv, uMouse, uOrigin); gl_FragColor.rgb = (1.0 - smoothstep(0.0, 0.01, d)) * vec3(1.0);gl_FragColor.a = 1.0;}`;const canvas = document.querySelector("canvas");const renderer = new GlRenderer(canvas);// 加载片元着色器并创建程序const program = renderer.compileSync(fragment, vertex);renderer.useProgram(program);renderer.uniforms.uMouse = [-1, -1];// 直线经过的固定点renderer.uniforms.uOrigin = [0.5, 0.5];canvas.addEventListener("mousemove", (e) => {const { x, y, width, height } =e.target.getBoundingClientRect();renderer.uniforms.uMouse = [(e.x - x) / width,1.0 - (e.y - y) / height,];});// 将顶点数据送入缓冲区renderer.setMeshData([{positions: [[-1, -1],[-1, 1],[1, 1],[1, -1],],attributes: {uv: [[0, 0],[0, 1],[1, 1],[1, 0],],},cells: [[0, 1, 2],[2, 0, 3],],},]);// 渲染renderer.render();</script></body>
</html>

在这里插入图片描述

绘制三角形

点到三角形三条边的距离有三个,只要这三个距离的符号都相同,我们就能确定点在三角形内。

<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8" /><meta http-equiv="X-UA-Compatible" content="IE=edge" /><meta name="viewport" content="width=device-width, initial-scale=1.0" /><title>片元着色器绘制三角形</title><style>canvas {border: 1px dashed salmon;}</style></head><body><canvas width="512" height="512"></canvas><script src="./common/lib/gl-renderer.js"></script><script>const vertex = `attribute vec2 a_vertexPosition;attribute vec2 uv;varying vec2 vUv;void main() {gl_PointSize = 1.0;vUv = uv;gl_Position = vec4(a_vertexPosition, 1, 1);}`;const fragment = `#ifdef GL_ESprecision highp float;#endifvarying vec2 vUv;float line_distance(in vec2 st, in vec2 a, in vec2 b) {vec3 ab = vec3(b - a, 0);vec3 p = vec3(st - a, 0);float l = length(ab);return cross(p, normalize(ab)).z;}float seg_distance(in vec2 st, in vec2 a, in vec2 b) {vec3 ab = vec3(b - a, 0);vec3 p = vec3(st - a, 0);float l = length(ab);float d = abs(cross(p, normalize(ab)).z);float proj = dot(p, ab) / l;if(proj >= 0.0 && proj <= l) return d;return min(distance(st, a), distance(st, b));}float triangle_distance(in vec2 st, in vec2 a, in vec2 b, in vec2 c) {float d1 = line_distance(st, a, b);float d2 = line_distance(st, b, c);float d3 = line_distance(st, c, a);if(d1 >= 0.0 && d2 >= 0.0 && d3 >= 0.0 || d1 <= 0.0 && d2 <= 0.0 && d3 <= 0.0) {return -min(abs(d1), min(abs(d2), abs(d3))); // 内部距离为负}return min(seg_distance(st, a, b), min(seg_distance(st, b, c), seg_distance(st, c, a))); // 外部为正}void main() {float d = triangle_distance(vUv, vec2(0.3), vec2(0.5, 0.7), vec2(0.7, 0.3));gl_FragColor.rgb = (1.0 - smoothstep(0.0, 0.01, d)) * vec3(1.0);gl_FragColor.a = 1.0;}`;const canvas = document.querySelector("canvas");const renderer = new GlRenderer(canvas);// 加载片元着色器并创建程序const program = renderer.compileSync(fragment, vertex);renderer.useProgram(program);// 将顶点数据送入缓冲区renderer.setMeshData([{positions: [[-1, -1],[-1, 1],[1, 1],[1, -1],],attributes: {uv: [[0, 0],[0, 1],[1, 1],[1, 0],],},cells: [[0, 1, 2],[2, 0, 3],],},]);// 渲染renderer.render();</script></body>
</html>

在这里插入图片描述

片元着色器绘图方法论:符号距离场渲染

在图形渲染中有一个专有的名称叫做符号距离场渲染Signed Distance Fields Rendering)。它本质上就是利用空间中的距离分布来着色的。

  • 第一步:定义距离。
  • 第二步:根据距离着色。

绘制平面分割线

constfragment = `#ifdef GL_ESprecision highp float;#endifvarying vec2 vUv;void main() {vec3 line = vec3(1, 1, 0);float d = abs(cross(vec3(vUv,0), normalize(line)).z);d = fract(20.0 * d);gl_FragColor.rgb = (smoothstep(0.45, 0.5, d) - smoothstep(0.5, 0.55, d)) * vec3(1.0);gl_FragColor.a = 1.0;}
`;

在这里插入图片描述

绘制圆环

const fragment = `#ifdef GL_ESprecision highp float;#endifvarying vec2 vUv;void main() {float d = distance(vUv, vec2(0.5));d = fract(20.0 * d);gl_FragColor.rgb = (smoothstep(0.45, 0.5, d) - smoothstep(0.5, 0.55, d)) * vec3(1.0);gl_FragColor.a = 1.0;}
`;

在这里插入图片描述

绘制三角环

<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8" /><meta http-equiv="X-UA-Compatible" content="IE=edge" /><meta name="viewport" content="width=device-width, initial-scale=1.0" /><title>片元着色器绘图方法论:符号距离场渲染</title><style>canvas {border: 1px dashed salmon;}</style></head><body><canvas width="512" height="512"></canvas><script src="./common/lib/gl-renderer.js"></script><script>const vertex = `attribute vec2 a_vertexPosition;attribute vec2 uv;varying vec2 vUv;void main() {gl_PointSize = 1.0;vUv = uv;gl_Position = vec4(a_vertexPosition, 1, 1);}`;// // 绘制平面分割线// const fragment = `//     #ifdef GL_ES//     precision highp float;//     #endif//     varying vec2 vUv;//     void main() {//         vec3 line = vec3(1, 1, 0);//         float d = abs(cross(vec3(vUv,0), normalize(line)).z);//         d = fract(20.0 * d);//         gl_FragColor.rgb = (smoothstep(0.45, 0.5, d) - smoothstep(0.5, 0.55, d)) * vec3(1.0);//         gl_FragColor.a = 1.0;//     }// `;// // 绘制圆环// const fragment = `//     #ifdef GL_ES//     precision highp float;//     #endif//     varying vec2 vUv;//     void main() {//         float d = distance(vUv, vec2(0.5));//         d = fract(20.0 * d);//         gl_FragColor.rgb = (smoothstep(0.45, 0.5, d) - smoothstep(0.5, 0.55, d)) * vec3(1.0);//         gl_FragColor.a = 1.0;//     }// `;// 绘制三角环const fragment = `#ifdef GL_ESprecision highp float;#endifvarying vec2 vUv;float line_distance(in vec2 st, in vec2 a, in vec2 b) {vec3 ab = vec3(b - a, 0);vec3 p = vec3(st - a, 0);float l = length(ab);return cross(p, normalize(ab)).z;}float seg_distance(in vec2 st, in vec2 a, in vec2 b) {vec3 ab = vec3(b - a, 0);vec3 p = vec3(st - a, 0);float l = length(ab);float d = abs(cross(p, normalize(ab)).z);float proj = dot(p, ab) / l;if(proj >= 0.0 && proj <= l) return d;return min(distance(st, a), distance(st, b));}float triangle_distance(in vec2 st, in vec2 a, in vec2 b, in vec2 c) {float d1 = line_distance(st, a, b);float d2 = line_distance(st, b, c);float d3 = line_distance(st, c, a);if(d1 >= 0.0 && d2 >= 0.0 && d3 >= 0.0 || d1 <= 0.0 && d2 <= 0.0 && d3 <= 0.0) {return -min(abs(d1), min(abs(d2), abs(d3))); // 内部距离为负}return min(seg_distance(st, a, b), min(seg_distance(st, b, c), seg_distance(st, c, a))); // 外部为正}void main() {float d = triangle_distance(vUv, vec2(0.3), vec2(0.5, 0.7), vec2(0.7, 0.3));d = fract(20.0 * abs(d));// gl_FragColor.rgb = vec3(d); // vec3(d) 来渲染颜色gl_FragColor.rgb = (smoothstep(0.45, 0.5, d) - smoothstep(0.5, 0.55, d)) * vec3(1.0);gl_FragColor.a = 1.0;}`;const canvas = document.querySelector("canvas");const renderer = new GlRenderer(canvas);// 加载片元着色器并创建程序const program = renderer.compileSync(fragment, vertex);renderer.useProgram(program);// 将顶点数据送入缓冲区renderer.setMeshData([{positions: [[-1, -1],[-1, 1],[1, 1],[1, -1],],attributes: {uv: [[0, 0],[0, 1],[1, 1],[1, 0],],},cells: [[0, 1, 2],[2, 0, 3],],},]);// 渲染renderer.render();</script></body>
</html>

在这里插入图片描述

vec3(d) 来渲染颜色

在这里插入图片描述

着色器绘制几何图形的用途

  • 实现图像的剪裁
  • 实现对图像的动态修饰
  • 可以在一些 3D 场景中修饰几何体

实现图像的剪裁

<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8" /><meta http-equiv="X-UA-Compatible" content="IE=edge" /><meta name="viewport" content="width=device-width, initial-scale=1.0" /><title>着色器造型实现图像的剪裁</title>
</head><body><canvas width="1920" height="1080"></canvas><script src="./common/lib/gl-renderer.js"></script><script>const vertex = `attribute vec2 a_vertexPosition;attribute vec2 uv;varying vec2 vUv;void main() {gl_PointSize = 1.0;vUv = uv;gl_Position = vec4(a_vertexPosition, 1, 1);}`;const fragment = `#ifdef GL_ESprecision highp float;#endifvarying vec2 vUv;uniform sampler2D tMap;uniform float uTime;float line_distance(in vec2 st, in vec2 a, in vec2 b) {vec3 ab = vec3(b - a, 0);vec3 p = vec3(st - a, 0);float l = length(ab);return cross(p, normalize(ab)).z;}float seg_distance(in vec2 st, in vec2 a, in vec2 b) {vec3 ab = vec3(b - a, 0);vec3 p = vec3(st - a, 0);float l = length(ab);float d = abs(cross(p, normalize(ab)).z);float proj = dot(p, ab) / l;if(proj >= 0.0 && proj <= l) return d;return min(distance(st, a), distance(st, b));}float triangle_distance(in vec2 st, in vec2 a, in vec2 b, in vec2 c) {float d1 = line_distance(st, a, b);float d2 = line_distance(st, b, c);float d3 = line_distance(st, c, a);if(d1 >= 0.0 && d2 >= 0.0 && d3 >= 0.0 || d1 <= 0.0 && d2 <= 0.0 && d3 <= 0.0) {return -min(abs(d1), min(abs(d2), abs(d3))); // 内部距离为负}return min(seg_distance(st, a, b), min(seg_distance(st, b, c), seg_distance(st, c, a))); // 外部为正}void main() {vec4 color = texture2D(tMap, vUv);vec2 uv = vUv - vec2(0.5);vec2 a = vec2(-0.577, 0) - vec2(0.5);vec2 b = vec2(0.5, 1.866) - vec2(0.5);vec2 c = vec2(1.577, 0) - vec2(0.5);float scale = min(1.0, 0.0005 * uTime);float d = triangle_distance(uv, scale * a, scale * b, scale * c);gl_FragColor.rgb = (1.0 - smoothstep(0.0, 0.01, d)) * color.rgb;gl_FragColor.a = 1.0;}`;const canvas = document.querySelector('canvas');const renderer = new GlRenderer(canvas);// load fragment shader and createProgramconst program = renderer.compileSync(fragment, vertex);renderer.useProgram(program);(async function () {const texture = await renderer.loadTexture('./assets/img/flower.jpg');renderer.uniforms.tMap = texture;renderer.uniforms.uTime = 0;renderer.setMeshData([{positions: [[-1, -1],[-1, 1],[1, 1],[1, -1],],attributes: {uv: [[0, 0],[0, 1],[1, 1],[1, 0],],},cells: [[0, 1, 2], [2, 0, 3]],}]);renderer.render();function update(t) {renderer.uniforms.uTime = t / 2;requestAnimationFrame(update);}update(0);}());</script></script>
</body></html>

在这里插入图片描述

实现对图像的动态修饰

<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8" /><meta http-equiv="X-UA-Compatible" content="IE=edge" /><meta name="viewport" content="width=device-width, initial-scale=1.0" /><title>实现对图像的动态修饰</title>
</head><body><canvas width="1920" height="1080"></canvas><script src="./common/lib/gl-renderer.js"></script><script>const vertex = `attribute vec2 a_vertexPosition;attribute vec2 uv;varying vec2 vUv;void main() {gl_PointSize = 1.0;vUv = uv;gl_Position = vec4(a_vertexPosition, 1, 1);}`;const fragment = `#ifdef GL_ESprecision highp float;#endifvarying vec2 vUv;uniform sampler2D tMap;uniform float uTime;float line_distance(in vec2 st, in vec2 a, in vec2 b) {vec3 ab = vec3(b - a, 0);vec3 p = vec3(st - a, 0);float l = length(ab);return cross(p, normalize(ab)).z;}float seg_distance(in vec2 st, in vec2 a, in vec2 b) {vec3 ab = vec3(b - a, 0);vec3 p = vec3(st - a, 0);float l = length(ab);float d = abs(cross(p, normalize(ab)).z);float proj = dot(p, ab) / l;if(proj >= 0.0 && proj <= l) return d;return min(distance(st, a), distance(st, b));}float triangle_distance(in vec2 st, in vec2 a, in vec2 b, in vec2 c) {float d1 = line_distance(st, a, b);float d2 = line_distance(st, b, c);float d3 = line_distance(st, c, a);if(d1 >= 0.0 && d2 >= 0.0 && d3 >= 0.0 || d1 <= 0.0 && d2 <= 0.0 && d3 <= 0.0) {return -min(abs(d1), min(abs(d2), abs(d3))); // 内部距离为负}return min(seg_distance(st, a, b), min(seg_distance(st, b, c), seg_distance(st, c, a))); // 外部为正}void main() {vec4 color = texture2D(tMap, vUv);vec2 uv = vUv - vec2(0.5);vec2 a = vec2(0, 1);float time = 0.0005 * uTime;vec2 b = vec2(sin(time), cos(time));float d = 0.0;float c0 = cross(vec3(b, 0.0), vec3(a, 0.0)).z;float c1 = cross(vec3(uv, 0.0), vec3(a, 0.0)).z;float c2 = cross(vec3(uv, 0.0), vec3(b, 0.0)).z;if(c0 > 0.0 && c1 > 0.0 && c2 < 0.0) {d = 1.0;}if(c0 < 0.0 && (c1 >= 0.0 || c2 <= 0.0)) {d = 1.0;}gl_FragColor.rgb = color.rgb;gl_FragColor.r *= mix(0.3, 1.0, d);gl_FragColor.a = mix(0.9, 1.0, d);}`;const canvas = document.querySelector('canvas');const renderer = new GlRenderer(canvas);// load fragment shader and createProgramconst program = renderer.compileSync(fragment, vertex);renderer.useProgram(program);(async function () {const texture = await renderer.loadTexture('./assets/img/flower.jpg');renderer.uniforms.tMap = texture;renderer.uniforms.uTime = 0;renderer.setMeshData([{positions: [[-1, -1],[-1, 1],[1, 1],[1, -1],],attributes: {uv: [[0, 0],[0, 1],[1, 1],[1, 0],],},cells: [[0, 1, 2], [2, 0, 3]],}]);renderer.render();function update(t) {renderer.uniforms.uTime = 2*t;requestAnimationFrame(update);}update(0);}());</script></script>
</body></html>

在这里插入图片描述

推荐网址

  • 构建和分享世界上你最喜欢的着色器并受启发:shadertoy

在这里插入图片描述

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.luyixian.cn/news_show_410053.aspx

如若内容造成侵权/违法违规/事实不符,请联系dt猫网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

工地ai智能视频监控系统

工地ai智能视频监控系统在监控摄像头监控的画面范围之内&#xff0c;对人的不安全行为&#xff08;违规行为&#xff09;或者物的不安全状态进行实时分析识别&#xff0c;当工地ai智能视频监控系统发现现场违规行为时&#xff0c;可根据需要设置各种警戒要求&#xff0c;工地ai…

【计算机网络--物理层】编码和调制与数据交换方式

注&#xff1a;最后有面试挑战&#xff0c;看看自己掌握了吗 文章目录基带信号与宽带信号基带信号宽带信号小结编码与调制编码调制的方法数字数据编码为数字信号数字数字调制为模拟信号模拟数据编码为数字信号模拟信号调制为模拟信号数据交换电路交换报文交换分组交换数据报方式…

windows系统命令行查看已连接过的WiFi密码

展示所有连接过的WiFi列表netsh wlan show profiles 显示具体某个WiFi的密码netsh wlan show profiles name="XXXXXX" key=clear name - 所要显示配置文件的名称。就是WiFi的名称 interface - 已配置此配置文件的接口的名称。 key - 以纯…

跨境电商万圣节社媒营销:8个方法助你冲出重围

今天是西方一年一度的万圣节前夜&#xff0c;同时也是跨境电商第四季度第一个大促日。Nox聚星获悉&#xff0c;2022年万圣节期间会有69%的美国民众参与这场万圣节狂欢&#xff0c;预计人均消费将达到100.45美金&#xff0c;预计将产生106亿的销售额。作为四季度第一个促销日&am…

【飞桨PaddleSpeech语音技术课程】— 多语言合成与小样本合成技术应用实践

(以下内容搬运自飞桨PaddleSpeech语音技术课程&#xff0c;点击链接可直接运行源码) 多语言合成与小样本合成技术应用实践 一 简介 1.1 语音合成的简介 语音合成是一种将文本转换成音频的技术。通常语音合成的整体流程如图1所示。可以分为&#xff1a;文本前端&#xff0c;…

团队分工越明确,工作效率越低?

一个团队各项任务能否顺利完成,关键看员工的执行力,而员工执行力的发挥,取决于组织对员工的合理分工。 分工合理,能调动员工的积极性,分工不合理,便会扼杀积极性。 那么如何才能做到合理分工呢?有些人认为分工就是把工作内容拆成一个个小任务,然后让员工去分头完成。…

C语言学习推荐---小游戏

文章目录控制台文字游戏srand、rand、time猜拳游戏控制台动作游戏运动的小球贪吃蛇音乐图形界面easyx介绍后续学习c语言的时候&#xff0c;想写例子&#xff0c;但是课后习题又太枯燥怎么办&#xff1f; 写小游戏可以锻炼我们的编程抽象能力和思维&#xff0c;而且比较有趣&…

基于nodejs电影交流网站设计与实现-计算机毕业设计源码+LW文档

摘 要 网络的广泛应用给生活带来了十分的便利。所以把电影交流管理与现在网络相结合&#xff0c;利用nodejs技术建设电影交流网站&#xff0c;实现电影交流的信息化。则对于进一步提高电影交流管理发展&#xff0c;丰富电影交流管理经验能起到不少的促进作用。 电影交流网站能…

论文研读1——对抗样本(Adversarial Example)综述

论文地址&#xff1a;Threat of Adversarial Attacks on Deep Learning in Computer Vision: A Survey 部分内容参考科研篇二&#xff1a;对抗样本&#xff08;Adversarial Example&#xff09;综述 一、主要内容 肯定了深度学习在计算机视觉等领域的贡献&#xff0c;但深度…

后端开发总结(2):go语言的知识点

go语言知识点1 append 列表2 如何打印指针结构体的值3 * 和 & 的用法1 append 列表 append() 切片需要增加 ... var a []inta append(a, 1) // 追加1个元素 a append(a, 1, 2, 3) // 追加多个元素 a append(a, []int{1,2,3}...) // 追加切片,2 如何打印指针结构体的值…

如何将程序打包成exe

我们经常需要将我们写的程序打包发给用户使用&#xff0c;很多时候为了方便会直接将文件夹或者压缩包发出去。这种方式对于一些不太懂电脑的用户来说的话&#xff0c;假如程序中有多个可执行文件&#xff0c;就会完全不知道怎么使用。众所周知&#xff0c;客户体验也是评判软件…

SpringBoot笔记:Hello World

SpringBoot简化了Spring应用的初始框架搭建和开发过程,利用SpringBoot框架可以快速的进行Spring应用的开发,SpringBoot具有以下特性:能够快速创建基于Spring的应用程序。 提供了约定好的初始POM来简化Maven配置,让Maven配置变得更简单。 多数情况可以直接使用注解开发来替代…

标准库类型string和vector

一、命名空间 std::cinstd就是命名空间&#xff0c; 这个的含义是 &#xff1a;编译器应该从操作符左侧的名字所示的作用域std中去寻找cin。 另一种方式就是在开头显式进行说明&#xff1a; using std::cin;这样一来后续就不用再去在每条语句中显式说明了。 需要注意的是&…

Java垃圾回收器

Java垃圾回收器1 GC分类与性能指标1.1 垃圾回收器概述1.2 垃圾回收器分类1.2.1 按照线程分1.2.2 按照工作模式分1.2.3 碎片处理方式分1.2.4 工作的内存区间分1.3 评估GC的性能指标1.4 吞吐量与暂停时间的对比说明1.4.1 吞吐量1.4.2 暂停时间1.4.3 高吞吐量 VS 暂停时间2 垃圾回…

非常实用的Visual Studio Code快捷键(2) 欢迎各位大侠补充

折叠或展开代码 代码须易于理解并且要记录在案。可以使用以下快捷键轻松折叠代码中次重要的部分&#xff1a; 按_Ctrl Shift [_ 进行折叠。按_Ctrl Shift ]_ 展开 导航到特定行 如果要转到包含数千行的文件中的所需行。只需执行以下操作&#xff1a; 按_Ctrl G_&#x…

wireshark测试tcp三次握手与四次挥手

wireshark 选择Loopback来监听本地网络。 监听的内容是分三大模块的&#xff1a; 封包列表的面板中显示&#xff0c;编号&#xff0c;时间戳&#xff0c;源地址&#xff0c;目标地址&#xff0c;协议&#xff0c;长度&#xff0c;以及封包信息。 你可以看到不同的协议用了…

网课搜题接口-掘光者题库系统

网课搜题接口-掘光者题库系统 本平台优点&#xff1a; 多题库查题、独立后台、响应速度快、全网平台可查、功能最全&#xff01; 1.想要给自己的公众号获得查题接口&#xff0c;只需要两步&#xff01; 2.题库&#xff1a; 题库&#xff1a;题库后台&#xff08;点击跳转&am…

Hive与SparkSQL语法差异

一、相同函数差异 1、Spark运行时用到的hash函数&#xff0c;与Hive的哈希算法不同&#xff0c;如果使用hash()&#xff0c;结果和Hive的hash()会有差异 2、Hive和SparkSQL使用grouping sets生成的GROUPING_ID不一致 3、regexp_extract未匹配上的话&#xff0c;在HIVE里返回…

Hive事务表 (Transactional Tables)

文章目录1. 为什么要使用事务表&#xff1f;2. 创建使用事务表1. 为什么要使用事务表&#xff1f; Hive 原本是不支持事务的&#xff0c;也就是不支持 增删改(insert、delete、update)、回滚等 操作的。因为&#xff1a; Hive的核心目标是&#xff1a;将已经存在的结构化数据文…

大学生影视主题网页制作 HTML+CSS+JS仿360影视网站 dreamweaver电影HTML网站制作

HTML实例网页代码, 本实例适合于初学HTML的同学。该实例里面有设置了css的样式设置&#xff0c;有div的样式格局&#xff0c;这个实例比较全面&#xff0c;有助于同学的学习,本文将介绍如何通过从头开始设计个人网站并将其转换为代码的过程来实践设计。 文章目录一、网页介绍一…