pocketgl支持在自己的web页面集成类似 Shadertoy、 Threejs 等基于webGL 的渲染图形窗口, 并且拥有shader代码高亮编辑器支持实时修改和预览。 其自带的mesh包含两个Sphere 和 Teaport, 同时支持上床自定义的网格 和 背景天空盒。其既支持像Shadertoy 这种只包含frag 的着色器, 可以用来实现一些后处理效果和 SDF配合RayMatch的材质, 也支持vert的顶点着色器。
环境安装
Pocket.gl 基于nodejs的前端库:
- Three.js, 3D 渲染
- Ace, 代码编辑器
- dat.GUI, GUI 截面绘制
- clipboard.js, 复制粘贴版操作
- RequireJS, Loading条
pocketgl 依赖 nodejs 和 npm 环境, 在确保安装的情况下, 通过npm 安装bower, 如下命令:
npm install -g bower
获取 pocketgl 可以通过 bower 来安装:
bower install pocket.gl --save
也可以直接通过 此链接下载 zip包。
进入到项目目录下, 执行下面命令, 安装所有依赖的包
bower install
如果安装成功, 在当前目录会出现一个 bower_components 的目录, 这里有所有依赖的插件包。
编译
编译过程依赖于 require.js 优化器去组织各个模块。 编译生成的js存放在dist目录。
These batch scripts can be used to build the library:
- build/build.bat – 生成 dist/pocket.gl.js
- build/build-min.bat – 生成 the dist/pocket.gl.min.js
- build/build-all.bat – 上面二者同时生成
其实 .bat 里面的内容也是调用 node相关的接口, 对于非windows平台, 可以直接把 .bat 后缀修改.sh 在mac 或者linux平台去运行。
加载
在你的页面加载 pocketgl, 可以直接在你的代码里加如下:
// 使用本地编译生成的
<script src="dist/pocket.gl.min.js/>// 使用上传 RawGit的
<script src="https://cdn.rawgit.com/gportelli/pocket.gl/v1.2.4/dist/pocket.gl.min.js"/>
然后在js里实例化一个 PocketGL
new PocketGL("myContainer");
构造
PocketGL 一共三个参数, 其中最后两个是可选项。
PocketGL(container, [config], [baseURL]);
- container – (string) 绑定div的id属性名, 通过css可以定义窗口的大小
- config – (object or string, 可选项) 可以绑定一个js,参数是js的路径。 一般是类似官方例子里 param.js , 可以定义外部传入shader的uniform值, 同时用来在右上角画gui。
- baseURL – (string, 可选项) 指定第二步config 的基础路径。
使用如下:
// examples 是几个官方例子,通过index进行切换
new PocketGL(widgetContainer,"data/" + examples[index] + "/params.js", "data/" + examples[index]);
配置
由于 PocketGL 可以通过第二个参数绑定js支持自定义的效果, 这里详细讲下js里相关的字段。
Shaders
- vertexShader – (string) vertex shader 代码.
- fragmentShader – (string) fragment shader 代码.
- vertexShaderFile – (string) 通过一个路径URL绑定一个vert shader的 .glsl文件
- fragmentShaderFile – (string) 通过一个路径URL绑定一个frag shader的 .glsl文件
pocketgl内置的uniform变量, 不需要声明, 可以在shader里直接引用。
// vertex shader prefix
// = object.matrixWorld
uniform mat4 modelMatrix;// = camera.matrixWorldInverse * object.matrixWorld
uniform mat4 modelViewMatrix;// = camera.projectionMatrix
uniform mat4 projectionMatrix;// = camera.matrixWorldInverse
uniform mat4 viewMatrix;// = inverse transpose of modelViewMatrix
uniform mat3 normalMatrix;// = camera position in world space
uniform vec3 cameraPosition;attribute vec3 position;
attribute vec3 normal;
attribute vec2 uv;
attribute vec2 uv2;// fragment shader prefix
uniform mat4 viewMatrix;
uniform vec3 cameraPosition;
如下面vert代码中,直接使用相关的代码进行 位置的坐标系变换:
gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );
// or
gl_Position = projectionMatrix * viewMatrix * modelMatrix * vec4( position, 1.0 );
关于鼠标跟踪
你可以在shader 里使用mouse这个uniform vec4变量, 其中xy分量代表鼠标在当前屏幕里的像素位置,zw分量代表鼠标的相对运动位移。使用如下面代码:
uniform vec4 mouse;
uniform float time;void main() {vec2 p = -1.0 + 2.0 * gl_FragCoord.xy / resolution.xy;p.y *= resolution.y / resolution.x;// Rotationvec2 rot = -vec2(mouse.z, mouse.w) / resolution * vec2(2.0*PI, PI);...
}
添加GUI
右上角的GUI界面会根据下面格式来绑定uniform变量, 这些变量可以同步到shader。
uniforms: [{ type: typename, value: defaultValue, min: minValue, max: maxValue, name: variableName,GUIName: name}
]
- type - string类型, 支持 “float”, “integer”, “boolean” 和 “color”,
其中boolean强转float的时候会变成0或者1, 颜色color对应shader里的vec3类型 - value 设置默认值, 其中颜色可以这样填: [#RRGGBB or #RGB]
- min - float 类型, 最小值
- max - float 类型, 最大值
- name - string类型, 绑定shader里的uniform名
- GUIName - string类型, UI界面上显示的名称
例子:
uniforms: [{ type: "boolean", value: false, name: "flatShading",GUIName: "Flat shading" },{ type: "color", value: "#26a00c", name: "diffuseColor",GUIName: "Color"},{ type: "float", value: 0.5, min: 0, max: 1,name: "specularGloss", GUIName: "Glossiness"},{ type: "integer", value: 5, min: 0, max: 10, name: "specularIntensity",GUIName: "Specular intensity"}
]
绑定在shader对应的unifrom变量名:
uniform float flatShading;
uniform vec3 diffuseColor;
uniform float specularGloss;
uniform float specularIntensity;
Group名
Pocketgl还支持分组, 如下配置:
uniforms: [[{ groupName: "Group 1" },{ type: "float", value: 0.5, min: 0, max: 1, name: "v1", GUIName: "Var 1" },{ type: "boolean", value: true, name: "v2", GUIName: "Var 2" }],[{ groupName: "Group 2" },{ type: "float", value: 0.5, min: 0, max: 1, name: "v3", GUIName: "Var 3" },{ type: "boolean", value: true, name: "v4", name: "Var 4" }],[{ groupName: "Group 2", opened: true },{ type: "float", value: 0.5, min: 0, max: 1, name: "v5", GUIName: "Var 5" },{ type: "boolean", value: true, name: "v6", GUIName: "Var 6" }]
]
对应到GUI显示如下:
Mesh网格
支持 OBJ 和 Collada 两种格式, 同时你可以下面配置指定mesh相关的属性:
meshes: [{ // Procedural meshtype: typename, subdivision: numberOfSubdvisions, // External meshurl: meshURL,name: nameInTheGUI,x: xOffset, y:yOffset, z: zOffset,rx: xRotation, ry: yRotation, z: zRotationscale: meshScale,doubleSided: showBackFaces,transparent: useAlphaChannel}
]
- type – (string) 本地内置的网格, 目前支持以下:
“teapot”, “cube”, “sphere”, “torus”, “cylinder”, “plane” - subdivision – (integer, optional) 网格的细分数量。
- url – (string URL) 本地路径 或者名字
- name – (string) GUI显示名称.
- x, y, z – (float, optional) 网格对象的位置
- rx, ry, rz – (float, optional) 网格对象的旋转.
- scale – (float) 缩放.
- doubleSided – (boolean) 是否渲染两面(前和后)
- transparent – (boolean) 是否开启透明
范例:
meshes: [{ url: "light-bulb.obj", name: "Light Bulb (obj)", rx: 90, scale: 0.17},{ type: "teapot", name: "Teapot", doubleSided: true},{ type: "sphere", name: "Sphere"},{ type: "torus", name: "Torus"},{ type: "cylinder", name: "Cylinder"},{ type: "cube", name: "Cube"},{ type: "plane", name: "Plane", doubleSided: true}
]
材质
mesh支持绑定单独的材质, 使用默认的shader, 即不在param.js里填写 shader相关的字段, 如vertexShader, vertexShaderFile等, 材质支持以下类型:
- color – (string, [#RRGGBB or #RGB], optional) 漫反射颜色diffuse.
- specular – (string, [#RRGGBB or #RGB], optional) 高光颜色specular.
- shininess – (number, optional) 高光反射/光泽度
- diffuseMap – (string, optional) 漫反射贴图URL .
- normalMap – (string, optional) 法线贴图URL.
如下面例子:
meshes: [{ url: "dice.obj", name: "Dice", // one material with diffuse and normal mapmaterials: [{ diffuseMap: "diffuse.jpg", normalMap: "normal.png" }]},{url: "light-bulb.obj", name: "Light Bulb", // two materials with two colors assigned to each sub-meshmaterials: [{ color: "#aaa" },{ color: "#c0a84a" }]}
]
贴图
定义贴图的采样方式以及wrap 可以通过如下方式:
textures: [{ url: textureURL, wrap: wrapType,filter: filtertype, name: variableName}
]
- url – (string, mandatory) 贴图URL, 支持 JPEG 和 PNG.
- wrap – (string, optional) 支持两个格式: “repeat” or “clamp”.
- filter – (string, optional) 支持两种格式: “linear” or “nearest”.
- name – (string, mandatory) shader里的 uniform sampler2D 变量.
外观
- width – (integer) 窗口宽.
- height – (integer) 窗口高.
- backgroundColor – (string, [#RRGGBB or #RGB]) 默认背景颜色.
- tabColor – (string,[#RRGGBB or #RGB]) tab页签颜色.
- tabTextColor – (string,[#RRGGBB or #RGB]) tab页签字体颜色.
{width: 800, height: 600, backgroundColor: "#300", tabColor: "#f00", tabTextColor: "#555", GUIClosed: true
}
天空盒
将默认背景色替换为天空盒。
- skybox – 按顺序定义box的六个面的图: right, left, top, bottom, front, back. 或者使用单张全景图.
shader中提供一个名为tCube的uniform变量,表示立方体贴图纹理。
// cubemap skybox shader uniform
uniform samplerCube tCube;
对于全景图, shader 定义为tEquirect
// equirectangular skybox shader uniform
uniform sampler2D tEquirect;
Cubemap 例子:
// cubemap skybox
skybox: ["cubemap/px.jpg", "cubemap/nx.jpg", "cubemap/py.jpg", "cubemap/ny.jpg", "cubemap/pz.jpg", "cubemap/nz.jpg",
]
全景图例子:
// equirectangular skybox
skybox: "textures/panorama.jpg"
Camera
- orbiting – (boolean) 允许使用拖动鼠标去旋转视角.
- autoOrbit – (boolean) 允许相机自动旋转(如果设置为true,动画将强制设置为true).
- autoOrbitSpeed – (number) 自动旋转速度 (一个单位代表6度每秒).
- cameraDistance – (number) 设置摄影机与网格轴的距离
- cameraPitch – (number) 相机 pitch 角.
- cameraYaw – (number) 相机yaw角
- cameraFOV – (number) 设置相机的fov.
- zoom – (boolean) 允许camera随着鼠标齿轮滑动进行缩放.
{orbiting: true, zoom: true, autoOrbit: true, autoOrbitSpeed: 0.5,cameraDistance: 100, cameraPitch: 27, cameraYaw: 0
}
动画
- animated – (boolean) 如果为true,画布将在每帧更新(通常为60fps),并且着色器中将提供时间统一变量。如果为false,则只有在窗口调整大小时才会重新绘制画布,从而减少开销.
- playButtons – (boolean)如果设置为true并且animated为true,则会显示一些播放控制按钮(播放、停止、暂停)
编辑器
- editorTheme – (string) 设置主题. 有 “dark” 和 “bright” 两个选项
- editorWrap – (boolean) 如果设置为true,则在编辑器中启用文本换行
- showTabs – (boolean) 如果设置为false,则选项卡将被删除,编辑器将不可用
{editorTheme: "bright", editorWrap: false, showTabs: true
}