Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Code repository for the examples from the Packt book "Learning Threejs"
Code repository for the examples from the Packt book "Learning Threejs"
首先什么是环境纹理?在WebGL或者OpenGL中他们实际上是种特殊的立方体纹理。一个立方体纹理是对整个场景(虚拟的或现实的)的观察,场景的样子被"贴"在了立方体的内部表面。想象一下,你站在山顶,向前看,向左看,向右看,向上看,向下看,最后向后看。每一次你都看到了这个"立方体"的内部表面,你就站在这个立方体的中心。如果这个立方体足够大,就很难分辨出立方体的棱和角,而给你一种错觉:你处在一个很大的环境里面。如果你还没弄明白,那么维基百科上的 cube maps 条目会非常有帮助。
这很酷,但是这怎么用?我们可以像做反射和折射一样,而且事实上这两者的函数都已经内建在GLSL,WebGL的着色器语言上了。你只需要传递给着色器6张纹理图片,每张代表立方体的一个内表面,然后告诉WebGL这是个立方体纹理,然后就可以使用上面的效果了。
半轴:这个术语服务于立方体纹理。因为我们通常使用三个轴来描述三维空间:x轴、y轴、z轴,所以用于立方体纹理的图片也用轴的名称来标识了。一共六张图片,每个轴两张图片,正半轴一个,负半轴一个。
全景图片可以是室内外比较空旷的地方,需要专门的应用拍摄,将图片做成了贴到球体上的那种,之后转换到立方体上。在此不赘述。
处理完成会获得与立方体六个面对应到6张图片,就是我们需要到环境纹理图。
现在我们已经获得了环境纹理,然后将其载入到场景中。Three.js使这变得非常简单:
现在只需要将cubemap指定到一个材质中去就可以了!
效果可以查看demo。
本文部分内容参照及引用:
此处所说照相机与现实有所差别, 由于threejs创建的场景是三维的,人眼要看出三维效果就需要有透视点。
在threejs中相机是 THREE.Camera
,有两种类型:
透视投影照相机 THREE.PerspectiveCamera(fov, aspect, near, far)
fov, aspect, near, far 分别代表了摄像机的视角、幕布宽高比、近和远两个视截面。
正交投影照相机 THREE.OrthographicCamera(left, right, top, bottom, near, far)
正交和透视的区别:
(a)透视投影:我们在素描中使用的透视法一致,远小近大(找一个宽阔的大马路看看远处路边的路灯及周边建筑就明白了)。
(b)正交投影:我们在数学几何图形绘画的效果就是,三维空间内平行的线,投影到二维空间也平行,所有物体在正交相机中的尺寸都不会变,且不需要设置长宽比.
本文部分内容参照及引用:
首选,在 Threejs 中 所有光源都是基于 THREE.Light
对象扩展而成的。
基本光源包含:
THREE.AmbientLight
THREE.PointLight
THREE.SpotLight
THREE.DirectinalLight
THREE.AmbientLight
创建时,颜色将会应用到全局,该光源并没有特别的来源方向,而且它不会生成阴影, 所以,不能将 THREE.AmbientLight
作为场景中唯一的光源,因为它会把场景中的物体渲染为相同的颜色,无论什么形状。
在使用其它光源的时候同时使用它,目的是弱化阴影或给场景添加一些额外的颜色。
AmbientLight( color, intensity )
color -- 光源颜色的RGB数值。
intensity -- 光源强度的数值。
使用方法
THREE.PointLight
是一种单发光点、照射所有方向的光源,比如:夜空中的照明弹。该光源不会产生阴影(因为朝所有方向发散光线,在这种情况计算阴影对GPU负担太大)。
点光源照到不同物体表面的亮度是线性递减的,因此,离点光源距离越远的物体会显得越暗。
构造函数
PointLight( color : Integer, intensity : Float, distance : Number, decay : Float )
color -- 颜色的RBG数值。
intensity -- 光强的数值。
distance - 光强为0处到光源的距离,0表示无穷大。
decay - 沿着光照距离的衰退量。
使用方法
THREE.SpotLight
聚光灯光源,是一种锥形效果光源,属于常见光源,在产生阴影的时候比较有用。实例:手电筒。
构造函数
SpotLight( color : Integer, intensity : Float, distance : Float, angle : Radians, penumbra : Float, decay : Float )
color -- 颜色的RBG数值。
intensity -- 光强的数值。
distance -- 光强为0处到光源的距离,0表示无穷大。
angle -- 光线散射角度,最大为Math.PI/2。
penumbra -- 聚光锥的半影衰减百分比。在0和1之间的值。默认为0。
decay -- 沿着光照距离的衰退量。
使用方法
特有属性
target
将聚光灯的焦点位于 target.position
处。
THREE.DirectinalLight
方向光可以看做是距离很远的光源,所发出的光线都是平行的,比如太阳。
方向光和聚光灯光源的区别:
方向光不像聚焦光那样离目标越远越暗淡
被方向光光源照亮整个区域接收到的光强是一样的
构造函数
DirectionalLight( color : Integer, intensity : Float )
color -- 光源颜色的RGB数值。
intensity -- 光源强度的数值。
特殊光源:
THREE.HemisphereLight
THREE.AreaLight
THREE.AreaLight
半球光光源,这种光源可以为室外场景创建更加自然点光照效果。
应用场景
当你在室外的时候,并不是所有光都来自上方,很多空气的散射、地面的反射,以及其它物体的反射,THREE.AreaLight
就是为这种情形创建的。
构造函数
HemisphereLight( skyColor : Integer, groundColor : Integer, intensity : Float )
skyColor -- 从天空发出光的颜色
groundColor -- 从地面发出光的颜色
intensity -- 光线照射的强度。默认值为1。
THREE.AreaLight
平面光光源,可以从很大的平面发射光线,而不是单个点。
如果要使用 THREE.AreaLight
光源,就不能用我们之前一直使用的 THREE.WebGLRenderer
对象,因为平面光光源氏一种非常复杂的光源,会对 THREE.WebGLRenderer
造成非常严重的性能损失, 可以用 THREE.WebGLDeferredRenderer
(WebGL的延迟渲染器)对象在渲染场景时,可以处理复杂光照或者是光源很多的情况。
需要引入额外的代码文件:
THREE.LensFlare
创建镜头光晕。
LensflareElement( texture : Texture, size : Float, distance : Float, color : Color, blending : Materials )
texture -- THREE.Texture (可选)
size -- 像素尺寸 (-1 = 使用 texture.width)
distance -- 介于 (0-1) 的光源距离(0 = 在光源处)
blending -- 混合模式 - 缺省为 THREE.NormalBlending
color -- 镜头光晕的颜色。
常识,发光到物体即光源,有光,就有影。要想体现物体的3D真实性,光影就是很重要的效果。 在threejs的世界里,也为光源提供了很多选择。
Light 是 Threejs 里所有光源的基类
Light( color : Integer, intensity : float )
color -- 光源颜色的RGB数值, 接受一个16进制的颜色值 如: 0xffffff
表示白色
intensity -- 光源强度的数值
基础光源:
AmbientLight 环境光 - 它的颜色会添加到整个场景和所有对象的当前颜色上
DirectionalLight 平行光 -- 例如:太阳光
PointLight 点光源 -- 空间中的一点,朝所有的方向发射光线
SpotLight 聚光源 - 聚光灯是由点光源发出,这种类型的光也可以产生投影,有聚光的效果
特殊光源:
HemisphereLight 半球光 - 可以为室内场景创建更加自然的光照效果,模拟反光面和光线微弱的天气
RectAreaLight 矩形区域光源 - 这种光从一个矩形面均匀地发射,可以用来模拟明亮的窗户或者带状的照明;可以产生投影
环境光故名思意,是光线经过周围环境多次反射而来的光,没有确定的方向。
AmbientLight( color, intensity )
color -- 光源颜色的RGB数值。
intensity -- 光源强度的数值。
从一个特定的方向,而不是从一个特定的位置。这个光看起来就像光源位于无限远处,因此它产生的光线都是平行的。 比如太阳,因为太阳很遥远,看起来所有的阳光照射到物体上都几乎来自同一个角度。
irectionalLight( hex, intensity )
hex -- 光源颜色的RGB数值。
intensity -- 光源强度的数值。
点光源:某个位置特定的发光点,比如灯泡、蜡烛、萤火虫等
PointLight( color, intensity, distance, decay )
color -- 颜色的RBG数值。
intensity -- 光强的数值。
distance -- 光强为0处到光源的距离,0表示无穷大。
decay -- 沿着光照距离的衰退量。
一种能投射锥形阴影区域的点光源,比如探照灯。
SpotLight( color, intensity, distance, angle, penumbra, decay )
color -- 颜色的RBG数值。
intensity -- 光强的数值。
distance -- 光强为0处到光源的距离,0表示无穷大。
angle -- 光线散射角度,最大为Math.PI/2。
penumbra -- 聚光锥的半影衰减百分比。在0和1之间的值。默认为0。
decay -- 沿着光照距离的衰退量。
物体的材质在渲染的时候,和光源有很重要的关系。比如,物体的纹理、色彩、透明度、光滑度、折射率、反光率等。
要想体现材质等真实性,光体现了很主要的效果,如果没有光,都是黑漆漆的,我们眼睛估计无法分辨物体的形态。
走夜路,打手电,通过光我们能分辨路上的石头、树枝、坑洞等。
本文部分内容参照及引用:
搜集並學習threejs的相關知識總結、Demo、 網站、書籍等,歡迎有興趣的小夥伴一起交流學習。
three.js是以webgl為基礎的庫,封裝了一些3D渲染需求中重要的工具方法與渲染循環。WebGL門檻相對較高,Three.js對WebGL提供的介面進行了非常好的封裝,簡化了很多細節,大大降低了學習成本。查看官方實例
個人學習過程中的疑問記錄及demoDemo,小白入門開始教程之Hello Threejs。
分享記錄遇到的坑及解決方案
以下經驗來自快樂小球球
圖片尺寸必須以2的n次方<=1024,如果圖片不是2的整數倍數,引擎會自動壓縮到2的整數倍數,在chrome控制台中會出提示,粗看沒事,但在iphone6Plus下會卡到微信閃退.
用webpack打包模型文件,用各種載入器中的 prase 直接解析即可。模型在 webpack 中以 raw 載入
The Book of Shaders--一本關於 Fragment Shaders(片段著色器)的入門指南
The Book of Shaders Editor- Shaders 在線編輯器
Inigo Quilez - 有關電腦圖形學、著色器的部落格程式碼示例
pixelshaders - 基礎程式碼示例
用如上 Shaders 在線編輯器 可以查看效果 這裡查看效果程式碼
marpi.pl - 很多牛X的Demo
Altered Qualia - 也是很棒的Demo
three-seed - three.js starter project with ES6 and Webpack
The Aviator - the-aviator-animating-basic-3d-scene-threejs
收集整理學習資料。
《threejs-intro》----很棒的入門示例
《WebGL編程指南》
《Three.js開發指南》-- 在線Demo案例
Three.js入門教程 -- 這是對國外一份教程的翻譯,一共六篇文章。講解不多,更多的是展示各個基本功能怎麼用。更適合有一些圖形基礎的同學
p5.js Web Editor - p5在線編輯器
OpenProcessing - 各種 demo
wangyasai-亞賽大人,很多好玩的效果,👍.
Speed-Line - 漫畫必備超燃速度線
Play-a-ball - 抽象球體生成器
Awesome Masoic - 動態馬賽克背景生成器
Perlin Noise - 等高線神器
Stars-Emmision - 萬箭齊發毫髮無傷背景生成器
Particles-Emission - 粒子循環運動神器
研究3D模型,就免不了用到了.obj文件及.mtl文件。 对这两种格式文件内容一头雾水,所有总结归纳一下,以备学习。
obj文件格式是Wavefront公司为它的一套基于工作站的3D建模和动画软件"AdvancedVisualizer"开发的一种文件格式。
OBJ文件是一种标准的3D模型文件格式,很适合用于3D软件模型之间的互导。OBJ文件是一种文本文件格式,这就意味着你可以直接用写字板打开进行查看修改。目前几乎所有知名的3D软件都支持OBJ文件的读写,不过很多软件需要通过插件才能做到这一点。另外,作为一种优秀的文件格式,很多游戏引擎也都支持OBJ文件。
1、OBJ是一种3D模型文件,因此不包含动画、材质特性、贴图路径、动力学、粒子等信息。
2、OBJ文件主要支持多边形(Polygons)模型。 虽然OBJ文件也支持曲线(Curves)、表面(Surfaces)、点组材质(Point Group Materials),但Maya导出的OBJ文件并不包括这些信息。
3、OBJ文件支持三个点以上的面,这一点很有用。 很多其它的模型文件格式只支持三个点的面,所以我们导入Maya的模型经常被三角化了,这对于我们对模型的再加工甚为不利。
4、OBJ文件支持法线和贴图坐标。
OBJ文件不需要任何种文件头(File Header),尽管经常使用几行文件信息的注释作为文件的开头。 OBJ文件由一行行文本组成,注释行以一个“#”号(#)为开头,空格和空行可以随意加到文件中以增加文件的可读性。有字的行都由一两个标记字母也就是关键字 (Keyword)开头,关键字可以说明这一行是什么样的数据。多行可以逻辑地连接在一起表示一行,方法是在每一行最后添加一个连接符()。注意连接符()后面不能出现空格或tab格,否则将导致文件出错。
下列关键字可以在OBJ文件使用【关键字根据数据类型排列,每个关键字有一段简短描述】
顶点数据(Vertex data):
v 几何体顶点 (Geometric vertices)
vt贴图坐标点 (Texture vertices)
vn顶点法线 (Vertex normals)
vp参数空格顶点 (Parameter space vertices)
自由形态曲线(Free-form curve)/表面属性(surface attributes):
deg度 (Degree)
bmat基础矩阵 (Basis matrix)
step步尺寸 (Step size)
cstype曲线或表面类型 (Curve or surface type)
元素(Elements):
p点 (Point)
l线 (Line)
f面 (Face)
curv曲线 (Curve)
curv2 2D曲线 (2D curve)
surf表面 (Surface)
自由形态曲线(Free-form curve)/表面主体陈述(surface body statements):
parm参数值 (Parameter values )
trim外部修剪循环 (Outer trimming loop)
hole内部整修循环 (Inner trimming loop)
scrv特殊曲线 (Special curve)
sp特殊的点 (Special point)
end结束陈述 (End statement)
自由形态表面之间的连接(Connectivity betweenfree-form surfaces):
con连接 (Connect)
成组(Grouping):
g组名称 (Group name)
s光滑组 (Smoothing group)
mg合并组 (Merging group)
o对象名称 (Object name)
显示(Display)/渲染属性(render attributes):
bevel导角插值 (Bevel interpolation)
c_interp颜色插值 (Color interpolation)
d_interp溶解插值 (Dissolve interpolation)
lod细节层次 (Level of detail)
usemtl材质名称 (Material name)
mtllib材质库 (Material library)
shadow_obj投射阴影 (Shadow casting)
trace_obj光线跟踪 (Ray tracing)
ctech曲线近似技术 (Curve approximation technique)
stech表面近似技术 (Surface approximation technique)
三维模型处理会要读取.mtl文件来获得材质信息。
.mtl文件(Material Library File)是材质库文件,描述的是物体的材质信息,ASCII存储,任何文本编辑器可以将其打开和编辑。一个.mtl文件可以包含一个或多个材质定义,对于每个材质都有其颜色,纹理和反射贴图的描述,应用于物体的表面和顶点。
以下是一个材质库文件的基本结构:
注释:每个材质库可含多个材质定义,每个材质都有一个材质名。用newmtl mtlName来定义一个材质。对于每个材质,可定义它的颜色光照纹理反射等描述特征。
主要的定义格式如下文所示:
材质颜色光照
1、环境反射有以下三种描述格式,三者是互斥的,不能同时使用。
Ka r g b
用RGB颜色值来表示,g和b两参数是可选的,如果只指定了r的值,则g和b的值都等于r的值。三个参数一般取值范围为0.0~1.0,在此范围外的值则相应的增加或减少反射率;
Ka spectral file.rfl factor
用一个rfl文件来表示。factor是一个可选参数,表示.rfl文件中值的乘数,默认为1.0;
Ka xyz x y z
用CIEXYZ值来表示,x,y,z是CIEXYZ颜色空间的各分量值。y和z两参数是可选的,如果只指定了x的值,则y和z的值都等于r的值。三个参数一般取值范围为0~1。
2、漫反射描述的三种格式:
Kd r g b
Kd spectral file.rfl factor
Kd xyz x y z
3、镜反射描述的三种格式:
Ks r g b
Ks spectral file.rfl factor
Ks xyz x y z
4、滤光透射率描述的三种格式:
Tf r g b
Tf spectral file.rfl factor
Tf xyz x y z
5、光照模型描述格式:
illum illum_# 指定材质的光照模型。illum后面可接0~10范围内的数字参数。
map_Kd -options args filename 为漫反射指定颜色纹理文件(.mpc)或程序纹理文件(.cxc),或是一个位图文件。作用原理与可选参数与map_Ka同。
map_Ks -options args filename 为镜反射指定颜色纹理文件(.mpc)或程序纹理文件(.cxc),或是一个位图文件。作用原理与可选参数与map_Ka同。
map_Ns -options args filename 为镜面反射指定标量纹理文件(.mps或.cxs)。可选参数如下所示:
blendu on | off
blendv on | off
clamp on | off
imfchan r | g | b | m | l | z
mm base gain
o u v w
s u v w
t u v w
texres value
map_d -options args filename 为消隐指数指定标量纹理文件(.mps或.cxs)。作用原理和可选参数与map_Ns同。
map_aat on 打开纹理反走样功能。
WebGL没有固定的渲染管线,你无法直接使用一个黑盒子式的着色器;WebGL提供的是可编程的管线,这种方式更强大但也更难理解和使用。长话短说,可编程渲染管线意味着编写程序的人要自己负责获取顶点并将它绘制在屏幕上了。着色器是渲染管线的一部分,有两种着色器:
顶点着色器(Vertex Shader)- 它接收 attributes,计算和操作每个顶点的位置,并传递额外的数据(varyings)给片段着色器。
片元着色器(Fragment Shader)- 它设置绘制到屏幕上的每个单独的片段(像素)颜色。
这两种着色器都完全运行在显卡的GPU上。
顶点着色器中的"顶点"指的正是 Mesh
中的顶点,对于每个顶点调用一次。因此,如果场景中有一个正方体,那么对八个顶点将各自调用一次顶点着色器,可以修改顶点的位置或者颜色等信息,然后传入片元着色器。
片元是栅格化之后,在形成像素之前的数据。片元着色器是每个片元会调用一次的程序,因此,片元着色器特别适合用来做图像后处理。
uniforms - 既可以传入顶点着色器,也可以传入片元着色器, 它们包含了哪些在整个渲染过程中保持不变的变量,比如灯光,雾。
attributes - 与每个顶点关联的变量,例如,顶点位置,法线和顶点颜色都是存储在attributes中的数据。attributes只可以在顶点着色器重访问。
varyings - 是从顶点着色器传递到片段着色器的变量。对于每一个片段,每一个varying的值将是相邻顶点值的平滑插值。
着色器是一段在GPU中执行的接近C语言的代码,顶点着色器对于每个顶点调用一次,片元着色器对于每个片元调用一次。、
如上代码:
从 main()
函数开始
gl_Position
全局变量
vec2
二分量浮点向量
vec4
四分量浮点向量,四个变元分别响应红,绿,蓝和透明度通道
float
Number
1
vec2
THREE.Vector2
2
vec3
THREE.Vector3
3
vec3
THREE.Color
3
vec4
THREE.Vector4
4
varing
是 WebGL定义限定符(Qualifier)用于数据类型(Type)之前,表明该变量的性质。
限定符共有四个:
const:这是我们熟悉的常量的意思
attribute:从JavaScript代码传递到顶点着色器中,每个顶点对应不同的值
uniform:每个顶点/片元对应相同的值
varying:从顶点着色器传递到片元着色器中
有了前面顶点着色器传过来的vUv信息,我们能做些有意思的事了吧?比如来看看使用颜色表示uv信息如何?
实际操作中的 uniform 。在上面的代码中我们使用 u_time 加上一个 sin 函数,来展示图中蓝色的动态变化。
GLSL 还有更多惊喜。GPU 的硬件加速支持我们使用角度,三角函数和指数函数。这里有一些这些函数的介绍:sin()
, cos()
, tan()
, asin()
, acos()
, atan()
, pow()
, exp()
, log()
, sqrt()
, abs()
, sign()
, floor()
, ceil()
, fract()
, mod()
, min()
, max()
和 clamp()
。
事实上,我们可以分别测试R、G、B三个通道,分别设置不同的速率等,看看有什么有趣等效果。
这些输入值叫做 uniform (统一值),它们的数据类型通常为:float, vec2, vec3, vec4, mat2, mat3, mat4, sampler2D and samplerCube。uniform 值需要数值类型前后一致。且在 shader 的开头,在设定精度之后,就对其进行定义。
推荐命名方式:按业界传统应在 uniform 值的名字前加 u_ ,这样一看即知是 uniform
这里查看 demo
最后可能也是最重要的细节是,GLSL 语言规范并不保证变量会被自动转换类别。这句话是什么意思呢?显卡的硬件制造商各有不同的显卡加速方式,但是却被要求有最精简的语言规范。因而,自动强制类型转换并没有包括在其中。在我们的"hello world!"例子中,vec4 精确到单精度浮点,所以应被赋予 float 格式,最好养成在 float 型数值里加一个 .0 的好习惯。比如 1
要写成 1.0
, 同样 0
也要写成 0.0
。
本文部分内容参照及引用:
在Three.js中,创建常见几何体比较方便,但是对于复杂模型,比如人、各种动物、植物甚至现实中复杂物体。就比较麻烦,这些复杂建模通常由3D Max等工具制作好三维模型。
*.obj
是最常用的模型格式, 导入带 *.mtl
材质的*.obj
文件需要 MTLLoader.js
以及 OBJMTLLoader.js
。 另有 PLYLoader.js
、STLLoader.js
等分别对应不同格式的加载器,可以根据模型格式自行选择。
目前,支持的模型格式有:
*.obj
-- 需要 OBJLoader.js
;
*.obj
, *.mtl
-- 需要 MTLLoader.js
以及 OBJMTLLoader.js
*.dae
*.ctm
*.ply
-- 需要 PLYLoader.js
*.stl
-- 需要 STLLoader.js
*.wrl
*.vtk
- 需要 VTKLoader.js
创建 loader
变量,用于导入模型
loader
导入模型的时候,接受两个参数:
第一个表示模型路径
第二个表示完成导入后的回调函数 - 一般我们需要在这个回调函数中将导入的模型添加到场景中。
json 格式文件加载
.obj 格式文件加载
.mtl
为材质文件
本文部分内容参照及引用:
材质种类:
LineBasicMaterial 基础线条材质 -- 可以用于THREE.Line几何体,从而创建着色的直线
LineDashedMaterial 虚线材质 -- 类似与基础材质,但可以创建虚线效果
MeshBasicMaterial 基础网孔材质 - 为几何体赋予一种简单的颜色,或者显示几何体的线框
MeshDepthMaterial 深度网孔材质 - 根据网格到相机的距离,该材质决定如何给网格染色
MeshLambertMaterial 兰伯特网孔材质 - 考虑光照的影响,可以创建颜色暗淡,不光亮的物体
MeshNormalMaterial 法向量网孔材质 - 根据物体表面的法向量计算颜色
MeshPhongMaterial Phong网孔材质 - 考虑光照的影响,可以创建光亮的物体
MeshPhysicalMaterial 物理材质
MeshStandardMaterial 基础网孔材质
MeshToonMaterial
PointsMaterial 点材料
RawShaderMaterial 原始着色器材料
ShaderMaterial 着色器材料 - 使用自定义的着色器程序,直接控制顶点的放置方式,以及像素的着色方式。
ShadowMaterial
SpriteMaterial 精灵材料
使用基本材质(BasicMaterial)的物体,渲染后物体的颜色始终为该材质的颜色,而不会由于光照产生明暗、阴影效果。如果没有指定材质的颜色,则颜色是随机的。(顶图左1)
MeshBasicMaterial( parameters : Object )
parameters
为对象,默认缺省,包含各属性,常见属性:
visible
:是否可见,默认为true
side
:渲染面片正面或是反面,默认为正面 THREE.FrontSide
,可设置为反面 THREE.BackSide
,或双面 THREE.DoubleSide
wireframe
:是否渲染线而非面,默认为 false
color
:十六进制RGB颜色,如红色表示为 0xff0000
map
:使用纹理贴图
纹理在threejs就好比皮肤,可以是各种图片贴图。
对于我们来说就是加载纹理图片,然后平铺到物体到某个面或者全部。
Texture( image, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy, encoding )
Image:这是一个图片类型,基本上它有ImageUtils来加载,如下代码 var image = THREE.ImageUtils.loadTexture(url);
url 是一个图片地址, 这不地址必须是 http://xxx/imgName.jpg
这样的。
Mapping:是一个THREE.UVMapping()类型,它表示的是纹理坐标。
wrapS:表示x轴的纹理的方式,
wrapT:表示y轴的纹理回环方式。
format:表示加载的图片的格式,这个参数可以取值THREE.RGBAFormat,RGBFormat等。THREE.RGBAFormat表示每个像素点要使用四个分量表示,分别是红、绿、蓝、透明来表示。RGBFormat则不使用透明,也就是说纹理不会有透明的效果。
type:表示存储纹理的内存的每一个字节的格式,是有符号,还是没有符号,是整形,还是浮点型。不过这里默认是无符号型(THREE.UnsignedByteType)。
anisotropy:各向异性过滤。使用各向异性过滤能够使纹理的效果更好,但是会消耗更多的内存、CPU、GPU时间。
本文部分内容参照及引用:
主要有两个起始函数:
程序开始时,setup()
函数中的语句执行一次
draw()
中的语句一直执行到程序停止为止。每个语句都按顺序执行,并且在读取最后一行之后,将再次执行第一行
draw()
函数中的代码从上到下连续运行,直到程序停止。
createCanvas(width, height)
: 例 createCanvas(800,600)
noLoop()
函数使 draw()
只执行一次, 如果不调用 noLoop()
,draw()
内的代码会持续运行。
redraw()
函数使 draw()
执行一次。在这个例子中,draw()
将在每次点击鼠标时执行一次。
Points 与 lines 可用于绘制基本几何。 更改变量 'd' 的值以缩放外形。这四个变量根据 'd' 的值设置位置。
基本形状的原始函数包括:
triangle() — 三角形
rect() - 正方形
quad() - 四边形
ellipse() - 圆形
arc() - 弧形 方块是通过 rect() 绘制, 圆形是通过 ellipse() 来绘制。每个功能都需要一些参数来确定形状的位置和大小。
正多边形函数
Star
star() 函数能够绘制各种不同的形式
五角星: star(0, 0, 30, 70, 5);
几何形状(Geometry)最主要的功能是储存了一个物体的顶点信息。WebGL需要程序员指定每个顶点的位置,而在Three.js中,可以通过指定一些特征来创建几何形状,例如使用半径创建一个球体,从而省去程序员一个个指定顶点的工作量。
基本几何形状包括:立方体、平面、球体、圆柱体、四面体、八面体等几何形状,以及以三维文字作为几何形状的方法。
盒型几何是四边形的原始几何类。它通常用于创建一个立方体或带有"宽度"、"高度"和"深度"构造函数参数的不规则四边形。
BoxGeometry(width : Float, height : Float, depth : Float, widthSegments : Integer, heightSegments : Integer, depthSegments : Integer)
width -- X轴上的面的宽度
height -- Y轴上的面的高度
depth -- Z轴上的面的深度
widthSegments -- 可选参数. 沿宽度面的分割面数量. 默认值为1.
heightSegments -- 可选参数. 沿高度面的分割面数量. 默认值为1.
depthSegments -- 可选参数. 沿深度面的分割面数量. 默认值为1.
CircleGeometry(radius, segments, thetaStart, thetaLength)
radius -- 圆的半径, 默认值 = 50.
segments -- 分割面数量 (三角形), 最低值 = 3, 默认值 = 8.
thetaStart -- 第一个分割面的开始角度, 默认值 = 0 (3点钟方向).
thetaLength -- 圆形扇形的圆心角通常称为θ。默认为2 * Pi,这形成了一个完整的圆
ConeGeometry(radius, height, radialSegments, heightSegments, openEnded, thetaStart, thetaLength)
radius -- 锥底半径. 默认值为20.
height -- 锥体高度. 默认值为100.
radiusSegments -- 围绕圆锥周长的分割面数量. 默认值为8.
heightSegments -- 沿圆锥高度的分割面数量. 默认值为1.
openEnded -- 指示锥底是打开还是覆盖的布尔值. 默认值为false, 意思是覆盖.
thetaStart -- 第一个分割面的开始角度, 默认值 = 0 (3点钟方向).
thetaLength -- 圆形扇形的圆心角通常称为θ。默认为2 * Pi,这形成了一个完整的锥体.
CylinderGeometry(radiusTop, radiusBottom, height, radiusSegments, heightSegments, openEnded, thetaStart, thetaLength)
radiusTop -- 圆柱体顶端半径. 默认值为20.
radiusBottom -- 圆柱体底端半径. 默认值为20.
height -- 圆柱体高度. 默认值为100.
radiusSegments -- 围绕圆柱体周长的分割面数量. 默认值为8.
heightSegments -- 沿圆柱体高度的分割面数量. 默认值为1.
openEnded -- 指示圆柱体两端是打开还是覆盖的布尔值. 默认值为false, 意思是覆盖.
thetaStart -- 第一个分割面的开始角度, 默认值 = 0 (3点钟方向).
thetaLength -- 圆形扇形的圆心角通常称为θ。默认为2 * Pi,这形成了一个完整的圆柱体.
PlaneGeometry(width, height, widthSegments, heightSegments)
width -- 沿X轴宽度.
height -- 沿Y轴高度
widthSegments -- 可选参数,x方向的分段数,缺省为1。
heightSegments -- 可选参数,y方向的分段数,缺省为1。
SphereGeometry(radius, widthSegments, heightSegments, phiStart, phiLength, thetaStart, thetaLength)
radius -- 球体半径. 默认值为50.
widthSegments -- 水平分割面的数量. 最小值为3, 默认值为8.
heightSegments -- 垂直分割面的数量. 最小值为2, 默认值为6.
phiStart -- 指定水平起始角度. 默认值为0.
phiLength -- 指定水平扫描角度大小. 默认值为 Math.PI * 2.
thetaStart -- 指定垂直起始角度. 默认值为0.
thetaLength -- 指定垂直扫描角度大小. 默认值为Math.PI.
TorusGeometry(radius, tube, radialSegments, tubularSegments, arc)
radius -- 半径, 默认值为100.
tube -- 管道直径. 默认值为40.
radialSegments -- 默认值为8
tubularSegments -- 默认值为6.
arc -- 圆心角. 默认值为Math.PI * 2.
TorusKnotGeometry(radius, tube, tubularSegments, radialSegments, p, q)
radius -- 半径, 默认值为100.
tube -- 管道直径. 默认值为40.
tubularSegments -- 默认值为64.
radialSegments -- 默认值为8.
p -- 这个值决定了几何体绕旋转对称轴绕了多少圈. 默认值为2.
q -- 这个值决定了几何体绕环面的圆绕了多少圈. 默认值为3.
TextGeometry(text, parameters)
text -- 要显示的文字
parameters -- 包含下面这些参数的对象
font -- THREE. 字体.
size -- Float. 大小.
height -- Float. 文字厚度. 默认值为50.
curveSegments -- Integer. 曲线上点的数量. 默认值为12.
bevelEnabled -- Boolean. 是否打开斜面. 默认值为False.
bevelThickness -- Float. 文本斜面的深度. 默认值为10.
bevelSize -- Float. 斜面离轮廓的距离. 默认值为8.
threejs 只提供了一部分3D字体模型. 汉字没戏了,
目前支持的字体有 helvetiker , optimer , gentilis , droid sans , droid serif 每种都包含normal正常体和 bold 粗体.
本文部分内容参照及引用:
关于性能:测试一个程序,性能上是否有瓶颈,在动画里,经常使用帧数的概念,首先我们来定义一下帧数的意义。
帧数:图形处理器每秒钟能够刷新几次,通常用fps(Frames Per Second)来表示。
当物体在快速运动时,当人眼所看到的影像消失后,人眼仍能继续保留其影像1/24秒左右的图像,这种现象被称为视觉暂留现象。是人眼具有的一种性质。人眼观看物体时,成像于视网膜上,并由视神经输入人脑,感觉到物体的像。一帧一帧的图像进入人脑,人脑就会将这些图像给连接起来,形成动画。
毫无疑问,帧数越高,画面的感觉就会越好。所以大多数游戏都会有超过30的FPS。为了监视FPS,看看你的程序哪里占用了很多的CPU时间,就需要学习一下性能监视器。
在Three.js中,性能由一个来管理。
性能监视器的截图如下所示:
FPS表示:上一秒的帧数,这个值越大越好,一般都为60左右。点击此视图,就会变成下面的另一个视图。
MS表示:渲染一帧需要的毫秒数,这个数字是越小越好。再次点击又可以回到FPS视图中。
添加性能测试窗体
调用stats.update()函数来统计时间和帧数 stats.update();
到 renderer
执行动画到时候即可。
本文部分内容参照及引用:
在这里,我们将动态画面简称为动画(animation)。正如动画片的原理一样,动画的本质是利用了人眼的视觉暂留特性,快速地变换画面,从而产生物体在运动的假象。而对于Three.js程序而言,动画的实现也是通过在每秒中多次重绘画面实现的。
为了衡量画面切换速度,引入了每秒帧数FPS(Frames Per Second)的概念,是指每秒画面重绘的次数。FPS越大,则动画效果越平滑,当FPS小于20时,一般就能明显感受到画面的卡滞现象。
那么FPS是不是越大越好呢?其实也未必。当FPS足够大(比如达到60),再增加帧数人眼也不会感受到明显的变化,反而相应地就要消耗更多资源(比如电影的胶片就需要更长了,或是电脑刷新画面需要消耗计算资源等等)。因此,选择一个适中的FPS即可。
NTSC标准的电视FPS是30,PAL标准的电视FPS是25,电影的FPS标准为24。而对于Three.js动画而言,一般FPS在30到60之间都是可取的。
window.requestAnimationFrame(callback);
requestAnimationFrame
方法告诉浏览器您希望执行动画并请求浏览器在下一次重绘之前调用指定的函数来更新动画,通常可能达到60FPS。
在之前demo中我们已经有过使用的代码,立方体的旋转等。
Tween.js是一个包含各种经典动画算法的JS资源,动画效果主要包括以下:
Quad, Cubic等等都是经典的动画运动算法名称,完整列表如下:
Linear:线性匀速运动效果;
Quadratic:二次方的缓动(t^2);
Cubic:三次方的缓动(t^3);
Quartic:四次方的缓动(t^4);
Quintic:五次方的缓动(t^5);
Sinusoidal:正弦曲线的缓动(sin(t));
Exponential:指数曲线的缓动(2^t);
Circular:圆形曲线的缓动(sqrt(1-t^2));
Elastic:指数衰减的正弦曲线缓动;
Back:超过范围的三次方缓动 ((s+1)*t^3 – s*t^2)
Bounce:指数衰减的反弹缓动
每个效果都分三个缓动方式,分别是:
easeIn:从0开始加速的缓动,也就是先慢后快;
easeOut:减速到0的缓动,也就是先快后慢;
easeInOut:前半段从0开始加速,后半段减速到0的缓动。
Tween.js 具体用法
tween.js 可以链式调用! 每个tween函数都会返回tween实例。
让某物体从A位置移动到B位置,
本文部分内容参照及引用:
WebGL(全写 Web Graphics Library)是一种 3D 绘图标准,这种绘图技术标准允许把 JavaScript 和 OpenGL ES 2.0 结合在一起,通过增加 OpenGL ES 2.0 的一个 JavaScript 绑 定,WebGL 可以为 HTML5 Canvas 提供硬件 3D 加速渲染,这样 Web 开发人员就可以借助系统 显卡来在浏览器里更流畅地展示 3D 场景和模型了,还能创建复杂的导航和数据视觉化。显 然,WebGL 技术标准免去了开发网页专用渲染插件的麻烦,可被用于创建具有复杂 3D 结构 的网站页面,甚至可以用来设计 3D 网页游戏等等。
WebGL 是内嵌在浏览器中的,无需安装插件和库就可以直接使用
在多平台运行 WebGL 程序
让海量数据的三维可视化成为了可能
开发环境简单,仅需文本编辑器和浏览器就可以编写三维图形程序
more
webgl正在成为一个行业标准, 以有越来越多的浏览器宣布支持它. webVR 等新技术的诞生也都离不开 webgl.
而且有GPU加速的浏览器, 必然如虎添翼,在web端可以有更精彩纷呈端效果。
当然,除了Threejs还有其他类似3D图形库比如:
threejs带来了什么?
3D绘图通常来说是比较复杂带工作,用到glsl到很多知识,用js直接调用操作,非常复杂且低效,
这个时候 threejs出现了,使用threejs封装好到功能,可以很方便快速到创造一些简单到场景。
下面我们就来试着写第一个hello world!
新建空白 html 页面,引入 three.js,及页面元素准备。
一个典型的Three.js程序至少要包括:
渲染器(Renderer)---- 渲染器将和Canvas元素进行绑定
场景(Scene)---- 我们创建的物体都添加到场景中,相当于一个大容器
照相机(Camera)---- 这里相当于一个透视投影的三维坐标系
在场景中创建的物体
创建一个形状的代码如下:
现实中会有光源照射物体,产生光影效果,这里也可以添加 light。
Threejs开发过程初步可归纳为
1、设置照相机 camera = new THREE.Camera();
用于观察物体 2、设置场景 scene = new THREE.Scene()
用于承载物体 3、建立物体 geometry = new THREE.CubeGeometry(200, 200, 200);
4、创建网格 mesh = new THREE.Mesh(geometry, material)
5、渲染呈现 renderer.render(scene, camera)
当然还有灯光、动画、材质、控制场景内物体等其他内容,在此不赘述,后续逐步学习。
以上,如果使用过flash或者maya等软件等话,相信对以上场景、相机、渲染、灯光等会比较容易理解。 在这里可以联想为在3D软件里创建一个物体,当然软件所有操作及效果是需要我们用代码来实现。
这里还有一份
threejs 最早是 在 GitHub上发布的一个基于webgl的3D图形库。
收集学习网络相关 three.js 的优秀 demo,学习之,共勉。
main 函数
最终的像素颜色取决于预设的全局变量 gl_FragColor。
vec4 四分量浮点向量 vec4(1.0,0.0,1.0,1.0), 四个变元分别响应红,绿,蓝和透明度通道
vec3 三分量浮点向量
vec2 二分量浮点向量
它们的数据类型通常为:float, vec2, vec3, vec4, mat2, mat3, mat4, sampler2D and samplerCube。
uniform 值需要数值类型前后一致。且在 shader 的开头,在设定精度之后,就对其进行定义。
就像 GLSL 有个默认输出值 vec4 gl_FragColor 一样,它也有一个默认输入值( vec4 gl_FragCoord )。
gl_FragCoord存储了活动线程正在处理的像素或屏幕碎片的坐标。有了它我们就知道了屏幕上的哪一个线程正在运转。
为什么我们不叫 gl_FragCoord uniform (统一值)呢?因为每个像素的坐标都不同,所以我们把它叫做 varying
(变化值)。
pow()
- 求x的y次幂
exp()
- 以自然常数e为底的指数函数
log()
- 对数函数
sqrt()
- 平方根函数
abs()
- 绝对值
ceil()
- 向正无穷取整
floor()
- 向负无穷取整
fract()
- 只选取小数部分
clamp(x,0.0,1.0)
把 x 的值限制在 0.0 到 1.0
Step 和 Smoothstep
step()
- 插值函数需要输入两个参数。第一个是极限或阀值,第二个是我们想要检测或通过的值。对任何小于阀值的值,返回 0.0,大于阀值,则返回 1.0。
smoothstep()
- 当给定一个范围的上下限和一个数值,这个函数会在已有的范围内给出插值。前两个参数规定转换的开始和结束点,第三个是给出一个值用来插值。
在GLSL中,有个十分有用的函数:mix()
mix()
函数:以百分比混合两个值。
百分比的取值范围:0~1
fract()
函数: 返回小数点后的数。
可用的数据类型只有4种:有符号整数,无符号整数,浮点数,布尔值。 OpenGL着色语言中没有指针和字符串或字符。返回值可以为void。
所有4种基本数据类型都可以存储在二维、三维或者四维向量中:
OpenGL着色语言向量数据类型
vec2,vec3,vec4
2分量、3分量和4分量浮点向量
ivec2,ivec3,ivec4
2分量、3分量和4分量整数向量
uvec2,uvec3,uvec4
2分量、3分量和4分量无符号整数向量
bvec2,vbec3,bvec4
2分量、3分量和4分量布尔向量
矩阵类型只支持浮点数
OpenGL着色语言矩阵数据类型
mat2,mat2x2
两行两列
mat3,mat3x3
三行三列
mat4,mat4x4
四行四列
mat2x3
三行两列
mat2x4
四行两列
mat3x2
两行三列
mat3x4
四行三列
mat4x2
两行四列
mat4x3
三行四列
限定符用于将变量标记为输入变量、输出变量或常量。
变量存储限定符
const
一个编译时常量,或者说是一个队函数来说为只读的参数
in
一个从以前的截断传递过来的变量
in
centroid 一个从以前的截断传递过来的变量,使用质心插值
out
传递到下一个处理阶段或者在一个函数中指定一个返回值
out
centroid 传递到下一个处理阶段,使用质心插值
inout
一个读/写变量,只能用于局部函数参数
uniform
一个从客户端代码传递过来的变量,在顶点之间不做改变
属性是每个顶点位置、表面法线和纹理坐标等都需要的,而统一值则用于为整个图元批次向保持不变的(统一(uniform)的)着色器传递数据。 创建一个统一值只需在变量声明开始时放置一个uniform关键词:
A collection of decorative shapes displayed as backgrounds using WebGL. The shapes are created with Three.js and animated with the TweenMax library. By Louis Hoebregts.
This demo is kindly sponsored by we.design: Snag the hottest new domain name for designers
NOISE! by Seph Gentle
Nexa Bold font by Fontfabric
This resource can be used freely if integrated or build upon in personal or commercial projects such as websites, web apps and web templates intended for sale. It is not allowed to take the resource "as-is" and sell it, redistribute, re-publish it, or sell "pluginized" versions of it. Free plugins built using this resource should have a visible mention and link to the original work. Always consider the licenses of all included libraries, scripts and images used.
Follow Louis: Twitter, Codepen, LinkedIn, GitHub
Follow Codrops: Twitter, Facebook, Google+, GitHub, Pinterest, Instagram
A tunnel experiment in WebGL inspired by the effect seen on the http://www.fornasetti.com/ website. By Louis Hoebregts.
Brick texture is from maxTextures
Perlin noise algorithm was written by Seph Gentle
Modern pattern with hand drawn stripes from Freepik.com
Blood cell model is from Turbosquid
This resource can be used freely if integrated or build upon in personal or commercial projects such as websites, web apps and web templates intended for sale. It is not allowed to take the resource "as-is" and sell it, redistribute, re-publish it, or sell "pluginized" versions of it. Free plugins built using this resource should have a visible mention and link to the original work. Always consider the licenses of all included libraries, scripts and images used.
Follow Louis: Twitter, Codepen, LinkedIn
Follow Codrops: Twitter, Facebook, Google+, GitHub, Pinterest, Instagram
整理收集了亚赛大人的效果展示。
Speed-Line - 漫画必备超燃速度线
Play-a-ball - 抽象球体生成器
Awesome Masoic - 动态马赛克背景生成器
Perlin Noise - 等高线神器
Stars-Emmision - 万箭齐发毫发无伤背景生成器
Particles-Emission - 粒子循环运动神器
Demos and game for the tutorial "The Making of 'The Aviator': Animating a Basic 3D Scene with Three.js", by Karim Maaloul.
Integrate or build upon it for free in your personal or commercial projects. Don't republish, redistribute or sell "as-is".
Read more here: License
Follow Karim: Twitter, Codepen
Follow Codrops: Twitter, Facebook, Google+, GitHub, Pinterest
Code repository for the examples from the Packt book "Learning Threejs"
All examples for chapter 1.
Branch used to update all examples to three.js release r63
Code repository for the examples from the Packt book "Learning Threejs"
Code repository for the examples from the Packt book "Learning Threejs"
Code repository for the examples from the Packt book "Learning Threejs"
Code repository for the examples from the Packt book "Learning Threejs"
Code repository for the examples from the Packt book "Learning Threejs"
Code repository for the examples from the Packt book "Learning Threejs"
Code repository for the examples from the Packt book "Learning Threejs"
void
空类型,即不返回任何值
bool
布尔类型 true,false
int
带符号的整数 signed integer
float
带符号的浮点数 floating scalar
vec2, vec3, vec4
n维浮点数向量 n-component floating point vector
bvec2, bvec3, bvec4
n维布尔向量 Boolean vector
ivec2, ivec3, ivec4
n维整数向量 signed integer vector
mat2, mat3, mat4
2x2, 3x3, 4x4 浮点数矩阵 float matrix
sampler2D
2D纹理 a 2D texture
samplerCube
盒纹理 cube mapped texture
结构
struct type-name{} 类似c语言中的 结构体
数组
float foo[3] glsl只支持1维数组,数组可以是结构体的成员
glsl中的向量(vec2,vec3,vec4)往往有特殊的含义,比如可能代表了一个空间坐标(x,y,z,w),或者代表了一个颜色(r,g,b,a),再或者代表一个纹理坐标(s,t,p,q) 所以glsl提供了一些更人性化的分量访问方式.
vector.xyzw
其中xyzw 可以任意组合
vector.rgba
其中rgba 可以任意组合
vector.stpq
其中rgba 可以任意组合
1
()
聚组:a*(b+c)
N/A
2
[] () . ++ --
数组下标__[],方法参数__fun(arg1,arg2,arg3),属性访问__a.b__,自增/减后缀__a++ a--__
L - R
3
++ -- + - !
自增/减前缀__++a --a__,正负号(一般正号不写)a ,-a,取反__!false__
R - L
4
* /
乘除数学运算
L - R
5
+ -
加减数学运算
L - R
7
< > <= >=
关系运算符
L - R
8
== !=
相等性运算符
L - R
12
&&
逻辑与
L - R
13
^^
逻辑排他或(用处基本等于!=)
L - R
14
||
逻辑或
L - R
15
? :
三目运算符
L - R
16
= += -= *= /=
赋值与复合赋值
L - R
17
,
顺序分配运算
L - R
ps 左值与右值:
glsl中,没有隐式类型转换,原则上glsl要求任何表达式左右两侧(l-value),(r-value)的类型必须一致 也就是说以下表达式都是错误的:
下面来分别说说可能遇到的情况:
1.float
与 int
:
float与float , int与int之间是可以直接运算的,但float与int不行.它们需要进行一次显示转换.即要么把float转成int: int(1.0) ,要么把int转成float: float(1) ,以下表达式都是正确的:
2.float
与 vec(向量)
mat(矩阵)
:
vec,mat这些类型其实是由float复合而成的,当它们与float运算时,其实就是在每一个分量上分别与float进行运算,这就是所谓的逐分量
运算.glsl里 大部分涉及vec,mat的运算都是逐分量
运算,但也并不全是. 下文中就会讲到特例.
逐分量
运算是线性的,这就是说 vec 与 float 的运算结果是还是 vec.
int 与 vec,mat之间是不可运算的, 因为vec和mat中的每一个分量都是 float 类型的. 无法与int进行逐分量计算.
下面枚举了几种 float 与 vec,mat 运算的情况
3. vec(向量)
与 vec(向量)
:
两向量间的运算首先要保证操作数的阶数都相同.否则不能计算.例如: vec3*vec2 vec4+vec3 等等都是不行的.
它们的计算方式是两操作数在同位置上的分量分别进行运算,其本质还是逐分量进行的,这和上面所说的float类型的 逐分量运算可能有一点点差异,相同的是 vec 与 vec 运算结果还是 vec, 且阶数不变.
3. vec(向量)
与 mat(矩阵)
:
要保证操作数的阶数相同,且vec与mat间只存在乘法运算.
它们的计算方式和线性代数中的矩阵乘法相同,不是逐分量运算.
向量与矩阵的乘法规则如下:
4. mat(矩阵)
与 mat(矩阵)
:
要保证操作数的阶数相同.
在mat与mat的运算中, 除了乘法是线性代数中的矩阵乘法外.其余的运算任为逐分量运算.简单说就是只有乘法是特殊的,其余都和vec与vec运算类似.
矩阵乘法规则如下:
none
(默认的可省略)本地变量,可读可写,函数的输入参数既是这种类型
const
声明变量或函数的参数为只读类型
attribute
只能存在于vertex shader中,一般用于保存顶点或法线数据,它可以在数据缓冲区中读取数据
uniform
在运行时shader无法改变uniform变量, 一般用来放置程序传递给shader的变换矩阵,材质,光照参数等等.
varying
主要负责在vertex 和 fragment 之间传递变量
const:
和C语言类似,被const限定符修饰的变量初始化后不可变,除了局部变量,函数参数也可以使用const修饰符.但要注意的是结构变量可以用const修饰, 但结构中的字段不行.
const变量必须在声明时就初始化 const vec3 v3 = vec3(0.,0.,0.)
局部变量只能使用const限定符.
函数参数只能使用const限定符.
attribute:
attribute变量是全局
且只读
的,它只能在vertex shader中使用,只能与浮点数,向量或矩阵变量组合, 一般attribute变量用来放置程序传递来的模型顶点,法线,颜色,纹理等数据它可以访问数据缓冲区 (还记得__gl.vertexAttribPointer__这个函数吧)
uniform:
uniform变量是全局
且只读
的,在整个shader执行完毕前其值不会改变,他可以和任意基本类型变量组合, 一般我们使用uniform变量来放置外部程序传递来的环境数据(如点光源位置,模型的变换矩阵等等) 这些数据在运行中显然是不需要被改变的.
varying:
varying类型变量是 vertex shader 与 fragment shader 之间的信使,一般我们在 vertex shader 中修改它然后在fragment shader使用它,但不能在 fragment shader中修改它.
要注意全局变量限制符只能为 const、attribute、uniform和varying中的一个.不可复合.
函数的参数默认是以拷贝的形式传递的,也就是值传递,任何传递给函数参数的变量,其值都会被复制一份,然后再交给函数内部进行处理. 我们可以为参数添加限定符来达到传递引用的目的,glsl中提供的参数限定符如下:
< none: default >
默认使用 in 限定符
in
复制到函数中在函数中可读写
out
返回时从函数中复制出来
inout
复制到函数中并在返回时复制出来
in
是函数参数的默认限定符,最终真正传入函数形参的其实是实参的一份拷贝.在函数中,修改in修饰的形参不会影响到实参变量本身.
out
它的作用是向函数外部传递新值,out模式下传递进来的参数是write-only的(可写不可读).就像是一个"坑位",坑位中的值需要函数给他赋予. 在函数中,修改out修饰的形参会影响到实参本身.
inout
inout下,形参可以被理解为是一个带值的"坑位",及可读也可写,在函数中,修改inout修饰的形参会影响到实参本身.
glsl允许在程序的最外部声明函数.函数不能嵌套,不能递归调用,且必须声明返回值类型(无返回值时声明为void) 在其他方面glsl函数与c函数非常类似.
glsl中变量可以在声明的时候初始化,float pSize = 10.0
也可以先声明然后等需要的时候在进行赋值.
聚合类型对象如(向量,矩阵,数组,结构) 需要使用其构造函数来进行初始化. vec4 color = vec4(0.0, 1.0, 0.0, 1.0);
glsl可以使用构造函数进行显式类型转换,各值如下:
glsl在进行光栅化着色的时候,会产生大量的浮点数运算,这些运算可能是当前设备所不能承受的,所以glsl提供了3种浮点数精度,我们可以根据不同的设备来使用合适的精度.
在变量前面加上 highp
mediump
lowp
即可完成对该变量的精度声明.
我们一般在片元着色器(fragment shader)最开始的地方加上 precision mediump float;
便设定了默认的精度.这样所有没有显式表明精度的变量 都会按照设定好的默认精度来处理.
如何确定精度:
变量的精度首先是由精度限定符决定的,如果没有精度限定符,则要寻找其右侧表达式中,已经确定精度的变量,一旦找到,那么整个表达式都将在该精度下运行.如果找到多个, 则选择精度较高的那种,如果一个都找不到,则使用默认或更大的精度类型.
invariant关键字:
由于shader在编译时会进行一些内部优化,可能会导致同样的运算在不同shader里结果不一定精确相等.这会引起一些问题,尤其是vertx shader向fragmeng shader传值的时候. 所以我们需要使用invariant
关键字来显式要求计算结果必须精确一致. 当然我们也可使用 #pragma STDGL invariant(all)
来命令所有输出变量必须精确一致, 但这样会限制编译器优化程度,降低性能.
限定符的顺序:
当需要用到多个限定符的时候要遵循以下顺序:
1.在一般变量中: invariant > storage > precision
2.在参数中: storage > parameter > precision
我们来举例说明:
以 # 开头的是预编译指令,常用的有:
比如 #version 100 他的意思是规定当前shader使用 GLSL ES 1.00标准进行编译,如果使用这条预编译指令,则他必须出现在程序的最开始位置.
内置的宏:
__LINE__
: 当前源码中的行号.
__VERSION__
: 一个整数,指示当前的glsl版本 比如 100 ps: 100 = v1.00
GL_ES
: 如果当前是在 OPGL ES 环境中运行则 GL_ES 被设置成1,一般用来检查当前环境是不是 OPENGL ES.
GL_FRAGMENT_PRECISION_HIGH
: 如果当前系统glsl的片元着色器支持高浮点精度,则设置为1.一般用于检查着色器精度.
实例:
1.如何通过判断系统环境,来选择合适的精度:
2.自定义宏:
glsl程序使用一些特殊的内置变量与硬件进行沟通.他们大致分成两种 一种是 input
类型,他负责向硬件(渲染管线)发送数据. 另一种是output
类型,负责向程序回传数据,以便编程时需要.
在 vertex Shader 中:
output 类型的内置变量:
highp vec4 gl_Position
;
gl_Position 放置顶点坐标信息
vec4
mediump float gl_PointSize
;
gl_PointSize 需要绘制点的大小,(只在gl.POINTS模式下有效)
float
在 fragment Shader 中:
input 类型的内置变量:
mediump vec4 gl_FragCoord
;
片元在framebuffer画面的相对位置
vec4
bool gl_FrontFacing
;
标志当前图元是不是正面图元的一部分
bool
mediump vec2 gl_PointCoord
;
经过插值计算后的纹理坐标,点的范围是0.0到1.0
vec2
output 类型的内置变量:
mediump vec4 gl_FragColor
;
设置当前片点的颜色
vec4 RGBA color
mediump vec4 gl_FragData[n]
设置当前片点的颜色,使用glDrawBuffers数据数组
vec4 RGBA color
glsl提供了一些内置的常量,用来说明当前系统的一些特性. 有时我们需要针对这些特性,对shader程序进行优化,让程序兼容度更好.
在 vertex Shader 中:
1.const mediump int gl_MaxVertexAttribs
>=8
gl_MaxVertexAttribs 表示在vertex shader(顶点着色器)中可用的最大attributes数.这个值的大小取决于 OpenGL ES 在某设备上的具体实现, 不过最低不能小于 8 个.
2.const mediump int gl_MaxVertexUniformVectors
>= 128
gl_MaxVertexUniformVectors 表示在vertex shader(顶点着色器)中可用的最大uniform vectors数. 这个值的大小取决于 OpenGL ES 在某设备上的具体实现, 不过最低不能小于 128 个.
3.const mediump int gl_MaxVaryingVectors
>= 8
gl_MaxVaryingVectors 表示在vertex shader(顶点着色器)中可用的最大varying vectors数. 这个值的大小取决于 OpenGL ES 在某设备上的具体实现, 不过最低不能小于 8 个.
4.const mediump int gl_MaxVertexTextureImageUnits
>= 0
gl_MaxVaryingVectors 表示在vertex shader(顶点着色器)中可用的最大纹理单元数(贴图). 这个值的大小取决于 OpenGL ES 在某设备上的具体实现, 甚至可以一个都没有(无法获取顶点纹理)
5.const mediump int gl_MaxCombinedTextureImageUnits
>= 8
gl_MaxVaryingVectors 表示在 vertex Shader和fragment Shader总共最多支持多少个纹理单元. 这个值的大小取决于 OpenGL ES 在某设备上的具体实现, 不过最低不能小于 8 个.
在 fragment Shader 中:
1.const mediump int gl_MaxTextureImageUnits
>= 8
gl_MaxVaryingVectors 表示在 fragment Shader(片元着色器)中能访问的最大纹理单元数,这个值的大小取决于 OpenGL ES 在某设备上的具体实现, 不过最低不能小于 8 个.
2.const mediump int gl_MaxFragmentUniformVectors
>= 16
gl_MaxFragmentUniformVectors 表示在 fragment Shader(片元着色器)中可用的最大uniform vectors数,这个值的大小取决于 OpenGL ES 在某设备上的具体实现, 不过最低不能小于 16 个.
3.const mediump int gl_MaxDrawBuffers
= 1
gl_MaxDrawBuffers 表示可用的drawBuffers数,在OpenGL ES 2.0中这个值为1, 在将来的版本可能会有所变化.
glsl中还有一种内置的uniform状态变量, gl_DepthRange
它用来表明全局深度范围.
结构如下:
除了 gl_DepthRange 外的所有uniform状态常量都已在glsl 1.30 中废弃
.
glsl的流控制和c语言非常相似,这里不必再做过多说明,唯一不同的是片段着色器中有一种特殊的控制流discard
. 使用discard会退出片段着色器,不执行后面的片段着色操作。片段也不会写入帧缓冲区。
glsl提供了非常丰富的函数库,供我们使用,这些功能都是非常有用且会经常用到的. 这些函数按功能区分大改可以分成7类:
通用函数:
下文中的 类型 T可以是 float, vec2, vec3, vec4,且可以逐分量操作.
T abs(T x)
返回x的绝对值
T sign(T x)
比较x与0的值,大于,等于,小于 分别返回 1.0 ,0.0,-1.0
T floor(T x)
返回<=x的最大整数
T ceil(T x)
返回>=等于x的最小整数
T fract(T x)
获取x的小数部分
T mod(T x, T y) T mod(T x, float y)
取x,y的余数
T min(T x, T y) T min(T x, float y)
取x,y的最小值
T max(T x, T y) T max(T x, float y)
取x,y的最大值
T clamp(T x, T minVal, T maxVal) T clamp(T x, float minVal,float maxVal)
min(max(x, minVal), maxVal),返回值被限定在 minVal,maxVal之间
T mix(T x, T y, T a) T mix(T x, T y, float a)
取x,y的线性混合,x*(1-a)+y*a
T step(T edge, T x) T step(float edge, T x)
如果 x<edge 返回 0.0 否则返回1.0
T smoothstep(T edge0, T edge1, T x) T smoothstep(float edge0,float edge1, T x)
如果x<edge0 返回 0.0 如果x>edge1返回1.0, 否则返回Hermite插值
角度&三角函数:
下文中的 类型 T可以是 float, vec2, vec3, vec4,且可以逐分量操作.
T radians(T degrees)
角度转弧度
T degrees(T radians)
弧度转角度
T sin(T angle)
正弦函数,角度是弧度
T cos(T angle)
余弦函数,角度是弧度
T tan(T angle)
正切函数,角度是弧度
T asin(T x)
反正弦函数,返回值是弧度
T acos(T x)
反余弦函数,返回值是弧度
T atan(T y, T x) T atan(T y_over_x)
反正切函数,返回值是弧度
指数函数:
下文中的 类型 T可以是 float, vec2, vec3, vec4,且可以逐分量操作.
T pow(T x, T y)
返回x的y次幂 xy
T exp(T x)
返回x的自然指数幂 ex
T log(T x)
返回x的自然对数 ln
T exp2(T x)
返回2的x次幂 2x
T log2(T x)
返回2为底的对数 log2
T sqrt(T x)
开根号 √x
T inversesqrt(T x)
先开根号,在取倒数,就是 1/√x
几何函数:
下文中的 类型 T可以是 float, vec2, vec3, vec4,且可以逐分量操作.
float length(T x)
返回矢量x的长度
float distance(T p0, T p1)
返回p0 p1两点的距离
float dot(T x, T y)
返回x y的点积
vec3 cross(vec3 x, vec3 y)
返回x y的叉积
T normalize(T x)
对x进行归一化,保持向量方向不变但长度变为1
T faceforward(T N, T I, T Nref)
根据 矢量 N 与Nref 调整法向量
T reflect(T I, T N)
返回 I - 2 * dot(N,I) * N, 结果是入射矢量 I 关于法向量N的 镜面反射矢量
T refract(T I, T N, float eta)
返回入射矢量I关于法向量N的折射矢量,折射率为eta
矩阵函数:
mat可以为任意类型矩阵.
mat matrixCompMult(mat x, mat y)
将矩阵 x 和 y的元素逐分量相乘
向量函数:
下文中的 类型 T可以是 vec2, vec3, vec4, 且可以逐分量操作.
bvec指的是由bool类型组成的一个向量:
bvec lessThan(T x, T y)
逐分量比较x < y,将结果写入bvec对应位置
bvec lessThanEqual(T x, T y)
逐分量比较 x <= y,将结果写入bvec对应位置
bvec greaterThan(T x, T y)
逐分量比较 x > y,将结果写入bvec对应位置
bvec greaterThanEqual(T x, T y)
逐分量比较 x >= y,将结果写入bvec对应位置
bvec equal(T x, T y) bvec equal(bvec x, bvec y)
逐分量比较 x == y,将结果写入bvec对应位置
bvec notEqual(T x, T y) bvec notEqual(bvec x, bvec y)
逐分量比较 x!= y,将结果写入bvec对应位置
bool any(bvec x)
如果x的任意一个分量是true,则结果为true
bool all(bvec x)
如果x的所有分量是true,则结果为true
bvec not(bvec x)
bool矢量的逐分量取反
纹理查询函数:
图像纹理有两种 一种是平面2d纹理,另一种是盒纹理,针对不同的纹理类型有不同访问方法.
纹理查询的最终目的是从sampler中提取指定坐标的颜色信息. 函数中带有Cube字样的是指 需要传入盒状纹理. 带有Proj字样的是指带投影的版本.
以下函数只在vertex shader中可用:
以下函数只在fragment shader中可用:
在 vertex shader 与 fragment shader 中都可用:
下面的shader如果你可以一眼看懂,说明你已经对glsl语言基本掌握了.
Vertex Shader:
Fragment Shader:
Code repository for the examples from the Packt book "Learning Threejs"