首页
学习
活动
专区
工具
TVP
发布
精选内容/技术社群/优惠产品,尽在小程序
立即前往

从js到gl,开启潘多拉的魔盒

如果你进到这里,相信你一定是不满足基于JavaScript的前端页面。其实,无论是视觉效果还是渲染效率,GLSL都会给你带来不一样的惊喜,仿佛打开一个潘多拉的魔盒!虽然,操纵着色器语言GLSL比起高级语言JavaScript将更有难度,但是与底层汇编语言相比,GLSL仍是人类可读的。这里,研习君着重针对与JavaScript的不同,对GLSL语言做一些介绍。

JavaScript和GLSL都是在浏览器中运行的编程语言,都是用来在屏幕上绘制一些有趣的东西的。相比较于广为人知的JavaScript,或许大部分人对GLSL仍比较陌生。GLSL为OpenGL着色语言(OpenGL Shading Language),它和JavaScript之间有些什么不同呢?

解释语言 vs 编译语言

首先,二者之间最根本的差别就是JavaScript为解释语言,而GLSL为编译语言。编译后的程序是在操作系统上本机执行的,它是低级的,而且通常速度很快。一个解释程序需要一个虚拟机(VM)来执行,它的级别很高,而且通常很慢。

当浏览器(JavaScript虚拟机)执行或解释一段JavaScript脚本时,它不知道哪个变量是什么,哪个函数做什么。因此,它不能预先优化任何东西,因此需要一些时间来读取代码,从被使用的情况来推断变量和方法的类型(更多内容可搜索Chrome的V8引擎是如何工作的)。最糟糕的是,每一个浏览器都会以自己的方式优化JS,而这个过程对外界是隐藏的;即使身为程序员的你,也无能为力。

与之不同的是,编译后的程序不会被解释;操作系统运行它,如果程序有效,则执行该程序。这是一个很大的变化;如果你忘记了一个分号在行尾,你的代码是无效的,它将无法编译,因为你的代码根本不会变成一个程序。听上去很残酷,但GLSL就是这样:在GPU上执行的编译程序。不要害怕!作为一名程序员,编译器,作为一个验证和确保你的代码合法有效的程序,会成为你最好的朋友。

弱类型 vs 强类型

在JavaScript中变量和方法都是不用指定类型的,我们可以动态地添加、删除类成员,刷新页面,看看它是否有效,再更改、刷新,重复下去,生活如此美好。所以,从JavaScript迈向GLSL,初始化变量将是最困难的一步。必须显式地指定所使用的每个变量的类型,这样编译器一看到它们,就知道如何有效进行处理。所幸GLSL中的变量类型还是很有限的,如bool(布尔值)、int(整数)、float(浮点数)等,因此也是很容易理解和掌握的。

下面的片段展示了在JavaScript和GLSL中声明变量的不同:

//a Boolean value:

JS: var b = true;

GLSL:boolb = true;

//an Integer value

JS: var i = 1;     

GLSL:inti = 1;

//a Float value (a Number)

JS: var f = 3.14159;

GLSL:floatf = 3.14159;

不是那么难吧?如果你仍有质疑,请相信这样做是为了让我们的程序比JavaScript快得多。

重载(Overloads)

JavaScript中不允许重载,但在GLSL中,重载几乎无处不在。例如,运算符的重载:

vec2a =vec2( 1.0, 1.0 );

vec2b =vec2( 1.0, 1.0 );

//overloaded addition

vec2c = a + b;   // c = vec2( 2.0, 2.0 );

纳尼?不是数值也可以直接相加?是的,而且这也适用于其他的运算符(+, -, * & /) 。看下面的代码:

vec2a =vec2( 0.0, 0.0 );

vec2b =vec2( 1.0, 1.0 );

//overloaded constructor

vec4c =vec4( a , b );       // c = vec4( 0.0, 0.0, 1.0, 1.0 );

我们用两个二维向量构造了一个四维向量,这就是函数的重载。其实,这个vec4构造函数还允许很多不同版本的实现,例如以下所有的声明语句都是合法的,我们唯一需要的就是确保提供足够的参数给向量:

vec4a =vec4(1.0, 1.0, 1.0, 1.0);

vec4a =vec4(1.0);// x, y, z, w all equal 1.0

vec4a =vec4( v2,float, v4 );// vec4( v2.x, v2.y, float, v4.x );

vec4a =vec4( v3,float);// vec4( v3.x, v3.y, v3.z, float );

限定符(qualifiers)

限定符也是在JavaScript中没有的概念。GLSL在变量类型之上,提供了限定符,从而让编译器知道哪个变量是什么。例如,有些数据只能由CPU提供给GPU,这些数据称为attributes和uniforms。attributes是为顶点着色器保留的,uniforms在顶点着色器和片段着色器中均可使用。还有一个用于在顶点和片段着色器之间传递变量的varying限定符。例如下面的语句:

uniform vec2u_resolution;

我们在变量类型之前加了一个uniform的限定符,这意味着我们正在处理的画布的分辨率从CPU传递给着色器。当编译器看到前面有这个限定符的变量时,它将确保我们不能在运行时设置这些值。

此外,GLSL中为函数提供了了3个额外的限定符:in、out和inout。在JavaScript中,当我们向函数传递标量参数时,它们的值是只读的,如果我们在函数内部更改它们的值,则这些更改不会应用于函数外部的变量。但在GLSL中可以通过参数限定符来指定参数的行为:

in:将为只读(默认)

out:意味着它是 write only,无法读取此参数的值,但可以设置它

inout:意味着read-write,可以获取并设置此变量的值

这与JS非常不同,功能也非常强大。

空间坐标

最后一点,在基于JavaScript操纵的DOM和Canvas2d中,我们习惯于让Y轴指向“向下”。这在DOM上下文中是有意义的,因为它遵循web页面展开的方式;导航栏位于顶部,内容向底部展开。在WebGL画布中,Y轴则指向上。这意味着原点(0,0)位于WebGL上下文的左下角,而不是像在2D画布中那样位于左上角。

参考文献:

《An introduction for those coming from JS》/Nicolas Barradeau;

《The Book of Shaders》/Patricio Gonzalez Vivo & Jen Lowe;

更多技术分享,欢迎关注研习书社,一个技术研究和分享的角落!

  • 发表于:
  • 原文链接https://kuaibao.qq.com/s/20200824A0SQL700?refer=cp_1026
  • 腾讯「腾讯云开发者社区」是腾讯内容开放平台帐号(企鹅号)传播渠道之一,根据《腾讯内容开放平台服务协议》转载发布内容。
  • 如有侵权,请联系 cloudcommunity@tencent.com 删除。

扫码

添加站长 进交流群

领取专属 10元无门槛券

私享最新 技术干货

扫码加入开发者社群
领券