这个周末创造一些美丽的东西!写下您的第一个着色器并将其放在网络上使用WebGL
#html #webgl #glsl

我一直想创建一个“着色器” - 一个非常快速起作用的图形程序(它在您的GPU上运行) - 但是我一直被推迟,因为它们似乎真的很困难。

着色器有两种形式:碎片着色器和顶点着色器。碎片着色器是我们在这里关心的,因为它们对于绘画更有用。片段着色器是一种处理屏幕上各个碎片(像素)的着色器。它负责确定最终渲染图像中每个像素的颜色。 GLSL是一种类似C的语言,用于在OpenGL中编写着色器。

所有这些复杂性使我很长一段时间。今天,我设法将这种恐惧放在一边并创造这个 - 有趣的动态梯度背景:

自己运行着色器..

..在Shadertoy中

Shadertoy是一个用于运行着色器的交互式网络操场。

void mainImage(out vec4 fragColor, in vec2 fragCoord)
{
    // Normalized pixel coordinates (from 0 to 1)
    vec2 uv = fragCoord / iResolution.xy;

    // Time-based variables for smooth animation
    float t = iTime * 1.5;
    float t1 = sin(t) * 0.5 + 0.5;
    float t2 = cos(t) * 0.5 + 0.5;

    // Color components
    float r = sin(3.0 * uv.x + t1) * 0.5 + 0.5;
    float g = cos(3.0 * uv.y + t2) * 0.5 + 0.5;
    float b = sin(4.0 * (uv.x + uv.y) + t1 + t2) * 0.5 + 0.5;

    // Output the final color
    fragColor = vec4(r, g, b, 1.0);
}

要使用此着色器,请执行以下步骤:

  1. Go to https://www.shadertoy.com/new.
  2. 用上面提供的代码替换“ mainImage”函数中的现有代码。
  3. 单击“播放”按钮。

..在本地

如果您想学习如何在自己的项目中使用着色器,则需要做更多的工作来设置。

该项目有两个文件:

  • glsl.html-主要网页
  • shader.frag- a 碎片着色器

glsl.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>GLSL/WebGL Shader Example</title>
    <meta name="author" content="Tim McNamara">
    <meta property=”og:url content=”https://github.com/timClicks/glsl-shader-intro” />
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <script type="text/javascript" src="https://rawgit.com/patriciogonzalezvivo/glslCanvas/master/dist/GlslCanvas.js"></script>
    <style>
        html, body {
          width:  100%;
          height: 100%;
          margin: 0;
        }
        canvas {
            display: block;
            width: 100%;
            height: 100%;
        }
    </style>
</head>
<body>
    <canvas class="glslCanvas" data-fragment-url="shader.frag"></canvas>
    <script>
        const canvas = document.querySelector('.glslCanvas');
        canvas.width = window.innerWidth;
        canvas.height = window.innerHeight;
        const sandbox = new GlslCanvas(canvas);
    </script>
</body>
</html>

shader.frag

#ifdef GL_ES
precision mediump float;
#endif

uniform float u_time;
uniform vec2 u_resolution;

void mainImage(out vec4 fragColor, in vec2 fragCoord)
{
    // Normalized pixel coordinates (from 0 to 1)
    vec2 uv = fragCoord / u_resolution.xy;

    // Time-based variables for smooth animation
    float t = u_time * 1.5;
    float t1 = sin(t) * 0.5 + 0.5;
    float t2 = cos(t) * 0.5 + 0.5;

    // Color components
    float r = sin(2.0 * uv.x + t1) * 0.5 + 0.5;
    float g = cos(3.0 * uv.y + t2) * 0.5 + 0.5;
    float b = sin(4.0 * (uv.x + uv.y) + t1 + t2) * 0.5 + 0.5;

    // Output the final color
    fragColor = vec4(r, g, b, 1.0);
}

void main() {
    mainImage(gl_FragColor, gl_FragCoord.xy);
}

注意:WebGL中的变量与Shadertoy中可用的变量不同。 Shadertoy的iResolution变为u_resolution,其iTime变为u_time

解释代码

shader.frag中的GLSL代码相对较短,但仍然令人反感。让我们分解。

预处理器

开始,我们有一个“预处理器指令”。编译器具有阶段,初始阶段之一称为“预处理器”。

  #ifdef GL_ES
  precision mediump float;
  #endif

此部分检查着着色器是否在OpenGL ES(嵌入式系统)上运行,这是移动设备和嵌入式设备的OpenGL子集。如果是这样,它将默认的浮点精度设置为“媒介”。精度指示浮点变量的准确性和范围。 “中等”的精度在性能和准确性之间提供平衡。

创建两个“统一”(全局)变量

uniform float u_time;
uniform vec2 u_resolution;

统一变量是可以从着色器外部(通常是从应用程序代码)设置的全局变量。在这种情况下,u_time表示经过的时间,而u_resolution表示屏幕分辨率为2D向量(宽度,高度)。

mainimage函数

void mainImage(out vec4 fragColor, in vec2 fragCoord)

mainImage函数基于片段坐标(fragCoord)处理片段颜色(fragColor)。它采用类型vec4的“输出变量” fragColor,而不是使用返回值来设置片段的颜色(像素)和一个vec2的输入变量fragCoord,该vec2描述了片段的坐标。

标准化像素坐标

vec2 uv = fragCoord / u_resolution.xy;

这条线将片段的坐标转换在绝对位置和0%至100%之间的相对位置之间。我之所以使用术语标准化,是因为坐标uv独立于渲染着色器的设备,而fragCoord是设备特定的。该代码通过将片段坐标除以分辨率来计算uv。紫外线坐标的范围从(0,0)到(1,1),分别代表屏幕的左下角和右上角。

更改随时间推移显示的内容

float t = u_time * 1.5;
float t1 = sin(t) * 0.5 + 0.5;
float t2 = cos(t) * 0.5 + 0.5;

这些行创建了基于时间的变量,用于平滑动画。 t变量缩放经过的时间(u_time),而t1t2使用正弦和余弦函数来创建平稳变化的值,在0和1之间振荡。

>

更改将常数乘以u_time会改变图像变化的速度。调整t1t2的行为如何影响产生颜色的周期。

计算颜色成分(红色,绿色,蓝色)

float r = sin(2.0 * uv.x + t1) * 0.5 + 0.5;
float g = cos(3.0 * uv.y + t2) * 0.5 + 0.5;
float b = sin(4.0 * (uv.x + uv.y) + t1 + t2) * 0.5 + 0.5;

这些线使用基于时间的变量和归一化的像素坐标来计算每个片段的红色,绿色和蓝色成分。正弦和余弦函数会产生平稳的变化值,在屏幕上创建颜色梯度。

设置像素的颜色

fragColor = vec4(r, g, b, 1.0);

此行将输出fragColor设置为具有计算的颜色组件(rgb)和Alpha(透明度)值为1.0(完全不透明)。

主要功能

void main() {
    mainImage(gl_FragColor, gl_FragCoord.xy);
}

main函数是着色器的入口点。它的唯一工作是调用我们刚刚聊天的mainImage函数。我包括了mainImage,以简化您自己的HTML和Shadertoy的托管环境之间的重构和翻译。

扩展着色器

您可以通过调整参数(例如正弦(sin)中的系数(sin)和Cosine(cos)函数来进一步实验此着色器,从而产生颜色组件,从而产生不同的效果。

致谢

此示例利用了patriciogonzalezvivo/glslCanvas项目,这使得在HTML标签中使用GLSL着色器非常容易。

GitHub logo patriciogonzalezvivo / glslCanvas

使用WebGL在HTML画布上加载GLSL着色器的简单工具

GlslCanvas是JavaScript库,可帮助您轻松地将GLSL片段和Vertex着色器加载到HTML帆布中。我已经在我的Book of ShadersglslEditor中使用过。

Donate

如何使用它?

有不同的方法可以做到这一点。但首先,请确保您通过将此行添加到HTML:

来在页面上加载最新版本的GlslCanvas.js
  <  script   type type  =“  text/javascript  src  =”  https:// .com/patriciogonzalezvivo/glslcanvas/master/dist/dist/glslcanvas.js >      脚本 >  

,或者如果您在控制台上使用NPM软件包管理器:

 npm安装glslcanvas 

简单的方式

  1. 在您的html中创建一个帆布元素。
  2. 将类名称glslCanvas添加到画布中。
  3. 分配着着色器
    • 通过使用属性data-fragment-url通过URL
    • 或直接在data-fragment属性中编写代码
  <  canvas   class  =“  glslcanvas  data-fragment-url  =“  shader.frag在/span> =“  500 >