import * as THREE from 'three';
import { OrbitControls } from "three/examples/jsm/controls/OrbitControls";
import { RectAreaLightHelper } from "three/examples/jsm/helpers/RectAreaLightHelper";
/**
* 3d Material 材质
* https://threejs.org/docs/index.html#api/zh/materials/LineBasicMaterial
*/
export class ThreeDoc7Material {
constructor(canvasId) {
this.work(canvasId);
}
work(canvasId) {
// 创建 3d 场景
const scene = new THREE.Scene();
scene.background = new THREE.Color(0x9e9e9e);
const renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
// 最后一步很重要,我们将renderer(渲染器)的dom元素(renderer.domElement)添加到我们的HTML文档中。这就是渲染器用来显示场景给我们看的<canvas>元素。
document.body.appendChild(renderer.domElement);
// AxesHelper 3个坐标轴的对象.
this.addAxesHelper(scene);
// 添加几何体
const geometry = new THREE.BoxGeometry(1, 1, 1);
let material;
// 基础线条材质(LineBasicMaterial) - 不受光照影响?
material = this.getLineBasicMaterial();
// 虚线材质(LineDashedMaterial) - 不受光照影响?
material = this.getLineDashedMaterial();
// 基础网格材质(MeshBasicMaterial) - 这种材质不受光照的影响。
material = this.getMeshBasicMaterial();
// 深度网格材质(MeshDepthMaterial)
material = this.getMeshDepthMaterial();
// MeshDistanceMaterial
// material = this.getMeshDistanceMaterial();
// Lambert网格材质(MeshLambertMaterial) - 一种非光泽表面的材质,没有镜面高光。
material = this.getMeshLambertMaterial();
// MeshMatcapMaterial
material = this.getMeshMatcapMaterial();
// 法线网格材质(MeshNormalMaterial)
material = this.getMeshNormalMaterial();
// Phong网格材质(MeshPhongMaterial)
material = this.getMeshPhongMaterial();
// 物理网格材质(MeshPhysicalMaterial)
material = this.getMeshPhysicalMaterial();
// 标准网格材质(MeshStandardMaterial)
material = this.getMeshStandardMaterial();
// MeshToonMaterial
material = this.getMeshToonMaterial();
// 点材质(PointsMaterial)
this.getPointsMaterial(scene);
// 原始着色器材质(RawShaderMaterial) - 需要额外 script 内容,参考 three.js webgl_buffergeometry_rawshader.html
// material = this.getRawShaderMaterial(scene);
// 着色器材质(ShaderMaterial) - 类似上一个
// 阴影材质(ShadowMaterial)
this.getShadowMaterial(scene);
// 点精灵材质(SpriteMaterial)
this.getSpriteMaterial(scene);
// 创建物体
const dodecahedron = new THREE.Mesh(geometry, material);
scene.add(dodecahedron);
// 包围盒辅助线框对象
// const box = new THREE.BoxHelper(dodecahedron, 0xffff00);
// scene.add(box);
// 半球光(HemisphereLight)
this.addHemisphereLight(scene);
// 平面光光源(RectAreaLight)
this.addRectAreaLight(scene);
const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
// 设置相机位置
camera.position.x = 10;
camera.position.y = 10;
camera.position.z = 10;
// camera.lookAt(0, 0, 0);
// 添加控制器
let orb = new OrbitControls(camera, document.body);
orb.addEventListener('change', function () {
renderer.render(scene, camera);
});
renderer.render(scene, camera);
}
/**
* AxesHelper
* 用于简单模拟3个坐标轴的对象.
* 红色代表 X 轴. 绿色代表 Y 轴. 蓝色代表 Z 轴.
* AxesHelper( size : Number )
* size -- (可选的) 表示代表轴的线段长度. 默认为 1.
*/
addAxesHelper(scene) {
const axesHelper = new THREE.AxesHelper(12);
scene.add(axesHelper);
}
/**
* 半球光(HemisphereLight) - 喜欢这个光
* 光源直接放置于场景之上,光照颜色从天空光线颜色渐变到地面光线颜色。
* 半球光不能投射阴影。
*
* HemisphereLight( skyColor : Integer, groundColor : Integer, intensity : Float )
* skyColor - (可选参数) 天空中发出光线的颜色。 缺省值 0xffffff。
* groundColor - (可选参数) 地面发出光线的颜色。 缺省值 0xffffff。
* intensity - (可选参数) 光照强度。 缺省值 1。
*/
addHemisphereLight(scene) {
const light = new THREE.HemisphereLight(0xffffbb, 0x080820, 100);
scene.add(light);
light.position.set(0, -5, 0);
const helper = new THREE.HemisphereLightHelper(light, 3);
scene.add(helper);
}
/**
* 平面光光源(RectAreaLight) - 这个光源也不错!
* 平面光光源从一个矩形平面上均匀地发射光线。这种光源可以用来模拟像明亮的窗户或者条状灯光光源。
* 注意事项:
* 不支持阴影。
* 只支持 MeshStandardMaterial 和 MeshPhysicalMaterial 两种材质。
* 你必须在你的场景中加入 RectAreaLightUniformsLib ,并调用init()。
*
* RectAreaLight( color : Integer, intensity : Float, width : Float, height : Float )
* color - (可选参数) 十六进制数字表示的光照颜色。缺省值为 0xffffff (白色)
* intensity - (可选参数) 光源强度/亮度 。缺省值为 1。
* width - (可选参数) 光源宽度。缺省值为 10。
* height - (可选参数) 光源高度。缺省值为 10。
*/
addRectAreaLight(scene) {
const width = 20;
const height = 10;
const intensity = 100;
const rectLight = new THREE.RectAreaLight(0xffffff, intensity, width, height);
rectLight.position.set(5, 5, 0);
rectLight.lookAt(0, 0, 0);
scene.add(rectLight);
let rectLightHelper = new RectAreaLightHelper(rectLight);
scene.add(rectLightHelper);
}
/**
* 基础线条材质(LineBasicMaterial) - 不受光照影响?
* LineBasicMaterial( parameters : Object )
* parameters - (可选)用于定义材质外观的对象,具有一个或多个属性。材质的任何属性都可以从此处传入(包括从Material继承的任何属性)。
* 属性color例外,其可以作为十六进制字符串传递,默认情况下为 0xffffff(白色),内部调用Color.set(color)。
* .color : Color
* 材质的颜色(Color),默认值为白色 (0xffffff)。
* .fog : Boolean
* 材质是否受雾影响。默认为true。
* .linewidth : Float
* 控制线宽。默认值为 1。
* 由于OpenGL Core Profile与 大多数平台上WebGL渲染器的限制,无论如何设置该值,线宽始终为1。
* .linecap : String
* 定义线两端的样式。可选值为 'butt', 'round' 和 'square'。默认值为 'round'。
* 该属性对应2D Canvas lineCap属性, 并且会被WebGL渲染器忽略。
* .linejoin : String
* 定义线连接节点的样式。可选值为 'round', 'bevel' 和 'miter'。默认值为 'round'。
*/
getLineBasicMaterial() {
return new THREE.LineBasicMaterial({
color: 0x00ffff,
linewidth: 1,
linecap: 'round', //ignored by WebGLRenderer
linejoin: 'round' //ignored by WebGLRenderer
});
}
/**
* 虚线材质(LineDashedMaterial) - 不受光照影响?
* LineDashedMaterial( parameters : Object )
* parameters - (可选)用于定义材质外观的对象,具有一个或多个属性。材质的任何属性都可以从此处传入
* (包括从LineBasicMaterial继承的任何属性)。
* .dashSize : number
* 虚线的大小,是指破折号和间隙之和。默认值为 3。
* .gapSize : number
* 间隙的大小,默认值为 1。
* .isLineDashedMaterial : Boolean
* Read-only flag to check if a given object is of type LineDashedMaterial.
* .scale : number
* 线条中虚线部分的占比。默认值为 1。
*/
getLineDashedMaterial() {
return new THREE.LineDashedMaterial({
color: 0x00ffff,
linewidth: 1,
scale: 1,
dashSize: 3,
gapSize: 1,
});
}
/**
* 基础网格材质(MeshBasicMaterial)
* 一个以简单着色(平面或线框)方式来绘制几何体的材质。
* 这种材质不受光照的影响。
* MeshBasicMaterial( parameters : Object )
* parameters - (可选)用于定义材质外观的对象,具有一个或多个属性。材质的任何属性都可以从此处传入(包括从Material继承的任何属性)。
* 属性color例外,其可以作为十六进制字符串传递,默认情况下为 0xffffff(白色),内部调用Color.set(color)。
* .alphaMap : Texture
* alpha贴图是一张灰度纹理,用于控制整个表面的不透明度。(黑色:完全透明;白色:完全不透明)。 默认值为null。
* 仅使用纹理的颜色,忽略alpha通道(如果存在)。 对于RGB和RGBA纹理,WebGL渲染器在采样此纹理时将使用绿色通道, 因为在DXT压缩和未压缩RGB 565格式中为绿色提供了额外的精度。 Luminance-only以及luminance/alpha纹理也仍然有效。
* .aoMap : Texture
* 该纹理的红色通道用作环境遮挡贴图。默认值为null。aoMap需要第二组UV。
* .aoMapIntensity : Float
* 环境遮挡效果的强度。默认值为1。零是不遮挡效果。
* .color : Color
* 材质的颜色(Color),默认值为白色 (0xffffff)。
* .combine : Integer
* 如何将表面颜色的结果与环境贴图(如果有)结合起来。
* 选项为THREE.MultiplyOperation(默认值),THREE.MixOperation, THREE.AddOperation。如果选择多个,则使用.reflectivity在两种颜色之间进行混合。
* .envMap : Texture
* 环境贴图。默认值为null。
* .fog : Boolean
* 材质是否受雾影响。默认为true。
* .lightMap : Texture
* 光照贴图。默认值为null。lightMap需要第二组UV。
* .lightMapIntensity : Float
* 烘焙光的强度。默认值为1。
* .map : Texture
* 颜色贴图。默认为null。
* .reflectivity : Float
* 环境贴图对表面的影响程度; 见.combine。默认值为1,有效范围介于0(无反射)和1(完全反射)之间。
* .refractionRatio : Float
* 空气的折射率(IOR)(约为1)除以材质的折射率。它与环境映射模式THREE.CubeRefractionMapping 和THREE.EquirectangularRefractionMapping一起使用。 The index of refraction (IOR) of air (approximately 1) divided by the index of refraction of the material. It is used with environment mapping mode THREE.CubeRefractionMapping. 折射率不应超过1。默认值为0.98。
* .specularMap : Texture
* 材质使用的高光贴图。默认值为null。
* .wireframe : Boolean
* 将几何体渲染为线框。默认值为false(即渲染为平面多边形)。
* .wireframeLinecap : String
* 定义线两端的外观。可选值为 'butt','round' 和 'square'。默认为'round'。
* 该属性对应2D Canvas lineJoin属性, 并且会被WebGL渲染器忽略。
* .wireframeLinejoin : String
* 定义线连接节点的样式。可选值为 'round', 'bevel' 和 'miter'。默认值为 'round'。
* 该属性对应2D Canvas lineJoin属性, 并且会被WebGL渲染器忽略。
* .wireframeLinewidth : Float
* 控制线框宽度。默认值为1。
*/
getMeshBasicMaterial() {
return new THREE.MeshBasicMaterial({
color: 0x00ffff,
});
}
/**
* 深度网格材质(MeshDepthMaterial)
* 一种按深度绘制几何体的材质。深度基于相机远近平面。白色最近,黑色最远。
* MeshDepthMaterial( parameters : Object )
* parameters - (可选)用于定义材质外观的对象,具有一个或多个属性。 材质的任何属性都可以从此处传入(包括从Material继承的任何属性)。
* .alphaMap : Texture
* alpha贴图是一张灰度纹理,用于控制整个表面的不透明度。(黑色:完全透明;白色:完全不透明)。 默认值为null。
* 仅使用纹理的颜色,忽略alpha通道(如果存在)。 对于RGB和RGBA纹理,WebGL渲染器在采样此纹理时将使用绿色通道, 因为在DXT压缩和未压缩RGB 565格式中为绿色提供了额外的精度。 Luminance-only以及luminance/alpha纹理也仍然有效。
* .depthPacking : Constant
* depth packing的编码。默认为BasicDepthPacking。
* .displacementMap : Texture
* 位移贴图会影响网格顶点的位置,与仅影响材质的光照和阴影的其他贴图不同,移位的顶点可以投射阴影,阻挡其他对象,以及充当真实的几何体。 位移纹理是指:网格的所有顶点被映射为图像中每个像素的值(白色是最高的),并且被重定位。
* .displacementScale : Float
* 位移贴图对网格的影响程度(黑色是无位移,白色是最大位移)。如果没有设置位移贴图,则不会应用此值。默认值为1。
* .displacementBias : Float
* 位移贴图在网格顶点上的偏移量。如果没有设置位移贴图,则不会应用此值。默认值为0。
* .map : Texture
* 颜色贴图。默认为null。
* .wireframe : Boolean
* 将几何体渲染为线框。默认值为false(即渲染为平滑着色)。
* .wireframeLinewidth : Float
* 控制线框宽度。默认值为1。
*/
getMeshDepthMaterial() {
return new THREE.MeshDepthMaterial({
color: 0xffffff,
});
}
/**
* Lambert网格材质(MeshLambertMaterial)
* 一种非光泽表面的材质,没有镜面高光。
*
* 该材质使用基于非物理的Lambertian模型来计算反射率。 这可以很好地模拟一些表面(例如未经处理的木材或石材),但不能模拟具有镜面高光的光泽表面(例如涂漆木材)。
* MeshLambertMaterial( parameters : Object )
* parameters - (可选)用于定义材质外观的对象,具有一个或多个属性。 材质的任何属性都可以从此处传入(包括从Material继承的任何属性)。
*
* 属性color例外,其可以作为十六进制字符串传递,默认情况下为 0xffffff(白色),内部调用Color.set(color)。
*/
getMeshLambertMaterial() {
return new THREE.MeshDepthMaterial({
color: 0x00ffff,
});
}
/**
* MeshMatcapMaterial
* MeshMatcapMaterial 由一个材质捕捉(MatCap,或光照球(Lit Sphere))纹理所定义,其编码了材质的颜色与明暗。
* MeshMatcapMaterial( parameters : Object )
* parameters - (可选)用于定义材质外观的对象,具有一个或多个属性。 材质的任何属性都可以从此处传入(包括从Material继承的任何属性)。
*
* 属性color例外,其可以作为十六进制字符串传递,默认情况下为 0xffffff(白色),内部调用Color.set(color)。
*/
getMeshMatcapMaterial() {
return new THREE.MeshDepthMaterial({
color: 0x00ffff,
});
}
/**
* 法线网格材质(MeshNormalMaterial)
* 一种把法向量映射到RGB颜色的材质。
* MeshNormalMaterial( parameters : Object )
* parameters - (可选)用于定义材质外观的对象,具有一个或多个属性。材质的任何属性都可以从此处传入(包括从Material继承的任何属性)。
*/
getMeshNormalMaterial() {
return new THREE.MeshNormalMaterial({});
}
/**
* Phong网格材质(MeshPhongMaterial)
* 一种用于具有镜面高光的光泽表面的材质。
* MeshPhongMaterial( parameters : Object )
* parameters - (可选)用于定义材质外观的对象,具有一个或多个属性。 材质的任何属性都可以从此处传入(包括从Material继承的任何属性)。
*
* 属性color例外,其可以作为十六进制字符串传递,默认情况下为 0xffffff(白色),内部调用Color.set(color)。
*/
getMeshPhongMaterial() {
return new THREE.MeshPhongMaterial({
color: 0x00ffff,
});
}
/**
* 物理网格材质(MeshPhysicalMaterial)
* MeshStandardMaterial的扩展,提供了更高级的基于物理的渲染属性:
*
* Clearcoat: 有些类似于车漆,碳纤,被水打湿的表面的材质需要在面上再增加一个透明的,具有一定反光特性的面。而且这个面说不定有一定的起伏与粗糙度。Clearcoat可以在不需要重新创建一个透明的面的情况下做到类似的效果。
* 基于物理的透明度:.opacity属性有一些限制:在透明度比较高的时候,反射也随之减少。使用基于物理的透光性.transmission属性可以让一些很薄的透明表面,例如玻璃,变得更真实一些。
* 高级光线反射: 为非金属材质提供了更多更灵活的光线反射。
* MeshPhysicalMaterial( parameters : Object )
* parameters - (可选)用于定义材质外观的对象,具有一个或多个属性。 材质的任何属性都可以从此处传入(包括从Material和MeshStandardMaterial继承的任何属性)
*
* 属性color例外,其可以作为十六进制字符串传递,默认情况下为 0xffffff(白色),内部调用Color.set(color)。
*/
getMeshPhysicalMaterial() {
return new THREE.MeshPhysicalMaterial({
color: 0x00ffff,
});
}
/**
* 标准网格材质(MeshStandardMaterial)
* 一种基于物理的标准材质,使用Metallic-Roughness工作流程。
*
* 基于物理的渲染(PBR)最近已成为许多3D应用程序的标准,例如Unity, Unreal和 3D Studio Max。
* MeshStandardMaterial( parameters : Object )
* parameters - (可选)用于定义材质外观的对象,具有一个或多个属性。 材质的任何属性都可以从此处传入(包括从Material继承的任何属性)。
*
* 属性color例外,其可以作为十六进制字符串传递,默认情况下为 0xffffff(白色),内部调用Color.set(color)。
*/
getMeshStandardMaterial() {
return new THREE.MeshPhysicalMaterial({
color: 0x049EF4,
});
}
/**
* MeshToonMaterial
* A material implementing toon shading.
* MeshToonMaterial( parameters : Object )
* parameters - (optional) an object with one or more properties defining the material's appearance. Any property
* of the material (including any property inherited from Material) can be passed in here.
*/
getMeshToonMaterial() {
return new THREE.MeshToonMaterial({
color: 0x00ffff,
});
}
/**
* 点材质(PointsMaterial)
* Points使用的默认材质。
* PointsMaterial( parameters : Object )
* parameters - (可选)用于定义材质外观的对象,具有一个或多个属性。 材质的任何属性都可以从此处传入(包括从Material继承的任何属性)。
*
* 属性color例外,其可以作为十六进制字符串传递,默认情况下为 0xffffff(白色),内部调用Color.set(color)。
*/
getPointsMaterial(scene) {
const vertices = [];
for (let i = 0; i < 10000; i++) {
const x = THREE.MathUtils.randFloatSpread(2000);
const y = THREE.MathUtils.randFloatSpread(2000);
const z = THREE.MathUtils.randFloatSpread(2000);
vertices.push(x, y, z);
}
const geometry = new THREE.BufferGeometry();
geometry.setAttribute('position', new THREE.Float32BufferAttribute(vertices, 3));
const material = new THREE.PointsMaterial({ color: 0x000000 });
const points = new THREE.Points(geometry, material);
scene.add(points);
}
/**
* 原始着色器材质(RawShaderMaterial)
* 此类的工作方式与ShaderMaterial类似,不同之处在于内置的uniforms和attributes的定义不会自动添加到GLSL shader代码中。
* RawShaderMaterial( parameters : Object )
* parameters - (可选)用于定义材质外观的对象,具有一个或多个属性。 材质的任何属性都可以从此处传入(包括从Material 和 ShaderMaterial继承的任何属性)。
*/
getRawShaderMaterial() {
return new THREE.RawShaderMaterial({
uniforms: {
time: { value: 1.0 }
},
vertexShader: document.getElementById('vertexShader').textContent,
fragmentShader: document.getElementById('fragmentShader').textContent,
});
}
/**
* 阴影材质(ShadowMaterial)
* 此材质可以接收阴影,但在其他方面完全透明。
* ShadowMaterial( parameters : Object )
* parameters - (可选)用于定义材质外观的对象,具有一个或多个属性。 材质的任何属性都可以从此处传入(包括从Material继承的任何属性)。
*/
getShadowMaterial(scene) {
const geometry = new THREE.PlaneGeometry( 2000, 2000 );
geometry.rotateX( - Math.PI / 2 );
const material = new THREE.ShadowMaterial();
material.opacity = 0.2;
const plane = new THREE.Mesh( geometry, material );
plane.receiveShadow = true;
scene.add( plane );
}
/**
* 点精灵材质(SpriteMaterial)
* 一种使用Sprite的材质。
* SpriteMaterial( parameters : Object )
* parameters - (可选)用于定义材质外观的对象,具有一个或多个属性。 材质的任何属性都可以从此处传入(包括从Material 和 ShaderMaterial继承的任何属性)。
*
* 属性color例外,其可以作为十六进制字符串传递,默认情况下为 0xffffff(白色), 内部调用Color.set(color)。 SpriteMaterials不会被Material.clippingPlanes裁剪。
*/
getSpriteMaterial(scene) {
const map = new THREE.TextureLoader().load( 'assets/111.png' );
const material = new THREE.SpriteMaterial( { map: map, color: 0xffffff } );
const sprite = new THREE.Sprite( material );
sprite.scale.set(200, 200, 0);
scene.add( sprite );
}
}