// Project setup
npm install
// Compiles and hot-reloads for development
npm run dev
// Compiles and minifies for production
npm run build
场景Scene、相机Camera、渲染器Renderer
// 创建3D场景对象Scene
const scene = new THREE.Scene();
// 实例化一个透视投影相机对象,模拟人眼
const camera = new THREE.PerspectiveCamera(30, 1, 1, 3000); //视角(范围),画布宽高比,近裁截面,远裁截面
camera.position.set(200, 200, 200); //相机位置
camera.lookAt(0, 0, 0); //相机观察目标
// 创建渲染器对象
const renderer = new THREE.WebGLRenderer();
renderer.setSize(width, height); //设置three.js渲染区域的尺寸(像素px)
renderer.render(scene, camera); //执行渲染操作
document.getElementById('xxId').appendChild(renderer.domElement); //画布插入到任意HTML元素中
const pointLight = new THREE.PointLight(0xffffff); // 白光
pointLight.intensity = 1.0;//光照强度
pointLight.decay = 0.0;//设置光源不随距离衰减
pointLight.position.set(400, 200, 300); //光照位置
光源辅助观察,例xxxxLightHelper
通过相机控件OrbitControls实现旋转缩放预览效果。旋转:拖动鼠标左键,缩放:滚动鼠标中键,平移:拖动鼠标右键
// 引入轨道控制器扩展库OrbitControls.js
import { OrbitControls } from 'three/addons/controls/OrbitControls.js';
const controls = new OrbitControls(camera, renderer.domElement); // 设置相机控件轨道控制器
// 如果OrbitControls改变了相机参数,重新调用渲染器渲染三维场景
controls.addEventListener('change', function () {
renderer.render(scene, camera);
});
threejs可以借助HTML5的API请求动画帧window.requestAnimationFrame实现动画渲染
function render() {
renderer.render(scene, camera); //执行渲染操作
requestAnimationFrame(render);//请求再次执行函数render,无限循环
}
设置了渲染循环,相机控件OrbitControls就不用再通过事件change执行renderer.render(scene, camera);因为渲染循环一直在执行renderer.render(scene, camera);。
// 轨道控制器
const controls = new OrbitControls(camera, renderer.domElement);
controls.update();
// 渲染循环
const render3D = () => {
renderer.render(scene, camera)
requestAnimationFrame(render3D)
}
threejs渲染输出的结果就是一个Cavnas画布,所以可以插入到web页面上任何一个元素中
// onresize 事件会在窗口被调整大小时发生
window.onresize = function () {
// 重置渲染器输出画布canvas尺寸
renderer.setSize(window.innerWidth, window.innerHeight);
// 全屏情况下:设置观察范围长宽比aspect为窗口宽高比
camera.aspect = window.innerWidth / window.innerHeight;
// 渲染器执行render方法的时候会读取相机对象的投影矩阵属性projectionMatrix
// 但是不会每渲染一帧,就通过相机的属性计算投影矩阵(节约计算资源)
// 如果相机的一些属性发生了变化,需要执行updateProjectionMatrix ()方法更新相机的投影矩阵
camera.updateProjectionMatrix();
};
stats.js库可以查看three.js当前的渲染性能,计算three.js的渲染帧率(FPS)。简单说就是three.js每秒钟完成的渲染次数,一般渲染达到每秒钟60次为最佳状态。
//引入性能监视器stats.js
import Stats from 'three/addons/libs/stats.module.js';
const stats = new Stats(); //创建stats对象
document.body.appendChild(stats.domElement); //web页面上输出计算结果
function render() {
stats.update(); // 循环调用方法update(),来刷新时间
renderer.render(scene, camera);
requestAnimationFrame(render);
}
render();
可以通过stats.setMode()方法的参数mode的数值设置首次打开页面,测试结果的显示模式。鼠标单击可以更换为不同的显示模式。
//BoxGeometry:长方体
const geometry = new THREE.BoxGeometry(100, 100, 100);
// SphereGeometry:球体
const geometry = new THREE.SphereGeometry(50);
// CylinderGeometry:圆柱
const geometry = new THREE.CylinderGeometry(50,50,100);
// PlaneGeometry:矩形平面
const geometry = new THREE.PlaneGeometry(100,50);
// CircleGeometry:圆形平面
const geometry = new THREE.CircleGeometry(50);
Three.js的材质默认正面可见,反面不可见
new THREE.MeshBasicMaterial({
// side: THREE.FrontSide, //默认只有正面可见
// side: THREE.BackSide, //设置只有背面可见
side: THREE.DoubleSide, //两面可见
});
1、抗锯齿 antialias
const renderer =new Three.WebGLRenderer({
antialias: true // 默认false,开启抗锯齿图像展示更平滑
})
2、设备像素比 .setPixelRatio()
// 获取你屏幕对应的设备像素比.devicePixelRatio告诉threejs,以免渲染模糊问题
renderer.setPixelRatio(window.devicePixelRatio); // 必写
能够可视化的动态地调整设置的图像参数,便于观察变化。
1、通过.add()增加交互界面,改变obj对应属性值。
// 引入dat.gui.js的一个类GUI
import { GUI } from 'three/addons/libs/lil-gui.module.min.js';
const gui = new GUI(); // 实例化一个gui对象
const obj = {x: 30, y: 60, z: 300};
gui.add(obj, 'x', 0, 100); // 属性值范围(0-100)
gui.add(obj, 'y', 0, 50); // 属性值范围(0-50)
gui.add(obj, 'z', 0, 60);
gui.add(ambient, 'intensity', 0, 2.0); // 设置灯光强度
gui.add(mesh.position, 'x', 0, 180); // 模型位置
gui.add(mesh.position, 'y', [0,10,20,30,40]);
gui.add(mesh.position, 'z', {left: -10,center: 0,right: 10});
2、通过.name('自定义名称'),对属性进行命名
gui.add(ambient, 'intensity', 0, 2.0).name('设置光强度');
3、.step()设置调节步长
gui.add(ambient, 'intensity', 0, 2.0).name('设置光强度').step(0.5)
4、.onChange()属性改变时触发对应事件
gui.add(mesh.position, 'x', 0, 180).onChange(function(value){
console.log('mesh的x坐标:',value)
}
5、.addColor()颜色值改变
gui.addColor(light, 'color').name('设置灯光颜色')
6、.addFolder()分组,方便管理,可套娃
const posFolder = gui.addFolder('坐标')
posFolder.add(mesh.position, 'y', [0,10,20,30,40])
posFolder.add(mesh.position, 'x', 0, 50)
const lightFolder = gui.addFolder('光照')
lightFolder.add(light, 'intensity', 0, 10)
lightFolder.addColor(light, 'color')
lightFolder.close() // 折叠组
posFolder.open() // 打开组
长方体BoxGeometry、球体SphereGeometry等几何体都是基于BufferGeometry (opens new window)类构建的;
BufferGeometry是一个没有任何形状的空几何体,你可以通过定义顶点数据,BufferGeometry展示出任何几何形状。
//创建一个空的几何体对象
const geometry = new THREE.BufferGeometry();
//创建顶点数据,类型化数组
const vertices = new Float32Array([
0, 0, 0, //顶点1坐标
50, 0, 0, //顶点2坐标
0, 100, 0, //顶点3坐标
0, 0, 10, //顶点4坐标
0, 0, 100, //顶点5坐标
50, 0, 10, //顶点6坐标
]);
// 创建属性缓冲区对象。3个为一组,表示一个顶点的xyz坐标
const attribue = new THREE.BufferAttribute(vertices, 3);
// .attributes.position 设置几何体attributes属性的位置属性
geometry.attributes.position = attribue;
点模型Points和网格模型Mesh一样,只是大部分情况都是用Mesh表示物体。点模型Points会把几何体渲染为点,网格模型Mesh会把几何体渲染为面。
// 点渲染模式
const material = new THREE.PointsMaterial({
color: 0xffff00,
size: 10.0 //点对象像素尺寸
});
const points = new THREE.Points(geometry, material); //点模型对象
渲染效果是从第一个点开始到最后一个点,依次连成线。
// 线材质对象
const material = new THREE.LineBasicMaterial({
color: 0xff0000 //线条颜色
});
const line = new THREE.Line(geometry, material); // 创建线模型对象
const line = new THREE.LineLoop(geometry, material); // 闭合线条
const line = new THREE.LineSegments(geometry, material); //非连续的线条
网格模型Mesh其实就一个一个三角形(面)拼接构成。使用网格模型Mesh渲染几何体geometry,就是几何体所有顶点坐标三个为一组,构成一个三角形,多组顶点构成多个三角形,就可以用来模拟表示物体的表面。
眼睛(相机)对着三角形的一个面,如果三个顶点的顺序是逆时针方向,该面视为正面;反之,为反面。
一个矩形平面,可以至少通过两个三角形拼接而成。而且两个三角形有两个顶点的坐标是重合的。
注意三角形的正反面问题:保证矩形平面两个三角形的正面是一样的,也就是从一个方向观察,两个三角形都是逆时针或顺时针。
const vertices = new Float32Array([
0, 0, 0, //顶点1坐标
80, 0, 0, //顶点2坐标
80, 80, 0, //顶点3坐标
0, 0, 0, //顶点4坐标 和顶点1位置相同
80, 80, 0, //顶点5坐标 和顶点3位置相同
0, 80, 0, //顶点6坐标
]);
// Uint16Array类型数组创建顶点索引数据
const indexes = new Uint16Array([
// 下面索引值对应顶点位置数据中的顶点坐标
0, 1, 2, 0, 2, 3,
])
// 索引数据赋值给几何体的index属性
geometry.index = new THREE.BufferAttribute(indexes, 1); //1个为一组
可以用顶点索引index数据构建几何体,也可以不用,threejs默认的大部分几何体都有三角形的顶点索引数据,具体可以通过浏览器控制台打印几何体数据查看。
const geometry = new THREE.PlaneGeometry(100,50); //矩形平面几何体
// const geometry = new THREE.BoxGeometry(50,50,50); //长方体
console.log('几何体',geometry);
console.log('顶点位置数据',geometry.attributes.position);
console.log('顶点索引数据',geometry.index);
线条模式渲染,查看几何体三角形结构
const material = new THREE.MeshLambertMaterial({
color: 0x00ffff,
wireframe:true, // 线条模式渲染mesh对应的三角形数据
});
Three.js很多几何体都提供了细分数相关的参数。例:矩形平面几何体至少需要两个三角形拼接而成。
// 矩形几何体PlaneGeometry的参数3,4表示细分数,默认是1,1
const geometry = new THREE.PlaneGeometry(100,50,1,1);
// 把一个矩形分为2份,每个矩形2个三角形,总共就是4个三角形
const geometry = new THREE.PlaneGeometry(100,50,2,1);
// 把一个矩形分为4份,每个矩形2个三角形,总共就是8个三角形
const geometry = new THREE.PlaneGeometry(100,50,2,2);
对于一个曲面而言,细分数越大,表面越光滑,但是三角形和顶点数量却越多。
几何体三角形数量或者说顶点数量直接影响Three.js的渲染性能,在不影响渲染效果的情况下,一般尽量越少越好。
BufferGeometry的旋转、缩放、平移等方法,本质上就是改变顶点的位置坐标
// 几何体xyz三个方向都放大2倍
geometry.scale(2, 2, 2);
// 几何体旋转、缩放或平移之后,查看几何体顶点位置坐标的变化
console.log('顶点位置数据', geometry.attributes.position);
// 几何体沿着x轴平移50
geometry.translate(50, 0, 0);
// 几何体绕着x轴旋转45度
geometry.rotateX(Math.PI / 4); // Math.PI = 3.1415926
geometry.translate(50, 0, 0);//偏移
// 居中:已经偏移的几何体居中,执行.center(),你可以看到几何体重新与坐标原点重合
geometry.center();
通过纹理贴图加载器TextureLoader的load()方法加载一张图片可以返回一个纹理对象Texture,纹理对象Texture可以作为模型材质颜色贴图.map属性的值。
//纹理贴图加载器TextureLoader, .load()方法加载图像,返回一个纹理对象Texture
const texLoader = new THREE.TextureLoader();
const texture = texLoader.load('./earth.jpg');
const material = new THREE.MeshLambertMaterial({
map: texture, //map表示材质的颜色贴图属性
});
// material.map = texture; // 也可设置贴图
.map颜色贴图和.color属性颜色值会混合
颜色纹理贴图映射到不同的几何体上,映射效果不同。其实和UV坐标相关。
顶点UV坐标的作用是从纹理贴图上提取像素映射到网格模型Mesh的几何体表面上。
const geometry = new THREE.PlaneGeometry(200, 100); //矩形平面
// const geometry = new THREE.BoxGeometry(100, 100, 100); //长方体
// const geometry = new THREE.SphereGeometry(100, 30, 30);//球体
console.log('uv',geometry.attributes.uv); // 查看几何体默认UV坐标
顶点UV坐标geometry.attributes.uv和顶点位置坐标geometry.attributes.position是一一对应的,即position有几个顶点,UV也需要设置几个顶点。
UV顶点坐标你可以根据需要在0~1之间任意设置
/**纹理坐标0~1之间随意定义*/
const uvs = new Float32Array([
0, 0, //图片左下角
1, 0, //图片右下角
1, 1, //图片右上角
0, 1, //图片左上角
]);
// 设置几何体attributes属性的位置normal属性
geometry.attributes.uv = new THREE.BufferAttribute(uvs, 2); //2个为一组,表示一个顶点的纹理坐标
const vertices = new Float32Array([
0,0,0,
10,0,0,
10,10,0,
0,0,0,
10,10,0,
0,10,0
])
const uvs = new Float32Array([
0, 0, //图片左下角
1, 0, //图片右下角
1, 1, //图片右上角
0, 0,
1, 1,
0, 1 //图片左上角
]);
const geometry = new Three.BufferGeometry()
geometry.setAttribute('uv',new Three.BufferAttribute(uvs, 2))
geometry.setAttribute('position',new Three.BufferAttribute(vertices, 3))
// 通过材质的map添加纹理
const material = new Three.MeshBasicMaterial({map: texture, side: Three.DoubleSide})
const mesh = new Three.Mesh(geometry, material)
mesh.position.set(10,10,0)
scene.add(mesh)
通过圆形几何体CircleGeometry创建一个网格模型Mesh,把一张图片作为圆形Mesh材质的颜色贴图,可以把一张方形图片剪裁四角,渲染为圆形效果。
CircleGeometry的UV坐标会对颜色纹理贴图.map进行提取,CircleGeometry的UV坐标默认提取的就是一个圆形轮廓。
使用纹理对象Texture的阵列功能+矩形平面几何体PlaneGeometry实现一个地面瓷砖效果。
设置了阵列,重复渲染纹理才会均匀分布
const geometry = new THREE.PlaneGeometry(2000, 2000);
const texLoader = new THREE.TextureLoader();
const texture = texLoader.load('./瓷砖.jpg');
//设置阵列
texture.wrapS = THREE.RepeatWrapping;
texture.wrapT = THREE.RepeatWrapping;
// 设置uv两个方向纹理重复数量
texture.repeat.set(10, 10)
const material = new THREE.MeshLambertMaterial({
map: texture,
});
const mesh = new THREE.Mesh(geometry, material);
把一个背景透明的.png图像作为平面矩形网格模型Mesh的颜色贴图是一个非常有用的功能,可以对三维场景进行标注。
整体思路:创建一个矩形平面,设置颜色贴图.map,注意选择背景透明的.png图像作为颜色贴图,同时材质设置transparent: true,这样png图片背景完全透明的部分不显示。
const geometry = new THREE.PlaneGeometry(60, 60); //默认在XOY平面上
const textureLoader = new THREE.TextureLoader();
const material = new THREE.MeshBasicMaterial({
map: textureLoader.load('./left.png'),
transparent: true, //开启透明
});
const mesh = new THREE.Mesh(geometry, material);
mesh.rotateX(-Math.PI / 2);
纹理对象Texture的.offset的功能是偏移贴图在Mesh上位置,本质上相当于修改了UV顶点坐标。
function render() {
texture.offset.x +=0.01; //设置纹理动画:偏移量根据纹理和动画需要,设置合适的值
// mesh.position.x -= 0.2
renderer.render(scene, camera);
requestAnimationFrame(render);
}
3D美术常用的三维建模软件,比如Blender、3dmax、C4D、maya等等
分工和流程:
GLTF格式是新2015发布的三维模型格式,随着物联网、WebGL、5G的进一步发展,会有越来越多的互联网项目Web端引入3D元素,你可以把GLTF格式的三维模型理解为.jpg、.png格式的图片一样是标配。在2017年又发布了GLTF2.0的版本。
GLTF文件通过JSON的键值对方式来表示模型信息。.gltf格式文件几乎可以包含所有的三维模型相关信息的数据,比如模型层级关系、PBR材质、纹理贴图、骨骼动画、变形动画...
不仅three.js,其它的WebGL三维引擎cesium、babylonjs都对gltf格式有良好的的支持。
glTF文件会关联一个或多个.bin文件,.bin文件以二进制形式存储了模型的顶点数据等信息。
.glb是gltf格式的二进制文件。.gltf模型和贴图信息.bin全部合成得到一个.glb文件。.glb文件相对.gltf文件体积更小,网络传输自然更快。
在实现基础场景、光源、渲染器、相机后,三步:
// 引入gltf模型加载库GLTFLoader.js
import { GLTFLoader } from 'three/addons/loaders/GLTFLoader.js';
// 创建GLTF加载器对象
const loader = new GLTFLoader();
// gltf对象包含模型、动画等信息,gltf.scene属性包含的是模型信息
loader.load( 'gltf模型.gltf', function ( gltf ) {
scene.add( gltf.scene ); // 返回的场景对象gltf.scene插入到threejs场景中
})
一般通过三维建模软件可以轻松测量模型尺寸,用三维建模软件blender打开gltf模型,测量尺寸。
three.js的世界没有任何单位,只有数字大小的运算。obj、gltf格式的模型信息只有尺寸,并不含单位信息。
不过实际项目开发的时候会约定单位,如果单位不统一,可以用.scale缩放
three.js加载gltf模型的时候,可能会渲染结果颜色偏差,对于这种情况,只需要修改WebGL渲染器默认的编码方式.outputColorSpace 即可
// 设置为SRGB颜色空间
renderer.outputColorSpace = THREE.sRGBEncoding; // 旧版用.outputEncoding
加载一个外部模型,比如gltf模型,如果你想批量修改每个Mesh的材质,一个一个设置比较麻烦,可以通过递归遍历方法.traverse()批量操作更加方便
// 递归遍历所有模型节点批量修改材质
gltf.scene.traverse(function(obj) {
if (obj.isMesh) { //判断是否是网格模型
console.log('模型节点名字',obj.name);
}
});
threejs解析gltf模型默认材质一般是MeshStandardMaterial或MeshPhysicalMaterial,这两个材质属于PBR物理材质,可以提供更加真实的材质效果
gltf.scene.traverse(function(obj) {
if (obj.isMesh) {
// 重新设置材质
obj.material = new THREE.MeshLambertMaterial({
color:0xffffff,
});
}
});
美术通过三维建模软件绘制好一个三维场景以后,一些外观一样的Mesh,可能会共享一个材质对象。因此出现改变一个模型颜色其它模型跟着变化
解决问题方向
//用代码方式解决mesh共享材质问题
gltf.scene.getObjectByName("小区房子").traverse(function (obj) {
if (obj.isMesh) {
// .material.clone()返回一个新材质对象,和原来一样,重新赋值给.material属性
obj.material = obj.material.clone();
}
});
mesh1.material.color.set(0xffff00);
mesh2.material.color.set(0x00ff00);
PBR基于物理的渲染(physically-based rendering)。
Three.js提供了两个PBR材质相关的APIMeshStandardMaterial和MeshPhysicalMaterial,MeshPhysicalMaterial是MeshStandardMaterial扩展的子类,提供了更多功能属性。他们用的光照模型不同,反射光照的代码算法不同,算法不同,自然模拟光照的真实程度也不同。
金属度属性.metalness表示材质像金属的程度, 非金属材料,如木材或石材,使用0.0,金属使用1.0。 threejs的PBR材质,.metalness默认是0.5,0.0到1.0之间的值可用于生锈的金属外观
粗糙度roughness表示模型表面的光滑或者说粗糙程度,越光滑镜面反射能力越强,越粗糙,表面镜面反射能力越弱,更多地表现为漫反射。 粗糙度roughness,0.0表示平滑的镜面反射,1.0表示完全漫反射,默认0.5。
new THREE.MeshStandardMaterial({
metalness: 1.0,//金属度属性
roughness: 0.5,//表面粗糙度
})
环境贴图对PBR材质渲染效果影响还是比较大,一般渲染PBR材质的模型,最好设置一个合适的环境贴图
Shader可以做什么:
需要了解WebGL的着色器GLSL ES语言
与MeshBasicMaterial、MeshLambertMaterial这些材质通过color、map设置外观不同
ShaderMaterial是通过着色器GLSL ES语言 (opens new window)自定义材质效果,比如颜色。
顶点着色器属性vertexShader的值是字符串,字符串的内容是着色器GLSL ES语言写的代码。 为了方便预览顶点着色器代码,咱们用模板字符串``的形式去写 先按照着色器GLSL ES语言的语法,给顶点着色器代码设置一个主函数main,函数main无返回值,前面加上关键字void即可。
gl_Position是着色器GLSL ES语言的内置变量,数据类型是四维向量vec4,前面三个参数表示xyz坐标,第四个参数一般为1.0。
const vertexShader = `
void main(){
gl_Position = vec4( x, y ,z ,1.0 );
}
`
const material = new THREE.ShaderMaterial({
vertexShader: vertexShader,// 顶点着色器
});
attribute关键字一般用来声明与顶点数据有关变量。 attribute vec3 pos表示用attribute声明了一个变量pos,attribute的作用就是指明pos是顶点相关变量,pos的数类型是三维向量vec3,分别是x、y、z三个分量
const vertexShader = `
attribute vec3 pos;
void main(){
gl_Position = vec4(pos,1.0 );
}`
调用shader材质ShaderMaterial的时候,threejs默认插入了一行代码attribute vec3 position;,相当于帮你声明了一个变量position,position表示顶点的位置数据
const vertexShader = `
// attribute vec3 position;//默认提供,不用自己写
void main(){
gl_Position = vec4(position,1.0 );
}`
用来声明非顶点的变量(顶点变量用atribute声明),比如模型的矩阵、光源位置等等。 执行uniform mat4 mT。意味着通过关键字uniform声明一个变量mT,变量mT的数据类型是mat4(4x4的矩阵)
调用shader材质ShaderMaterial的时候,threejs默认插入了一行代码uniform mat4 modelMatrix;。可以使用modelMatrix对几何体顶点位置坐标进行旋转、缩放、平移。
视图矩阵viewMatrix、投影矩阵projectionMatrix也是内置,通过viewMatrix和projectionMatrix来表示相机对场景模型的旋转、缩放、平移变换。
const vertexShader = `
// uniform mat4 modelMatrix;//默认提供,不用自己写
// uniform mat4 viewMatrix;//默认提供,不用自己写
// uniform mat4 projectionMatrix;//默认提供,不用自己写
void main(){
// 投影矩阵 * 视图矩阵 * 模型矩阵 * 顶点坐标
// 注意矩阵乘法前后顺序不要写错
gl_Position = projectionMatrix * viewMatrix * modelMatrix * vec4(position,1.0 );
}
`
gl_FragColor是着色器GLSL ES语言的内置变量。 gl_FragColor数据类型是四维向量vec4(r,g,b,a),第四个参数表示透明度,不透明就是1.0。
// 片元着色器代码
const fragmentShader = `
void main() {
// RGB 0.0,1.0,1.0对应16进制颜色是0x00ffff
gl_FragColor = vec4(0.0,1.0,1.0,1.0);
}`
const material = new THREE.ShaderMaterial({
vertexShader: vertexShader,// 顶点着色器
fragmentShader: fragmentShader,// 片元着色器
});
side: THREE.DoubleSide设置双面显示
const material = new THREE.ShaderMaterial({
vertexShader: vertexShader,
fragmentShader: fragmentShader,
side: THREE.DoubleSide // 双面显示
});
半透明通过片元着色器代码设置透明度,更改gl_FragColor的第四个分量。材质ShaderMaterial设置transparent:true,才会生效
// 片元着色器代码
const fragmentShader = `
void main() {
//透明度设置0.3,在0~1之间,半透明
gl_FragColor = vec4(0.0,1.0,1.0,0.3);
}`
const geometry = new THREE.PlaneGeometry(100, 50);
const material = new THREE.ShaderMaterial({
vertexShader: vertexShader,// 顶点着色器
fragmentShader: fragmentShader,// 片元着色器
transparent:true //开启透明
});
const fragmentShader = `
uniform float opacity; //uniform声明透明度变量opacity
uniform vec3 color; //声明一个颜色变量color
void main() {
gl_FragColor = vec4(color, opacity);
}`
const material = new THREE.ShaderMaterial({
uniforms: {
// 给透明度uniform变量opacity传值
opacity: {value:0.3}
// 给uniform同名color变量传值
color:{value:new THREE.Color(0x00ffff)}
},
vertexShader: vertexShader,
fragmentShader: fragmentShader, // 片元着色器
transparent: true, //允许透明
});
地址http://www.webgl3d.cn/pages/21c48e/ 顶点着色器到片元着色器的处理可成: 1、顶点缓冲区:顶点数据 2、顶点着色器:顶点变换 3、图元装配:比如渲染Mesh,Mesh几何体有多个三角形拼接,三个点为一组生成一个三角形 4、光栅化:比如在上一步三角形轮廓中,生成填充一个一个片元(像素) 5、片元着色器:给片元(像素)着色器
gl_FragCoord.xy坐标系的坐标原点,位于threejs canvas画布的左下角,x轴水平向右,y轴竖直向上,单位是像素px。
canvas画布总宽800px的情况下,以中间作为分界点,左半部分片元红色,右半部分片元蓝色。
if(gl_FragCoord.x < 400.0){
gl_FragColor = vec4(1.0,0.0,0.0,1.0);
}else {
gl_FragColor = vec4(0.0,0.0,1.0,1.0);
}
根据片元x坐标,设置一个渐变色。
gl_FragColor = vec4(gl_FragCoord.x/800.0*1.0,0.0,0.0,1.0);
discard是着色器语言GLSL ES的一个关键字,用来控制片元着色器功能单元,舍弃某个片元。
if(gl_FragCoord.x < 400.0){
// 符合条件片元保留,并设置颜色
gl_FragColor = vec4(1.0,0.0,0.0,1.0);
}else {
discard;//不符合条件片元直接舍弃掉
}
ShaderMaterial和原来的网格材质一样,设置vertexColors:true,允许设置使用顶点颜色渲染
ShaderMaterial还有一个内置变量color,color变量表示插值之前的顶点颜色数据,varying关键字声明一个插值计算后的顶点颜色变量vColor。
// 顶点着色器代码
const vertexShader = `
// attribute vec3 color;//默认提供不用手写
varying vec3 vColor; //表示顶点插值后位置数据,与片元数量相同,一一对应
void main(){
vColor = color;// 顶点颜色数据进行插值计算
// 投影矩阵 * 模型视图矩阵 * 模型顶点坐标
gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );
}`
// 片元着色器代码
const fragmentShader = `
varying vec3 vColor; //获取顶点着色器插值数据vPosition
void main() {
// gl_FragColor = vec4(0.0,1.0,1.0,1.0);
gl_FragColor = vec4(vColor,1.0);
}`
ShaderMaterial内置了顶点UV坐标变量uv(vec2),查看Uniform的文档,能看到着色器语言数据类型sampler2D
const vertexShader = `
varying vec2 vUv;
void main(){
vUv = uv;// UV坐标插值计算
gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );
}`
const fragmentShader = `
uniform sampler2D map; //颜色贴图变量
varying vec2 vUv;
void main() {
// 通过几何体的UV坐标从颜色贴图获取像素值
gl_FragColor = texture2D( map, vUv );
}`
const texture = new THREE.TextureLoader().load('./Earth.png');
const material = new THREE.ShaderMaterial({
uniforms: {
// 给着色器中同名uniform变量map传值
map: {value: texture},
},
vertexShader: vertexShader,
fragmentShader: fragmentShader,
});
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。