首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >有手就能学会|ShaderToy系列教程-开发环境配置与介绍

有手就能学会|ShaderToy系列教程-开发环境配置与介绍

作者头像
keyle
发布于 2024-11-01 04:18:41
发布于 2024-11-01 04:18:41
41302
代码可运行
举报
文章被收录于专栏:礼拜八不工作礼拜八不工作
运行总次数:2
代码可运行

现在这里开个坑,这个系列带着做一下shadertoy的一些案例,这个系列教程大概只能算基础教学(目录在下方),所以这个系列教程没有任何压力,有手就能学会。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
教程1. 开发环境配置与介绍
教程2. 语法与调试
教程3. 迁移脚本到游戏引擎

如果你是一个游戏开发者那么对Shader应该不会陌生,UE的Shader用的是HLSL,Unity兼容HLSL,与GLSL主推cg(HLSL)。那么shadertoy主要用的是什么语言呢?GLSL 当然要在unity或者ue使用shadertoy的代码怎么去做这个兼容后面的文章我们再聊一下,本篇就不作教学。

本系列的教程主要兴趣导向的,所以有时间的话可以玩玩看。

网站

https://www.shadertoy.com 下方的介绍来自维基百科

Shadertoy is an online community and platform for computer graphics professionals, academics[1] and enthusiasts who share, learn and experiment with rendering techniques and procedural art through GLSL code. There are more than 52 thousand public contributions as of mid-2021 coming from thousands of users. WebGL[2] allows Shadertoy to access the compute power of the GPU to generate procedural art, animation, models, lighting, state based logic and sound.

Shadertoy是一个在线社区和平台,面向计算机图形专业人员、学者[1]和爱好者,他们通过GLSL代码共享、学习和实验渲染技术和程序艺术。截至21年年中,有超过52000个公共捐款来自数千名用户。WebGL[2]允许Shadertoy访问GPU的计算能力,以生成程序艺术、动画、模型、照明、基于状态的逻辑和声音。

VsCode的插件安装

插件名: shadertoy 注意是第一个

安装完毕预览图glsl文件效果

下载与调试

在shadertoy上找到你想要下载的代码,复制并在本地创建一个glsl文件,如果有报错信息就会在右侧预览中显示。

你可以直接复制下面的代码到本地创建一个名为cube.glsl的文件。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
/**
 * Part 3 Challenges
 * - Make the camera move up and down while still pointing at the cube
 * - Make the camera roll (stay looking at the cube, and don't change the eye point)
 * - Make the camera zoom in and out
 */

const int MAX_MARCHING_STEPS = 255;
const float MIN_DIST = 0.0;
const float MAX_DIST = 100.0;
const float EPSILON = 0.0001;

/**
 * Signed distance function for a cube centered at the origin
 * with width = height = length = 2.0
 */
float cubeSDF(vec3 p) {
    // If d.x < 0, then -1 < p.x < 1, and same logic applies to p.y, p.z
    // So if all components of d are negative, then p is inside the unit cube
    vec3 d = abs(p) - vec3(1.0, 1.0, 1.0);
    
    // Assuming p is inside the cube, how far is it from the surface?
    // Result will be negative or zero.
    float insideDistance = min(max(d.x, max(d.y, d.z)), 0.0);
    
    // Assuming p is outside the cube, how far is it from the surface?
    // Result will be positive or zero.
    float outsideDistance = length(max(d, 0.0));
    
    return insideDistance + outsideDistance;
}

/**
 * Signed distance function for a sphere centered at the origin with radius 1.0;
 */
float sphereSDF(vec3 p) {
    return length(p) - 1.0;
}

/**
 * Signed distance function describing the scene.
 * 
 * Absolute value of the return value indicates the distance to the surface.
 * Sign indicates whether the point is inside or outside the surface,
 * negative indicating inside.
 */
float sceneSDF(vec3 samplePoint) {
    return cubeSDF(samplePoint);
}

/**
 * Return the shortest distance from the eyepoint to the scene surface along
 * the marching direction. If no part of the surface is found between start and end,
 * return end.
 * 
 * eye: the eye point, acting as the origin of the ray
 * marchingDirection: the normalized direction to march in
 * start: the starting distance away from the eye
 * end: the max distance away from the ey to march before giving up
 */
float shortestDistanceToSurface(vec3 eye, vec3 marchingDirection, float start, float end) {
    float depth = start;
    for (int i = 0; i < MAX_MARCHING_STEPS; i++) {
        float dist = sceneSDF(eye + depth * marchingDirection);
        if (dist < EPSILON) {
      return depth;
        }
        depth += dist;
        if (depth >= end) {
            return end;
        }
    }
    return end;
}
            

/**
 * Return the normalized direction to march in from the eye point for a single pixel.
 * 
 * fieldOfView: vertical field of view in degrees
 * size: resolution of the output image
 * fragCoord: the x,y coordinate of the pixel in the output image
 */
vec3 rayDirection(float fieldOfView, vec2 size, vec2 fragCoord) {
    vec2 xy = fragCoord - size / 2.0;
    float z = size.y / tan(radians(fieldOfView) / 2.0);
    return normalize(vec3(xy, -z));
}

/**
 * Using the gradient of the SDF, estimate the normal on the surface at point p.
 */
vec3 estimateNormal(vec3 p) {
    return normalize(vec3(
        sceneSDF(vec3(p.x + EPSILON, p.y, p.z)) - sceneSDF(vec3(p.x - EPSILON, p.y, p.z)),
        sceneSDF(vec3(p.x, p.y + EPSILON, p.z)) - sceneSDF(vec3(p.x, p.y - EPSILON, p.z)),
        sceneSDF(vec3(p.x, p.y, p.z  + EPSILON)) - sceneSDF(vec3(p.x, p.y, p.z - EPSILON))
    ));
}

/**
 * Lighting contribution of a single point light source via Phong illumination.
 * 
 * The vec3 returned is the RGB color of the light's contribution.
 *
 * k_a: Ambient color
 * k_d: Diffuse color
 * k_s: Specular color
 * alpha: Shininess coefficient
 * p: position of point being lit
 * eye: the position of the camera
 * lightPos: the position of the light
 * lightIntensity: color/intensity of the light
 *
 * See https://en.wikipedia.org/wiki/Phong_reflection_model#Description
 */
vec3 phongContribForLight(vec3 k_d, vec3 k_s, float alpha, vec3 p, vec3 eye,
                          vec3 lightPos, vec3 lightIntensity) {
    vec3 N = estimateNormal(p);
    vec3 L = normalize(lightPos - p);
    vec3 V = normalize(eye - p);
    vec3 R = normalize(reflect(-L, N));
    
    float dotLN = dot(L, N);
    float dotRV = dot(R, V);
    
    if (dotLN < 0.0) {
        // Light not visible from this point on the surface
        return vec3(0.0, 0.0, 0.0);
    } 
    
    if (dotRV < 0.0) {
        // Light reflection in opposite direction as viewer, apply only diffuse
        // component
        return lightIntensity * (k_d * dotLN);
    }
    return lightIntensity * (k_d * dotLN + k_s * pow(dotRV, alpha));
}

/**
 * Lighting via Phong illumination.
 * 
 * The vec3 returned is the RGB color of that point after lighting is applied.
 * k_a: Ambient color
 * k_d: Diffuse color
 * k_s: Specular color
 * alpha: Shininess coefficient
 * p: position of point being lit
 * eye: the position of the camera
 *
 * See https://en.wikipedia.org/wiki/Phong_reflection_model#Description
 */
vec3 phongIllumination(vec3 k_a, vec3 k_d, vec3 k_s, float alpha, vec3 p, vec3 eye) {
    const vec3 ambientLight = 0.5 * vec3(1.0, 1.0, 1.0);
    vec3 color = ambientLight * k_a;
    
    vec3 light1Pos = vec3(4.0 * sin(iTime),
                          2.0,
                          4.0 * cos(iTime));
    vec3 light1Intensity = vec3(0.4, 0.4, 0.4);
    
    color += phongContribForLight(k_d, k_s, alpha, p, eye,
                                  light1Pos,
                                  light1Intensity);
    
    vec3 light2Pos = vec3(2.0 * sin(0.37 * iTime),
                          2.0 * cos(0.37 * iTime),
                          2.0);
    vec3 light2Intensity = vec3(0.4, 0.4, 0.4);
    
    color += phongContribForLight(k_d, k_s, alpha, p, eye,
                                  light2Pos,
                                  light2Intensity);    
    return color;
}

/**
 * Return a transform matrix that will transform a ray from view space
 * to world coordinates, given the eye point, the camera target, and an up vector.
 *
 * This assumes that the center of the camera is aligned with the negative z axis in
 * view space when calculating the ray marching direction. See rayDirection.
 */
mat4 viewMatrix(vec3 eye, vec3 center, vec3 up) {
    // Based on gluLookAt man page
    vec3 f = normalize(center - eye);
    vec3 s = normalize(cross(f, up));
    vec3 u = cross(s, f);
    return mat4(
        vec4(s, 0.0),
        vec4(u, 0.0),
        vec4(-f, 0.0),
        vec4(0.0, 0.0, 0.0, 1)
    );
}

void mainImage( out vec4 fragColor, in vec2 fragCoord )
{
  vec3 viewDir = rayDirection(45.0, iResolution.xy, fragCoord);
    vec3 eye = vec3(8.0, 5.0, 7.0);
    
    mat4 viewToWorld = viewMatrix(eye, vec3(0.0, 0.0, 0.0), vec3(0.0, 1.0, 0.0));
    
    vec3 worldDir = (viewToWorld * vec4(viewDir, 0.0)).xyz;
    
    float dist = shortestDistanceToSurface(eye, worldDir, MIN_DIST, MAX_DIST);
    
    if (dist > MAX_DIST - EPSILON) {
        // Didn't hit anything
        fragColor = vec4(0.0, 0.0, 0.0, 0.0);
    return;
    }
    
    // The closest point on the surface to the eyepoint along the view ray
    vec3 p = eye + dist * worldDir;
    
    vec3 K_a = vec3(0.2, 0.2, 0.2);
    vec3 K_d = vec3(0.7, 0.2, 0.2);
    vec3 K_s = vec3(1.0, 1.0, 1.0);
    float shininess = 10.0;
    
    vec3 color = phongIllumination(K_a, K_d, K_s, shininess, p, eye);
    
    fragColor = vec4(color, 1.0);
}

创建文件后打开预览发现有报错

很显然上面显示的是一个重复函数名的报错,我们找到上面对应的函数 viewMatrix,将其与相关引用改为 viewMatrix1

现在我们可以看到渲染出一个红色方块,并且随着光照有不同的明暗变化。

本文引用资料

官方教程

https://inspirnathan.com/posts/47-shadertoy-tutorial-part-1

文章开头视频的脚本地址

https://www.shadertoy.com/view/4sdcz8

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2024-04-14,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 礼拜八不工作 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
OpenGL & Metal Shader 编程:ShaderToy 内置全局变量
前面发了一些关于 Shader 编程的文章,有读者反馈太碎片化了,希望这里能整理出来一个系列,方便系统的学习一下 Shader 编程。
字节流动
2023/09/04
1.4K0
OpenGL & Metal Shader 编程:ShaderToy 内置全局变量
不瞒你说,我被这个特效感动哭了
浏览博客时,偶然间发现这个"跳动的心"特效,瞬间被感动了,当得知这个特效是用纯代码实现( GLSL 实现)的,确实又被惊到了。
字节流动
2020/06/02
1K0
OpenGL ES Shader 怎样绘制一颗“心”
今天讲一下绘制心形的两种方式,主要是为了扩展一下绘制复杂形状的思路,为后面讲特效做一些简单的铺垫。
字节流动
2023/09/04
5220
OpenGL ES Shader 怎样绘制一颗“心”
CG实验5 简单光照明模型
(1) 示范代码为立方体在一束平行光照射下的漫反射光照效果。结合示范代码,学习掌握简单光照明模型的基本原理与实现; (2) 修改示范代码,给出不同光照参数和立方体位置,观察与验证光照效果; (3) 示范代码仅有漫反射光的光照效果,请尝试为其添加环境反射光和镜面反射光效果。
步行者08
2018/10/09
1.1K0
【前端er入门Shader系列】02—GLSL语言基础
Shader 一般由顶点着色器和片段着色器成对使用,GLSL 则是编写 Shader 着色器的语言,而 GLSL ES 是在 OpenGL Shader 着色器语言的基础上针对移动端和嵌入式设备的简化版。本章介绍 GLSL 语言相关语法。
CS逍遥剑仙
2025/01/08
1K0
【shadertoy】 heart3d
效果 图片 来源 shadertoy - Heart - 3D 实现 点击展开 // Copyright Inigo Quilez, 2017 - https://iquilezles.org/ // I am the sole copyright owner of this Work. // You cannot host, display, distribute or share this Work in any form, // including physical and digital. Yo
duadua
2022/10/31
2550
【shadertoy】 heart3d
2D Distance Functions
所有基本体都在原点处居中。您必须转换点以获得任意旋转、转换和缩放的对象(请参见下文)。
Ning@
2021/11/10
1.4K0
2D Distance Functions
Shader 编程:只用一个函数就能生成三角形、矩形等所有的正多边形
前面发了一些关于 Shader 编程的文章,有读者反馈太碎片化了,希望这里能整理出来一个系列,方便系统的学习一下 Shader 编程。
字节流动
2023/09/04
9110
Shader 编程:只用一个函数就能生成三角形、矩形等所有的正多边形
别人用 Shader 画了个圆,你却只能画椭圆?
由于主流的 Shader 编程网站,如 ShaderToy, gl-transitions 都是基于 GLSL 开发 Shader ,加上 MSL 和 GLSL 语法上差别不大,后面系列文章将以 GLSL 为主来介绍 Shader 编程。
字节流动
2023/09/04
8910
Shader 入门与实践
Shader(着色器)是一种用于在计算机图形学中进行图形渲染的程序。它们是在图形处理单元(GPU)上执行的小型程序,用于控制图形的各个方面,如颜色、光照、纹理映射、投影等。
KhalilH
2024/05/16
1.2K0
阅后即焚的燃尽图实现
我最开始是在一本书上掠过燃尽效果,当时就是觉得很有意思。但是最近才真正动手去实践它。我知道这个效果要用噪声实现,但是实际做的时候才发现不知道如何应用。于是,去shadertoy上搜索了一番。选取了三个例子,有了一点心得。
winty
2024/01/03
3520
阅后即焚的燃尽图实现
canvas霓虹爱心
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>canvas霓虹爱心</title> <style> body { background-color: #000; margin: 0; overflow: hidden; background-repeat: no-repeat; } </style> </head> <body> <canva
我不是费圆
2021/12/30
6810
canvas霓虹爱心
three.js 实现火花特效
上周末刚在原神里抽到了“火花骑士”可莉,于是就心血来潮,想用three.js来实现一种火系的特效,不是炸弹的爆炸,而是炸弹爆炸后在草上留下的火花效果
落落落洛克
2021/07/29
13.8K0
WebGL简易教程(十四):阴影
所谓阴影,就是物体在光照下向背光处投下影子的现象,使用阴影技术能提升图形渲染的真实感。实现阴影的思路很简单:
charlee44
2019/12/10
1.8K0
WebGL简易教程(十四):阴影
音视频开发之旅(42)-光照基础(一)
环境光(Ambient Lightiing)不来自任何特定方向的光,在经典光照模型中会用一个常量来表示 使用时只需要对其片源着色器添加一个环境光常量,作为gl_Fragcolor的调制即可_
音视频开发之旅
2021/04/19
6150
音视频开发之旅(42)-光照基础(一)
CG-Assignment2
本次作业在第一次作业的基础上,增加一个bezier曲面,并对场景添加光照和纹理效果。具体要求如下:
alanzeng
2025/01/14
1450
CG-Assignment2
用 Shader 写个完美的波浪~
根据我多年喝奶茶的经验,像这种效果用 Shader 做就再简单不过了,最终的效果如下:
陈皮皮
2020/09/10
1.9K0
Unity高级开发(六)-Shader开发-章鱼效果
效果图 章鱼图 Shader "Custom/MyTest" { Properties { _BodyLight("Body Light",Color) = (1, 0.1, 0.5,1) _BodyLightting("Body Lightting",Color) = (1, 0.5, 0.1,1) _Water("Water",Color) = (0.1, 0.5, 1,1) _DepthWater("D
孙寅
2020/07/10
8740
Unity高级开发(六)-Shader开发-章鱼效果
相关推荐
OpenGL & Metal Shader 编程:ShaderToy 内置全局变量
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验