内容来源于书籍【美】乔斯.德克森著,杨芬、赵汝达 译的《Three.js开发指南第2版》 以下为读书笔记,仅供学习
随书源码地址:https://github.com/josdirksen/learning-threejs
[TOC]
第 3 章 学习使用 Three.js 中的光源
不同种类的光源
名字 | 描述 |
---|---|
THREE. AmbientLight | 基本光源,该光源的颜色将会叠加到场景现有物体的颜色上 |
THREE. PointLight | 点光源,从空间的一个点向所有方向发射光线,点光源不能用来创建阴影 |
THREE. SpotLight | 光源有聚光的效果,类似台灯、天花板上的吊灯或手电筒,这种光源可以投射阴影 |
THREE. DirectionalLIght | 无线光,光源发出的光线可以看作是平行,类似太阳光,可创建阴影 |
THREE. HemisphereLight | 特殊光源,可通过模拟反光面和光线微弱的天空来创建更加自然的室外光线,不提供阴影相关功能 |
THREE. AreaLight | 可指定散发光线的平面,不是一个点,不投射阴影 |
THREE. LensFlare | 不是光源,可为场景中的光源家镜头光晕效果 |
THREE. AmbientLight
颜色将应用到全局,将场景中所有物体渲染为相同颜色
THREE. SpotLight 光源来产生阴影
THREE. Color
函数名 | 描述 |
---|---|
set(value) | 十六进制颜色值,可以是字符串,数值,THREE. Color |
setHex(value) | 十六进制数字值 |
setRGB(r, g, b) | RGB 值颜色,范围 0~1 |
setHSL(h, s, l) | HSL 值颜色,范围 0~1 |
setStyle(style) | css 颜色 |
copy(color) | 复制颜色对象 |
copyGammaToLinear(color) | 伽马色彩转换到线性色彩,内部使用 |
copyLinearToGamma(color) | 线性色彩转换到伽马色彩,内部使用 |
convertGammaToLinear(color) | 伽马色彩转换到线性色彩 |
convertLinearToGammacolor) | 线性色彩转换到伽马色彩 |
getHex() | 十六进制值 |
getHexString() | 十六进制字符串 |
getStyle() | css 颜色 |
getHSL(optionalTarget) | HSL 颜色值 |
offsetHSL(h, s, l) | 将 h, s, l 添加到当前颜色 h, s, l |
add(color) | 将 r, g, b 添加到当前颜色 |
addColors(color1, color2) | 内部使用,color1, color2 相加 |
addScalar(s) | 内部使用,当前颜色 RGB 分量上 |
multiply(color) | 内部使用,当前颜色与 THREE.color 对象的 RGB 值相乘 |
multiplyScalar(s) | 内部使用,当前颜色与 RGB 值相乘 |
lerp(color, alpha) | 内部使用,找出介于对象和颜色和提供颜色之间的颜色,alpha 定义当前颜色与提供颜色的差距 |
lerp(color, alpha) | 内部使用,找出介于对象和颜色和提供颜色之间的颜色,alpha 定义当前颜色与提供颜色的差距 |
equals(color) | THREE. Color 颜色对象的 RGB 值与当前值相等与否 |
fromArray(array) | 与 setRGB 方法具有相同的功能,只是 RGB 值通过数字数组传入 |
toArray | 返回三元素组[r, g, b] |
clone() | 复制当前颜色 |
THREE. PointLight
THREE. PointLight 从特定的一点向所有方向发射光线,点光源
属性 | 描述 |
---|---|
color(颜色) | 光源颜色 |
distance(距离) | 光源照射的距离,默认 0,以为光的强度不会随距离增加而减少 |
intensity(强度) | 光源照射的强度, 默认 1 |
position(位置) | 光源在场景中的位置 |
visible(是否可见) | true 光源打开,false 光源关闭 |
var pointColor = '#ccffcc';
var pointLight = new THREE.PointLight(pointColor);
pointLight.position.set(10, 10, 10);
pointLight.intensity = 2.4;
pointLight.distance = 100;
scene.add(pointLight);
THREE. SpotLight
从特定一点发射锥形光线,聚光灯光源
其他属性同 THREE. PointLight
属性 | 描述 |
---|---|
angle(角度) | 光源发射出的光速宽度,单位弧度, 默认值 Math. PI/3 |
caseShadow(投影) | 光源是否产生投影 |
exponent(光强衰减指数) | 光线强度递减的速度 |
onlyShadow(仅阴影) | 光源只生成阴影,不会再场景中添加任何光照 |
shadowBias(阴影偏移) | 偏置阴影的位置,默认 0 |
shadowCameraFar(投影远点) | 到距离光源光源那个位置可生成阴影,默认值为 5000 |
shadowCameraFov(投影视场) | 用于生成阴影的视场有多大,默认值为 50 |
shadowCameraNear(投影近点) | 到距离光源光源那个位置开始生成阴影,默认值为 50 |
shadowCameraVisible(阴影方式可见) | 光源阴影设置可见与否 |
shadowDarkness(阴影暗度) | 阴影渲染的暗度,在场景渲染后无法更改,默认 0.5 |
shadowMapWidth, shadowMapHeight(阴影映射宽度和高度) | 决定有多少像素用来生成阴影,若阴影锯齿状或不光滑,增加此值,渲染后无法更改,默认 512 |
target(目标) | 光源只想场景中的特定对象或位置 |
var pointColor = '#ffffff';
var spotLight = new THREE.spotLight(pointColor);
spotLight.position.set(-40, 60, -10);
spotLight.castShadow = true;
spotLight.target = plane;
var target = new THREE.Object3D();
target.position = new THREE.Vector3(5, 0, 0);
spotLight.target = target;
scene.add(spotLight);
阴影使用可能遇到的问题
- 阴影模糊,增加 shadowMapWidth 和 shadowMapHeight,或保证用于计算阴影区域紧密包围在对象周围(shadowCameraNear, shadowCameraFar, shadowCameraFov)
- 产生阴影与接收阴影设置,光源生成阴影,几何体是否接收或投射阴影 castShadow 和 receiveShadow
- 薄对象渲染阴影时可能出现奇怪的渲染失真,可通过 shadowBias 轻微偏移阴影来修复
- 调整 shadowDarkness 来改变阴影的暗度
- 阴影更柔和,可在 THREE. WebGLRenderer 设置不同 shadowMapType。默认 THREE. PCFShadowMap, 柔和:PCFSoftShadowMap
THREE. DirectionalLisht
从而为平面发射光线,光线彼此平行,平行光源,光强是一样的
其他属性同 SpotLight
//阴影区域
directionalLight.shadowCameraNear = 2;
directionalLight.shadowCameraFar = 200;
directionalLight.shadowCameraLeft = -50;
directionalLight.shadowCameraRight = 50;
directionalLight.shadowCameraTop = 50;
directionalLight.shadowCameraBottom = -50;
//创建更好的阴影效果
directionalLight.shadowCascade = true;
//将阴影生成分裂,靠近摄像机十点会产生更具细节的阴影,远离摄像机十点阴影的细节更少
directionalLight.shadowCascadeCount;
shadowCascadeBias;
shadowCascadeWidth;
shadowCascadeHeight;
shadowCascadeNearZ;
shadowCascadeFarZ;
THREE. HemisphereLight
户外光照效果
var hemiLight = new THREE.HemisphereLight(0x0000ff, 0x00ff00, 0.6);
hemiLight.position.set(0, 500, 0);
scene.add(hemiLight);
属性 | 描述 |
---|---|
groundColor | 从地面发出的光线颜色 |
color | 从天空发出的光线颜色 |
intensity | 光线照射强度 |
THREE. AreaLight
长方体的发光区域
使用 WebGLDeferredRenderer
<script type="text/javascript" src="../libs/WebGLDeferredRenderer.js"></script>
<script type="text/javascript" src="../libs/ShaderDeferred.js"></script>
<script type="text/javascript" src="../libs/RenderPass.js"></script>
<script type="text/javascript" src="../libs/EffectComposer.js"></script>
<script type="text/javascript" src="../libs/CopyShader.js"></script>
<script type="text/javascript" src="../libs/ShaderPass.js"></script>
<script type="text/javascript" src="../libs/FXAAShader.js"></script>
<script type="text/javascript" src="../libs/MaskPass.js"></script>
var renderer = new THREE.WebGLDeferredRenderer({
width: window.innerWidth,
height: window.innerHeight,
scale: 1,
antialias: true,
tonemapping: THREE.FilmicOperator,
brightness: 2.5,
});
var areaLight1 = new THREE.AreaLight(0xff0000, 3);
areaLight1.position.set(-10, 10, -35);
areaLight1.rotation.set(-Math.PI / 2, 0, 0);
areaLight1.width = 4;
areaLight1.height = 9.9;
scene.add(areaLight1);
var planeGeometry1 = new THREE.BoxGeometry(4, 10, 0);
var planeGeometry1Mat = new THREE.MeshBasicMaterial({
color: 0xff0000
});
var plane1 = new THREE.Mesh(planeGeometry1, planeGeometry1Mat);
//在areaLight相同位置 防止对象来模拟光线照射的区域
plane1.position.copy(areaLight1.position);
scene.add(plane1);
THREE. LensFlare
镜头光晕
flare = new THREE.LensFlare(texture, size, distance, blending, color, opacity);
参数 | 描述 |
---|---|
texture(纹理) | 图片纹理,用来决定光晕的形状 |
size(尺寸) | 光晕大小,单位像素,值-1,使用纹理本身的尺寸 |
distance(距离) | 从光源 0 到摄像机 1 的距离,将镜头光晕防止在正确位置 |
blending(混合) | 为光晕提供多种材质,混合材质,默认 THREE. AdditiveBlending |
color(颜色) | 光晕颜色 |
var textureFlare0 = THREE.ImageUtils.loadTexture('../assets/textures/lensflare/lensflare0.png');
var textureFlare3 = THREE.ImageUtils.loadTexture('../assets/textures/lensflare/lensflare3.png');
var flareColor = new THREE.Color(0xffaacc);
var lensFlare = new THREE.LensFlare(textureFlare0, 350, 0.0, THREE.AdditiveBlending, flareColor);
lensFlare.add(textureFlare3, 60, 0.6, THREE.AdditiveBlending);
lensFlare.add(textureFlare3, 70, 0.7, THREE.AdditiveBlending);
lensFlare.add(textureFlare3, 120, 0.9, THREE.AdditiveBlending);
lensFlare.add(textureFlare3, 70, 1.0, THREE.AdditiveBlending);
lensFlare.position.copy(spotLight.position);
scene.add(lensFlare);
第 4 章 使用 Three.js 的材质
名称 | 描述 |
---|---|
MeshBasicMaterial(网格基础材质) | 给几何体赋予一种简单颜色,可显示几何体线框 |
MeshDepthMaterial(网格深度材质) | 从摄像机到网格的距离决定如何给网格上色 |
MeshNormalMaterial(网格法向材质) | 根据法向量计算物体表面的颜色 |
MeshFaceMaterial(网格面材质) | 容器,可为几何体的各个表面指定不同的材质 |
MeshLambertMaterial(网格 Lambert 材质) | 考虑光照影响,用于创建暗淡、不光亮的物体 |
MeshPhongMaterial(网格 Phong 式材质) | 考虑光照影响,用于创建光亮的物体 |
ShaderMaterial(着色器材质) | 允许自定义的着色器程序,直接控制顶点的繁殖方式和像素的着色方式,与 THREE. BufferedGeometry 一起使用 |
LineBaseMaterial(直线基础材质) | 用于 THREE. Line 几何体,创建着色的直线 |
LineDashMaterial(虚线材质) | 同上,允许创建出虚线效果 |
分类
- 基础属性:最常用,可控制物体的不透明度,是否可见以及被应用
- 融合属性:每个物体都有一系列的融合属性,决定物体与背景的融合
- 高级属性:可控制底层 WebGL 上下午对象渲染物体的方式
基础属性 THREE. Material
属性 | 描述 |
---|---|
id(标识符) | 用来识别材质,并在材质创建时复制,第一个材质的值从 0 开始,每新增一个材质这个值加 1 |
uuid(通用唯一识别码) | 生成的唯一 ID, 内部使用 |
name(名称) | 给材质赋予名称,用于调试的目的 |
opacity(不透明度) | 定义物体的透明度,与 transparent 一起使用,范围 0~1 |
transparent(是否透明) | true: 使用指定的不透明度的渲染物体,false: 物体不透明只是着色更加明亮,若使用 alpha 通道的纹理,设置为 true |
overdraw(过度描绘) | THREE. CanvasRender 时多边形会被渲染得稍微大一点,设 true |
visible(是否可见) | 材质是否可见,false 场景中不见该物体 |
side(侧面) | 几何体的哪一面应用材质,默认 THREE. FrontSide(前面,外侧), THREE. BackSide(背面,内侧), THREE. DoubleSide(双侧) |
needsUpdate(是否更新) | true: 更新材质属性 |
混合属性
名称 | 描述 |
---|---|
blending(融合) | 物体上材质与背景如何融合,一般融合模式 THREE. NormalBlending,只显示材质上层 |
blendsrc(融合源) | 自定义融合模式,物体(源),背景(目标),默认 THREE. SrcAlphaFactor,使用 alpha 透明度通道融合 |
blenddst(融合目标) | 默认 THREE. OneMinusSrcAlphaFactor, 也是用透明度融合,值 1 |
blendequation(融合公式) | 默认相加 AddEquation |
高级属性
名称 | 描述 |
---|---|
depthTest | 可打开 GL_DEPTH_TEST 参数,控制是否使用像素深度来计算心像素值 |
depthWrite | 内部属性,用来决定材质是否影响 WebGL 深度缓存,二维贴图时设 false |
polygonOffset, polygonOffsetFactor, polygonOffsetUnits | 控制 WebGL 的 POLYGON_OFFSET_FILL 特性 |
alphatest | 范围 0~1,某个像素小于该值则不显示,移除一些与透明度相关的毛边 |
MeshBaseMaterial
var meshMaterial = new THREE.MeshBasicMaterial({
color: 0x7777ff
});
var meshMaterial = new MeshBasicMaterial();
material.color = new THREE.Color(0xff0000);
名称 | 描述 |
---|---|
color(颜色) | 设置材质的颜色 |
wireframe(线框) | 将材质渲染成线框 |
wireframeLinewidth(线框线宽) | 线框中线的宽度 |
wireframeLinecap(线框线段端点) | 可选 butt 平, round 圆, square 方,默认 round,WebGLRenderer 不支持 |
wireframeLinejoin(线框线段连接点) | 同上 |
shading(着色) | 可选 THREE. SmoothShading(默认), THREE. NoShading, THREE. FlatShading |
vertexColors(顶点颜色) | 默认 THREE. NoColors, 设置后采用 THREE. Geometry 对象的 colors 属性 CanvasRenderer 不起作用 |
fog(雾化) | 是否受全局雾化效果影响 |
THREE. MeshDepthMaterial
名称 | 描述 |
---|---|
wireframe(线框) | 是否显示线框 |
wireframeLinewidth(线框线宽) | 线框中线的宽度 |
联合材质
var cubeMaterial = new THREE.MeshDepthMaterial();
var colorMaterial = new THREE.MeshBasicMaterial({
color: controls.color,
transparent: true, //
blending: THREE.MultiplyBlending, //混合模式,与背景相互作用
});
var cube = new THREE.SceneUtils.createMultiMaterialObject(cubeGeometry, [
colorMaterial,
cubeMaterial,
]);
cube.children[1].scale.set(0.99, 0.99, 0.99); //避免画面闪烁
THREE. MeshNormalMaterial
使用 THREE. ArrowHelper 添加法向量
for (var f = 0, fl = sphere.geometry.faces.length; f < fl; f++) {
var face = sphere.geometry.faces[f];
var centroid = new THREE.Vector3(0, 0, 0);
centroid.add(sphere.geometry.vertices[face.a]);
centroid.add(sphere.geometry.vertices[face.b]);
centroid.add(sphere.geometry.vertices[face.c]);
centroid.divideScalar(3);
var arrow = new THREE.ArrowHelper(face.normal, centroid, 2, 0x3333ff, 0.5, 0.5);
sphere.add(arrow);
}
名称 | 描述 |
---|---|
wireframe(线框) | 是否显示线框 |
wireframeLinewidth(线框线宽) | 线框中线的宽度 |
shading | 设置着色方法,THREE. FlatShading 平面着色, THREE. SmoothShadding 平滑着色 |
THREE. MeshFaceMaterial
材质容器,允许集合体的每个面指定不同的材质
var mats = [];
mats.push(new THREE.MeshBasicMaterial({
color: 0x009e60
}));
mats.push(new THREE.MeshBasicMaterial({
color: 0x009e60
}));
mats.push(new THREE.MeshBasicMaterial({
color: 0x0051ba
}));
mats.push(new THREE.MeshBasicMaterial({
color: 0x0051ba
}));
mats.push(new THREE.MeshBasicMaterial({
color: 0xffd500
}));
mats.push(new THREE.MeshBasicMaterial({
color: 0xffd500
}));
mats.push(new THREE.MeshBasicMaterial({
color: 0xff5800
}));
mats.push(new THREE.MeshBasicMaterial({
color: 0xff5800
}));
mats.push(new THREE.MeshBasicMaterial({
color: 0xc41e3a
}));
mats.push(new THREE.MeshBasicMaterial({
color: 0xc41e3a
}));
mats.push(new THREE.MeshBasicMaterial({
color: 0xffffff
}));
mats.push(new THREE.MeshBasicMaterial({
color: 0xffffff
}));
var faceMaterial = new THREE.MeshFaceMaterial(mats);
//魔方
for (var x = 0; x < 3; x++) {
for (var y = 0; y < 3; y++) {
for (var z = 0; z < 3; z++) {
var cubeGeom = new THREE.BoxGeometry(2.9, 2.9, 2.9);
var cube = new THREE.Mesh(cubeGeom, faceMaterial);
cube.position.set(x * 3 - 3, y * 3, z * 3 - 3);
group.add(cube);
}
}
}
THREE. MeshPhongMaterial
创建光亮材质,属性与暗淡材质 THREE. MeshLambertMaterial 基本属性一样
名称 | 描述 |
---|---|
ambient | 环境色,颜色与环境色相乘,默认白色 |
emissive | 材质发射的颜色,默认黑色,不收其他光照影响的颜色 |
specular | 指定材质光亮程度及高光部分的颜色,设为与color相同颜色,类似金属材质,设为灰色grey则更像塑料 |
shininess | 镜面高光部分的亮度,默认值30 |
metal | true金属效果,效果微弱 |
wrapAround | true启用办lambert光照技术,光下降更微妙,网格粗糙黑暗地区莹阴影柔和且分布更加均匀 |
wrapRGB | true可使用THREE. Vector3控制光下降的速度 |
THREE. ShaderMaterial 创建自己的着色器
着色器可讲Three.js中的JavaScript网格转换为屏幕上的像素,可指定对象如何渲染,如何覆盖或修改Three.js库中的默认值
名称 | 描述 |
---|---|
wireframe | 是否显示线框 |
wireframeLinewidth | 线框中线的宽度 |
shading | 设置着色方法,THREE. FlatShading 平面着色, THREE. SmoothShadding 平滑着色 |
vertexColors | 给每个顶点定义不同的颜色,对CanvasRenderer不起作用,对WebGLRenderer起作用 |
fog | 是否受全局无话效果影响 |
名称 | 描述 |
---|---|
fragmentShader | 定义的每个传入像素的颜色(必传) |
vertexShader | 允许你修改传入的定点位置(必传) |
uniforms | 可想你的着色器发信息,同样的信息会发送给每一个顶点和片段 |
defines | 转换成#define代码片段,这些片段可以设置着着色程序里的额外全局变量 |
attributes | 可修改每个顶点和片段,用来传递每个位置数据和法向量相关的数据 |
lights | 定义光照数据是否传递给着色器,默认false |
vertexShader:它会在几何体的每个顶点上执行,可用这个着色器改变顶点的位置来对集合体进行变换
fragmentShader: 它会在集合体的每一个片段上执行,在VertexShader里,会返回这个特定片段应该显示的颜色
<script id="vertex-shader" type="x-shader/x-vertex">
uniform float time;
varying vec2 vUv;
void main()
{
vec3 posChanged = position;
posChanged.x = posChanged.x*(abs(sin(time*1.0)));
posChanged.y = posChanged.y*(abs(cos(time*1.0)));
posChanged.z = posChanged.z*(abs(sin(time*1.0)));
//gl_Position = projectionMatrix * modelViewMatrix * vec4(position*(abs(sin(time)/2.0)+0.5),1.0);
gl_Position = projectionMatrix * modelViewMatrix * vec4(posChanged,1.0);
}
</script>
function createMaterial(vertexShader, fragmentShader) {
var vertShader = document.getElementById(vertexShader).innerHTML;
var fragShader = document.getElementById(fragmentShader).innerHTML;
var attributes = {
};
var uniforms = {
time: {
type: 'f',
value: 0.2
},
scale: {
type: 'f',
value: 0.2
},
alpha: {
type: 'f',
value: 0.6
},
resolution: {
type: "v2",
value: new THREE.Vector2()
}
};
uniforms.resolution.value.x = window.innerWidth;
uniforms.resolution.value.y = window.innerHeight;
var meshMaterial = new THREE.ShaderMaterial({
uniforms: uniforms,
attributes: attributes,
vertexShader: vertShader,
fragmentShader: fragShader,
transparent: true
});
return meshMaterial;
}
var cubeGeometry = new THREE.BoxGeometry(20, 20, 20);
var meshMaterial1 = createMaterial("vertex-shader", "fragment-shader-1");
var meshMaterial2 = createMaterial("vertex-shader", "fragment-shader-2");
var meshMaterial3 = createMaterial("vertex-shader", "fragment-shader-3");
var meshMaterial4 = createMaterial("vertex-shader", "fragment-shader-4");
var meshMaterial5 = createMaterial("vertex-shader", "fragment-shader-5");
var meshMaterial6 = createMaterial("vertex-shader", "fragment-shader-6");
var material = new THREE.MeshFaceMaterial(
[meshMaterial1,
meshMaterial2,
meshMaterial3,
meshMaterial4,
meshMaterial5,
meshMaterial6
]);
var cube = new THREE.Mesh(cubeGeometry, material);
THREE. LineBaseMaterial
用于线段的基础材质
名称 | 描述 |
---|---|
color | 线的颜色,指定vertexColors该属性会被忽略 |
linewidth | 线的宽度 |
linecap | 线段端点,可选只butt(平),round(圆),square(方),默认round |
linejoin | 线段连接,可选只butt(平),round(圆),square(方),默认round |
vertexColor | 每个顶点指定一种颜色 |
fog | 当前材质是否受全局无话效果影响 |
var points = gosper(4, 60); //gosper曲线
var lines = new THREE.Geometry();
var colors = [];
var i = 0;
points.forEach(function(e) {
lines.vertices.push(new THREE.Vector3(e.x, e.z, e.y));
colors[i] = new THREE.Color(0xffffff);
colors[i].setHSL(e.x / 100 + 0.5, (e.y * 20) / 300, 0.8);
i++;
});
lines.colors = colors;
var material = new THREE.LineBasicMaterial({
opacity: 1.0,
linewidth: 1,
vertexColors: THREE.VertexColors
});
var line = new THREE.Line(lines, material);
THREE. LineDashMaterial
属性与THREE. LineBaseMaterial一样,可指定虚线与空白间隙的长度来创建出虚线效果
名称 | 描述 |
---|---|
scale | 放缩dashSize和gapSize |
dashSize | 虚线长度 |
gapSize | 虚线间隔宽度 |
lines.computeLineDistances();
var material = new THREE.LineDashedMaterial({
vertexColors: true,
color: 0xffffff,
dashSize: 2,
gapSize: 2,
scale: 0.1
});