three.js浅谈@glsl与threejs

什么是glsl

众所周知threejs是对webGL的封装,而webGL又是openGL的web版本,而GL则是使用GLSL(OpenGL Shading Language)这种语言来描述。
这里有两张图描述这种关系

来自《WebGL编程指南》

来自《WebGL编程指南》

所以其实threejs也是对glsl的一种封装,但是threejs也保留了对glsl的接口便于我们直接书写glsl来更好的从底层的描述我们的图像

着色器

在GL中绘图我们就必须要使用2种着色器程序
顶点着色器

顶点着色器是用来描述顶点特性(如位置、颜色等)的程序。顶点是指二维或三维空间中的一个点,比如二维或三维图形的端点和交点

顶点是一系列的坐标点,因为一个图形是有大量的三角形构成的,每一个三角形就有3个顶点
顶点着色器的输入是一系列的顶点信息,比如坐标颜色等,然后将这些信息进行处理之后输出给片源着色器

片元着色器

进行逐片元处理过程如光照的程序。片元是一个WebGL术语,你可以将其理解为像素(图像的单元)

在顶点着色器运行完毕之后其实并不是立马执行片元着色器,这个时候回有一部光栅化的过程。什么是光栅化呢?在未光栅化之前,图形是连续的,但是显示器上面的像素是离散的,光栅化就是将连续的图形转化为离散的“像素”,这个一个像素就是一个片元,当然和真正的像素还是有所区别,比如完全重叠的2个图形按像素看就是一份像素,按片元看就要分为“上面的”片元和“下面的”片元

总的来说一个渲染流程入下图所示


https://www.adobe.com/devnet/flashplayer/articles/how-stage3d-works.html

如何在theejs中使用glsl

我们这里假装你已经熟知了glsl的语法,欠缺的只是如何把threejs和glsl凑合到一起(如果不熟悉的可以移步这里)
先来展示一段代码

import * as THREE from 'three'

const scene = new THREE.Scene();//创建一个场景
const camera = new THREE.PerspectiveCamera(50, window.innerWidth/window.innerHeight, 0.1, 1000);
camera.position.z=1//因为刚刚创建的对象都会位于原点,我们需要把相机拉远一点
//创建一个渲染器,并设置大小,然后把这个渲染器加入到dom中
const renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);

const vertices = new Float32Array([
    0.0,  0.0, 0.0,//顶点
]);
//将顶点数组放入缓冲区域
const verticesPosition = new THREE.BufferAttribute( vertices, 3 );
//创建一个空白的模型
const geometry = new THREE.BufferGeometry();
//将顶点数据传入到空白模型中
geometry.addAttribute('position',verticesPosition);
//使用着色器材质
const material=new THREE.ShaderMaterial({
    vertexShader:  `void main( void ) {
                        gl_Position = vec4( position, 1.0 );
                        gl_PointSize = 100.0;
                    }`,
    fragmentShader:`void main() {
                        gl_FragColor = vec4(0,0,0.9,1.0);
                    }`,
});
const points=new THREE.Points(geometry,material);//模型对象
scene.add( points )//场景中加入多面体
renderer.render(scene, camera);

这段代码的效果


效果

我们来解释一下上面这段代码和之前的不一样的部分

const vertices = new Float32Array([
    0.0,  0.0, 0.0,//顶点
]);

这是一个顶点数数组,JavaScript中的普通数组是无类型的,但是有时候js可能也会与其他强类型的语言沟通,所以不得不需要有类型的数组,因此创建了这一系列的api用来代替类型数组,一个顶点由4个数据组成x、y、z、w,这4个数据组成的坐标称为齐次坐标,等价于三维坐标x/w、y/w、z/w,因为w的值一般是1.0所以就可以省略一个位置,这个1.0在着色器中写死。x/y/z/w的取值范围是[-1.0,1.0]

const verticesPosition = new THREE.BufferAttribute( vertices, 3 );
//创建一个空白的模型
const geometry = new THREE.BufferGeometry();
//将顶点数据传入到空白模型中
geometry.addAttribute('position',verticesPosition);

BufferAttribute方法用于将顶点数据转化为Threejs需要的对象,第二个参数表示3个一组
BufferGeometry空白的缓存几何对象,里面不含任何顶点数据
addAttribute向该几何对象添加属性第一个参数是名称,第二个参数是值。
值得一提的是,这里使用了position作为名称传递给几何对象,这个键值对最终会传递到顶点着色器里面,而顶点着色器必须使用attribute vec3 position;这种方式去接受,但是我们这里却并没有在着色器定义这个变量,原因是因为threejs预先帮我们定义好了一系列变量,其中就包括position,因此如果传无关变量,就需要自己定义了。顺带一提使用着色器材质也可以传递参数而且没这么麻烦

//使用着色器材质
const material=new THREE.ShaderMaterial({
    vertexShader:  `void main( void ) {
                        gl_Position = vec4( position, 1.0 );
                        gl_PointSize = 100.0;
                    }`,
    fragmentShader:`void main() {
                        gl_FragColor = vec4(0,0,0.9,1.0);
                    }`,
});

这部分就是我们这次的主角
ShaderMaterial着色器材质有2个配置项一个是vertexShader(顶点着色器),一个是fragmentShader(片元着色器)。
在顶点着色器中我们接到了之前传过来的position并添上"1.0"成为齐次坐标传递给gl_Position ,然后设定点的大小是100.0
在片元着色器中我们将颜色(这里的颜色是rgba,参数是[0.0,1.0])设定为蓝色冰传递给gl_FragColor

const points=new THREE.Points(geometry,material);//模型对象

最后我们有了模型有了材质,2者一结合就形成了我们看到了一个100像素蓝色点的效果

附录

Threejs在顶点着色器中预定义的变量

precision highp float;
precision highp int;
#define HIGH_PRECISION
#define SHADER_NAME ShaderMaterial
#define VERTEX_TEXTURES
#define GAMMA_FACTOR 2
#define MAX_BONES 0
#define BONE_TEXTURE
uniform mat4 modelMatrix;
uniform mat4 modelViewMatrix;
uniform mat4 projectionMatrix;
uniform mat4 viewMatrix;
uniform mat3 normalMatrix;
uniform vec3 cameraPosition;
attribute vec3 position;
attribute vec3 normal;
attribute vec2 uv;
#ifdef USE_TANGENT
    attribute vec4 tangent;
#endif
#ifdef USE_COLOR
    attribute vec3 color;
#endif
#ifdef USE_MORPHTARGETS
    attribute vec3 morphTarget0;
    attribute vec3 morphTarget1;
    attribute vec3 morphTarget2;
    attribute vec3 morphTarget3;
    #ifdef USE_MORPHNORMALS
        attribute vec3 morphNormal0;
        attribute vec3 morphNormal1;
        attribute vec3 morphNormal2;
        attribute vec3 morphNormal3;
    #else
        attribute vec3 morphTarget4;
        attribute vec3 morphTarget5;
        attribute vec3 morphTarget6;
        attribute vec3 morphTarget7;
    #endif
#endif
#ifdef USE_SKINNING
    attribute vec4 skinIndex;
    attribute vec4 skinWeight;
#endif

参考

  1. STAGE3D如何工作:https://www.adobe.com/devnet/flashplayer/articles/how-stage3d-works.html
  2. LearnOpenGL-CN:https://learnopengl-cn.readthedocs.io/zh/latest/
  3. 2: OpenGL ES 2.0 知识串讲:http://geekfaner.com/shineengine/blog1_career.html
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,772评论 6 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,458评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,610评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,640评论 1 276
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,657评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,590评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,962评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,631评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,870评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,611评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,704评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,386评论 4 319
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,969评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,944评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,179评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,742评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,440评论 2 342

推荐阅读更多精彩内容