资讯动态

The Book of Shaders 实战:GLSL 片段着色器的第一个 Hello World 逐行解析

发布时间:2026/10/15 3:46:41 来源:尧图企业网站定制
【免费下载链接】thebookofshadersStep-by-step guide through the abstract and complex universe of Fragment Shaders.项目地址https://gitcode.com/gh_mirrors/th/thebookofshaders点击查看免费下载本文基于 The Book of Shaders 仓库的第二章内容02/README-tr.md 及其英文原版 02/README.md完整讲解片段着色器Fragment Shader的入门示例——用 GLSL 语言让画布上每一个像素呈现同一种颜色。读完本文你将掌握片段着色器程序的最小骨架main函数、输出变量gl_FragColor、vec4向量类型、预处理器宏与浮点精度声明并能识别最常见的白屏编译错误根因。在传统的编程学习中Hello world 是接触一门新语言的第一步一行简单的代码输出一句热情的问候。但在 GPU 的世界里第一步就渲染一行文字是过度复杂的任务——文本渲染需要字形、纹理与采样等一整套管线。因此本书的入门方式改为为画布上每一个像素选择一种明亮的欢迎色让整块画布喊出我们的热情。这也是理解片段着色器本质的最佳起点着色器是一段对屏幕上的每一个像素同时执行的程序它接收像素的位置返回该像素的颜色。先看完整代码hello_world.frag本仓库第二章的示例着色器位于 02/hello_world.frag全文只有 9 行#ifdef GL_ES precision mediump float; #endif uniform float u_time; void main() { gl_FragColor vec4(1.0,0.0,1.0,1.0); }当你在浏览器中阅读本书时页面上的代码块是可交互的可以点击并修改任意一行代码改动会立刻反映到旁边的实时预览画布上。这是因为本书站点src/main.js在页面加载时会把所有带data属性的.codeAndCanvas元素交给 GlslEditor 处理着色器代码借助 GPU 架构被on the fly即时重新编译并替换无需刷新页面。因此你可以大胆地把第 8 行的四个数值改成任意值观察颜色变化。别看这段代码只有寥寥数行从中可以推导出片段着色器最核心的七条知识点。1. 单一入口main 函数GLSLOpenGL Shading Language与 C 语言一样要求程序包含一个名为main的入口函数。片段着色器没有返回值传递机制而是通过预设的全局输出变量把颜色交给管线void main() { gl_FragColor vec4(1.0,0.0,1.0,1.0); }void main()是片元fragment着色阶段的唯一入口GPU 会为画布上的每一个像素/片元并行调用它最终像素颜色被赋给保留字全局变量gl_FragColor即 GLSL 内置的输出变量参见仓库术语表 glossary/gl_FragColor/README.md与上一章 01/README.md 中描述的并行架构一致每个线程彼此盲且无记忆只负责计算自己负责的那个片元的颜色。2. 第一次认识 vec4四分量浮点向量vec4是 GLSL 的内建类型表示四维浮点向量。从代码vec4(1.0,0.0,1.0,1.0)的四个参数可以推断它们分别对应参数位置通道含义第 1 个RRed红色分量第 2 个GGreen绿色分量第 3 个BBlue蓝色分量第 4 个AAlpha透明度分量同时可以注意到这些值都是**归一化normalized**的——取值范围限定在0.0到1.0之间。归一化之所以重要是因为它让不同变量、不同维度之间的数值可以方便地互相map映射例如把一个坐标值直接映射到颜色通道或把时间值映射到透明度。这也是后续章节反复使用的核心技巧。除vec4外GLSL 还提供vec3三分量浮点向量和vec2二分量浮点向量以及最常用的标量类型float、int、bool。仓库的术语表对每种类型的构造方式有完整说明例如 glossary/vec4/README.md、glossary/vec3/README.md、glossary/vec2/README.md 与 glossary/float/README.md。3. 预处理器宏GL_ES 与条件编译GLSL 继承了大量 C 语言的预处理特性。所有宏命令以#开头在正式编译之前的预编译阶段被处理#define定义宏/全局常量#ifdef若某宏已定义则编译其后代码#ifndef若某宏未定义则编译其后代码#endif结束条件块。回到我们的示例#ifdef GL_ES precision mediump float; #endif这里仅当宏GL_ES被定义时才插入第 2 行的精度声明。GL_ES通常在移动设备与浏览器WebGL / OpenGL ES 环境中编译着色器时自动定义而在桌面 OpenGL 环境中则不一定存在。因此这段包裹让同一个着色器既能跑在 WebGL 上也能兼容桌面环境。这是编写跨平台着色器的惯用写法在仓库几乎所有示例如 05/step.frag、07/circle.frag 等的头部都能看到同一模式。4. 浮点精度声明precision mediump float浮点类型在着色器中至关重要而**精度precision**直接决定了渲染速度与质量之间的取舍声明精度适用场景precision lowp float;低精度渲染最快但数值误差大、画质损失明显precision mediump float;中精度速度与质量的平衡点本书示例的默认选择precision highp float;高精度质量最高但渲染开销更大示例中的precision mediump float;把后续所有浮点变量统一设置为中精度你也可以按需为每个变量单独指定精度。精度不仅影响颜色渐变的平滑度还会影响数值运算的稳定性——例如在后面的噪声、分形章节中低精度会直接导致图案出现可见的条带或块状瑕疵。仓库术语表 glossary/precision/README.md 与 glossary/mediump/README.md 对相关声明做了归档。5. 最关键的陷阱GLSL 不保证自动类型转换GLSL 规范不保证变量会被自动强制转换implicit cast。原因在于显卡制造商为了加速图形处理会采取各自不同的实现策略他们只需要保证满足规范的最低要求而自动类型转换并不在最低要求之列。vec4是浮点精度的向量因此它的四个参数必须是float。请看这段不总是能运行的错误代码void main() { gl_FragColor vec4(1,0,0,1); // 错误整数传给浮点向量可能编译失败 }1、0是整数int而vec4期望浮点float。在有些显卡驱动上这段代码也许能侥幸通过但在另一些驱动上会直接编译失败——呈现一片白屏。规范要求我们养成在浮点数值后加上小数点.的习惯例如1.0、0.0。对于从 C/Java 等语言转来的读者这与(float) 1的显式 cast 语法不同GLSL 的cast就是在字面量上写出小数点。6. 动手实验把知识变成手感理解了上述要素之后就是点击代码块、亲手验证所学的时候了。请记住一旦代码编译失败程序不会运行画布会显示白屏。以下四组练习按难度递进练习一用整数替换浮点void main() { gl_FragColor vec4(1,0,0,1); }把第 8 行的1.0、0.0换成1、0观察你的显卡/浏览器驱动是否容忍这种行为——在不同设备上结果可能截然不同。练习二注释掉颜色赋值void main() { // gl_FragColor vec4(1.0,0.0,1.0,1.0); }把第 8 行注释掉不给main()赋任何像素值。程序同样无法通过编译屏幕将保持白色。练习三自定义函数返回颜色把返回特定颜色的逻辑封装成独立函数并在main()中调用vec4 red(){ return vec4(1.0,0.0,0.0,1.0); } void main() { gl_FragColor red(); }练习四探索 vec4 的多种构造方式vec4并不只有四个标量参数这一种构造写法。可以混合使用向量与标量甚至用一个标量填充所有分量。例如vec4 color vec4(vec3(1.0,0.0,1.0),1.0);此外仓库术语表 glossary/vec4/README.md 还收录了这些合法构造方式vec4 aVec4 vec4(1.0, 1.0, 1.0, 1.0); // 四个标量 vec4 bVec4 vec4(1.0); // 单个标量填充所有分量 vec4 cVec4 vec4(aVec2, aFloat, aVec3);// 向量与标量混合构造函数的参数分量总数必须不小于目标向量的分量数这是 GLSL 的硬性约束。7. 这只是起点下一步是空间与时间尽管整块画布同一颜色看起来并不刺激它却是最基础的示例——我们改变了画布内每一个像素的颜色尽管是相同的颜色。这也意味着着色器代码必须能根据像素在屏幕上的位置产生不同行为这正是片段着色器与普通 CPU 程序最本质的差异。下一章 03/README.md 将介绍两种驱动像素变化的输入源它们也对应着本书后续绝大部分示例的骨架空间space像素在屏幕上的位置坐标gl_FragCoord时间time页面加载后经过的秒数u_time。届时你会看到u_time、u_resolution、u_mouse这类uniform输入如何与sin()、cos()等硬件加速的数学函数组合让画布从一个静止的颜色变成流动的图案。而本示例 02/hello_world.frag 头部声明的uniform float u_time;正是为那个方向埋下的伏笔——虽然本章尚未使用它但它已经出现在每一个示例的模板中。赞分享【免费下载链接】thebookofshadersStep-by-step guide through the abstract and complex universe of Fragment Shaders.项目地址https://gitcode.com/gh_mirrors/th/thebookofshaders点击查看免费下载相关推荐The Book of Shaders 第 2 章详解用 Hello World 片段着色器入门 GLSLThe Book of Shaders 第 2 章详解用 Hello World 片段着色器入门 GLSL 本篇基于 The Book of ShaderThe Book of Shaders 入门实战从 GLSL Hello World 读懂片段着色器的 7 个核心要点The Book of Shaders 入门实战从 GLSL Hello World 读懂片段着色器的 7 个核心要点 导读 本文以开源教程《The BookThe Book of Shaders 第 2 章解析用 Hello World 掌握 GLSL 片元着色器的基础语法The Book of Shaders 第 2 章解析用 Hello World 掌握 GLSL 片元着色器的基础语法 本文基于 The Book of Sh上一篇agentic-awesome-skills 技能锻造指南用 Andru.ia Skill-Smith 按钻石标准设计、编写与部署新技能下一篇ccusage 仓库的 GitHub PR 评审自动化实战用 gh api 处理行内评论线程与解析状态创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑