页面节点
<style>
body {
margin: 0;
}
</style>
<div id="threemap" style="width:100%;height:100%;"></div>
添加引用
<script type="importmap">
{
"imports": {
"three": "../lib/build/three.module.js",
"three/addons/": "./lib/jsm/"
}
}
</script>
基础功能代码
<script type="module">
import * as THREE from 'three';
var dom = document.getElementById("threemap");
var displayWidth = dom.clientWidth;
var displayHeight = dom.clientHeight;
///创建场景
var scene = new THREE.Scene();
//几何体分为
//长方体
const geometry1 = new THREE.BoxGeometry(100, 100, 100);
//圆柱体
const geometry2 = new THREE.CylinderGeometry(50, 50, 100);
//球体
const geometry3 = new THREE.SphereGeometry(100);
//圆锥体
// radius: 圆锥体底部的半径;
//height: 圆锥体的总高度;
//radialSegments(径向分段数): 圆锥体周围的圆环部分的分段数;
//heightSegments(高度分段数): 圆锥体的高度上的分段数;
//openEnded(是否开口): 一个布尔值,指示圆锥体是否是开口的,如果为 true,则表示开口;
//thetaStart(起始角度): 圆锥体的起始角度,用弧度表示;
//thetaLength(角度范围): 圆锥体的角度范围,用弧度表示。
const geometry4 = new THREE.ConeGeometry(1, 10, 100, 200);
//矩形平面
const geometry5 = new THREE.PlaneGeometry(100, 50);
//圆平面
const geometry6 = new THREE.CircleGeometry(50);
//材质 默认只有正面可见 side: THREE.FrontSide,可以设置为 THREE.DoubleSide THREE.BackSide
//受光源影响的材质会受到光源和材质本身颜色影响 色谱叠加 模型正对光源的部分为高光部分
//网格基础材质 不受光源影响
const material1 = new THREE.MeshBasicMaterial({ color: 0xff0000, }); //0xff0000设置材质颜色为红色
//网格漫反射材质 受光源影响
const material2 = new THREE.MeshLambertMaterial({ color: 0xff0000, }); //0xff0000设置材质颜色为红色
//网格高光材质 受光源影响
const material3 = new THREE.MeshPhongMaterial({
color: 0xff0000,//0xff0000设置材质颜色为红色
shininess: 20, //高光部分的亮度,默认30
specular: 0xF7F709, //高光部分的颜色
});
//物理材质 受光源影响
const material4 = new THREE.MeshStandardMaterial({ color: 0xff0000, }); //0xff0000设置材质颜色为红色
const material5 = new THREE.MeshPhysicalMaterial({ color: 0xff0000, }); //0xff0000设置材质颜色为红色
//点材质
const material6 = new THREE.PointsMaterial({ color: 0xff0000, }); //0xff0000设置材质颜色为红色
//线基础材质
const material7 = new THREE.LineBasicMaterial({ color: 0xff0000, }); //0xff0000设置材质颜色为红色
//精灵材质
const material8 = new THREE.SpriteMaterial({ color: 0xff0000, }); //0xff0000设置材质颜色为红色
//网格模型对象Mesh 几何体和材质通过Mesh组合
const mesh = new THREE.Mesh(geometry1, material1);
const mesh1 = new THREE.Mesh(geometry3, material2);
mesh1.position.set(100, 100, 100);
//设置组合对象的位置
mesh.position.set(0, 0, 0);
//加到三维场景中
scene.add(mesh);
//scene.add(mesh1);
// AxesHelper:辅助观察的坐标系
const axesHelper = new THREE.AxesHelper(400);
scene.add(axesHelper);
//投影相机
// 30:视场角度,角度越大 能看到的场景越大
//displayWidth / displayHeight: Canvas画布宽高比,
//1: 近裁截面,
// 3000:远裁截面
//远裁截面-近裁截面构成了视锥体高度方向
//透视投影相机
const camera1 = new THREE.PerspectiveCamera(30, displayWidth / displayHeight, 1, 3000);
//正投影相机
const camera2 = new THREE.OrthographicCamera(30, displayWidth / displayHeight, 1, 3000);
//设置相机位置
camera1.position.set(800, 800, 800);
//相机观测位置 摄像头对准哪
camera1.lookAt(0, 0, 0); //坐标原点
//光源
//点光源(由一个点向外照射):两个参数分别表示光源颜色和光照强度
const pointLight = new THREE.PointLight(0xffffff, 1.0);
//点光源位置
//点光源放在x轴上
pointLight.position.set(200, 300, 200);
//光照强度 可以用参数设置
//pointLight.intensity = 1.0;
//设置光源随距离衰减 0-2 0为不受光源影响 2为受光源影响
pointLight.decay = 0.0;
//点光源辅助观查
const pointLightHelper = new THREE.PointLightHelper(pointLight, 10);
//scene.add(pointLightHelper);
//环境光(没有特定方向,整体改变场景的光照明暗):两个参数分别表示光源颜色和光照强度
const ambientLight = new THREE.AmbientLight(0x1A23F6, 1.0);
//聚光灯(一个光源点向指定方向发散照射):两个参数分别表示光源颜色和光照强度
const spotLight = new THREE.SpotLight(0x1A23F6, 1.0);
//平行光
const directionalLight = new THREE.DirectionalLight(0x1A23F6, 1.0);
// 设置光源的方向:通过光源position属性和目标指向对象的position属性计算
directionalLight.position.set(300, 200, 300);
// 方向光指向对象网格模型mesh,可以不设置,默认的位置是0,0,0
directionalLight.target = mesh;
//scene.add(directionalLight);
// DirectionalLightHelper:可视化平行光
const dirLightHelper = new THREE.DirectionalLightHelper(directionalLight, 5, 0xff0000);
//scene.add(dirLightHelper);
//光源添加到场景中
//scene.add(pointLight);
//有了景物和相机 只需要拿着相机拍一下就完成拍照
//渲染器 就是拍照
const renderer = new THREE.WebGLRenderer();
//渲染器锯齿属性
renderer.antialias = true;
//设置渲染器像素比当前屏幕设备像素比 默认为1 不同设备会有不同像素比
renderer.setPixelRatio(window.devicePixelRatio);
//设置背景颜色 0为透明度 一般跟随页面背景颜色时设置透明度为0
renderer.setClearColor(0xffffff, 0);
//设置three.js渲染区域的尺寸(像素px) 一般为节点宽高
renderer.setSize(displayWidth, displayHeight);
//执行渲染操作
renderer.render(scene, camera1);
//将canvas画布添加到页面节点中
dom.appendChild(renderer.domElement);
import Stats from '/lib/jsm/libs/stats.module.js';
//创建stats对象
const stats = new Stats();
//设置stats.domElement显示内容:如果不是循环一直在执行 显示信息不准确 是根据上一帧计算的
//0 渲染帧率 刷新频率, 一秒渲染次数
//1 渲染周期 渲染一帧多长时间(单位:毫秒ms)
stats.setMode(1);
//stats.domElement:web页面上输出计算结果,一个div元素,
document.body.appendChild(stats.domElement);
import { OrbitControls } from '/lib/jsm/controls/OrbitControls.js';
// 设置相机控件轨道控制器OrbitControls
const controls = new OrbitControls(camera1, renderer.domElement);
// 如果OrbitControls改变了相机参数,重新调用渲染器渲染三维场景
controls.addEventListener('change', function () {
//console.log('camera.position', camera1.position);//本质就是改变相机的位置
stats.update();//每一次变化调用一次方法改变输出
renderer.render(scene, camera1); //执行渲染操作
});//监听鼠标、键盘事件
//循环执行 可以在页面上一些项需要实时检测时执行
function render() {
//mesh1.rotateY(0.1);//每次绕y轴旋转0.01弧度
stats.update();
renderer.render(scene, camera1); //执行渲染操作
requestAnimationFrame(render);//请求再次执行渲染函数render,渲染下一帧
}
render();
// onresize 事件会在窗口被调整大小时发生 每次窗口大小调整都需要重新调整画布大小
window.onresize = function () {
//重新获取改变后的节点宽高
var dom = document.getElementById("threemap");
var width = dom.clientWidth;
var height = dom.clientHeight;
// 重置渲染器输出画布canvas尺寸
renderer.setSize(width, height);
// 全屏情况下:设置观察范围长宽比aspect为窗口宽高比
camera1.aspect = width / height;
// 渲染器执行render方法的时候会读取相机对象的投影矩阵属性projectionMatrix
// 但是不会每渲染一帧,就通过相机的属性计算投影矩阵(节约计算资源)
// 如果相机的一些属性发生了变化,需要执行updateProjectionMatrix ()方法更新相机的投影矩阵 不生效 先用render再次渲染
//camera1.updateProjectionMatrix();
renderer.render(scene, camera1);
};
import GUI from '/lib/jsm/libs/lil-gui.module.min.js';
const gui = new GUI();
//设置gui窗体位置 只能是页面上方 可设置宽高 高可不设置 控件撑开
gui.domElement.style.right = '0px';
gui.domElement.style.width = '300px';
//gui.domElement.style.height = '300px';
//更改gui窗体名称
gui.domElement.querySelector('.title').textContent="操作"
//创建gui分组 分组可多次嵌套
const matFolder = gui.addFolder('坐标操作');
//分组展开或关闭open/close
matFolder.close();
//创建一个对象,对象属性的值可以被GUI库创建的交互控件改变 可以通过此方法改变创建对象里的值 需要开启循环执行渲染或者改变后手动调用一次渲染操作
//name更改交互控件的显示名称
//step更改控件值的间隔
//onchange只有在改变值的同时有其他操作时使用 onchange和直接改变值相同
//默认值只有在控件初次加载的时候跟随模型修改 当多个控件更改一个属性时其他控件值不会更改 需在onchange中更改
// gui.add 第一个参数为要改变的对象 第二个参数为要改变的属性
//当三、四参数为数字时 生成拖动条 三为最小值 四为最大值
matFolder.add(mesh.position, 'x', 0, 300).name("模型x坐标").step(0.1);
matFolder.add(mesh.position, 'y', 0, 300).name("模型y坐标").step(0.1);
matFolder.add(mesh.position, 'z', 0, 300).name("模型z坐标").step(0.1);
//当三参数为数组时 生成下拉框
matFolder.add(mesh.position, 'x', [-100, 0, 100]).name("模型x坐标")
//当三参数为对象时 生成下拉菜单
// 参数3数据类型:对象(下拉菜单)
matFolder.add(mesh.position, 'x', {
左: -100,//可以用中文
中: 0,
右: 100
}).name('位置选择');
//当要改变属性为bool值时 生成单选框
const obj = {
bool: false,
};
// 改变的obj属性数据类型是布尔值,交互界面是单选框
gui.add(obj, 'bool').name('是否旋转');
//这种方式需要调用一次渲染或者循环渲染
gui.addColor(mesh.material, "color").name("模型颜色");
//gui.addColor(obj, 'color').onChange(function (value) {
// mesh.material.color.set(value);
//});
</script>