three.js 拾取描边,热点轮廓,模型轮廓,热点交互

it2023-09-25  108

1. three.js 拾取描边,热点轮廓,模型轮廓,热点交互

2. 案例地址

我自己简化的案例地址 官方地址案例地址

3. 全部代码

<!DOCTYPE html> <html lang="en"> <head> <title>three.js webgl - post processing - Outline Pass</title> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0"> <link type="text/css" rel="stylesheet" href="../../three.js-r115/examples/main.css"> </head> <body> </body> <script type="module"> import * as THREE from '../../three.js-r115/build/three.module.js'; import Stats from '../../three.js-r115/examples/jsm/libs/stats.module.js'; import {GUI} from '../../three.js-r115/examples/jsm/libs/dat.gui.module.js'; import {OrbitControls} from '../../three.js-r115/examples/jsm/controls/OrbitControls.js'; import {OBJLoader} from '../../three.js-r115/examples/jsm/loaders/OBJLoader.js'; import {EffectComposer} from '../../three.js-r115/examples/jsm/postprocessing/EffectComposer.js'; import {RenderPass} from '../../three.js-r115/examples/jsm/postprocessing/RenderPass.js'; // import {ShaderPass} from '../../three.js-r115/examples/jsm/postprocessing/ShaderPass.js';// 自定义了后期 import {OutlinePass} from '../../three.js-r115/examples/jsm/postprocessing/OutlinePass.js'; // import {FXAAShader} from '../../three.js-r115/examples/jsm/shaders/FXAAShader.js'; // 抗锯齿插件 let container, stats; let camera, scene, renderer, controls; let raycaster = new THREE.Raycaster(); let mouse = new THREE.Vector2(); let selectedObjects = []; let composer, effectFXAA, outlinePass; let obj3d = new THREE.Object3D(); let group = new THREE.Group(); let params = { edgeStrength: 3.0, edgeGlow: 0.0, edgeThickness: 1.0, pulsePeriod: 0, rotate: false, usePatternTexture: false }; // 参数 function initBase() { container = document.createElement('div'); document.body.appendChild(container); let width = window.innerWidth; let height = window.innerHeight; renderer = new THREE.WebGLRenderer(); renderer.shadowMap.enabled = true; renderer.setSize(width, height); document.body.appendChild(renderer.domElement); scene = new THREE.Scene(); camera = new THREE.PerspectiveCamera(45, width / height, 0.1, 100); camera.position.set(0, 0, 8); } // 初始化三大基础 function initControls() { controls = new OrbitControls(camera, renderer.domElement); controls.minDistance = 5; controls.maxDistance = 20; controls.enablePan = false; controls.enableDamping = true; controls.dampingFactor = 0.05; } // 初始化控制器 function initLight() { scene.add(new THREE.AmbientLight(0xaaaaaa, 0.2)); let light = new THREE.DirectionalLight(0xddffdd, 0.6); light.position.set(1, 1, 1); light.castShadow = true; light.shadow.mapSize.width = 1024; light.shadow.mapSize.height = 1024; let d = 10; light.shadow.camera.left = -d; light.shadow.camera.right = d; light.shadow.camera.top = d; light.shadow.camera.bottom = -d; light.shadow.camera.far = 1000; scene.add(light); }// 初始化灯光 function initModel() { let manager = new THREE.LoadingManager(); manager.onProgress = function (item, loaded, total) { console.log(item, loaded, total); }; let loader = new OBJLoader(manager); loader.load('../../three.js-r115/examples/models/obj/tree.obj', function (object) { let scale = 1.0; object.traverse(function (child) { if (child instanceof THREE.Mesh) { child.geometry.center(); child.geometry.computeBoundingSphere(); scale = 0.2 * child.geometry.boundingSphere.radius; let phongMaterial = new THREE.MeshPhongMaterial({ color: 0xffffff, specular: 0x111111, shininess: 5 }); child.material = phongMaterial; child.receiveShadow = true; child.castShadow = true; } }); object.position.y = 1; object.scale.divideScalar(scale); obj3d.add(object); }); // 生成球 let geometry = new THREE.SphereBufferGeometry(3, 48, 24); for (let i = 0; i < 20; i++) { let material = new THREE.MeshLambertMaterial(); material.color.setHSL(Math.random(), 1.0, 0.3); let mesh = new THREE.Mesh(geometry, material); mesh.position.x = Math.random() * 4 - 2; mesh.position.y = Math.random() * 4 - 2; mesh.position.z = Math.random() * 4 - 2; mesh.receiveShadow = true; mesh.castShadow = true; mesh.scale.multiplyScalar(Math.random() * 0.3 + 0.1); group.add(mesh); } let floorMaterial = new THREE.MeshLambertMaterial({side: THREE.DoubleSide}); let floorGeometry = new THREE.PlaneBufferGeometry(12, 12); let floorMesh = new THREE.Mesh(floorGeometry, floorMaterial); floorMesh.rotation.x -= Math.PI * 0.5; floorMesh.position.y -= 1.5; group.add(floorMesh); floorMesh.receiveShadow = true; let geometry2 = new THREE.TorusBufferGeometry(1, 0.3, 16, 100); let material = new THREE.MeshPhongMaterial({color: 0xffaaff}); let torus = new THREE.Mesh(geometry2, material); torus.position.z = -4; group.add(torus); torus.receiveShadow = true; torus.castShadow = true; scene.add(group); group.add(obj3d); console.log('scene: ', scene); { let geometry3 = new THREE.BoxBufferGeometry(1, 1, 1); let material3 = new THREE.MeshBasicMaterial({color: 0x00ff00}); let cube = new THREE.Mesh(geometry3, material3); cube.name = 'cube' scene.add(cube); } } // 初始化模型 function initHelper() { stats = new Stats(); container.appendChild(stats.dom); function gui() { let gui = new GUI({width: 300}); gui.add(params, 'edgeStrength', 0.01, 10).onChange(function (value) { outlinePass.edgeStrength = Number(value); }); gui.add(params, 'edgeGlow', 0.0, 1).onChange(function (value) { outlinePass.edgeGlow = Number(value); }); gui.add(params, 'edgeThickness', 1, 4).onChange(function (value) { outlinePass.edgeThickness = Number(value); }); gui.add(params, 'pulsePeriod', 0.0, 5).onChange(function (value) { outlinePass.pulsePeriod = Number(value); }); gui.add(params, 'rotate'); gui.add(params, 'usePatternTexture').onChange(function (value) { outlinePass.usePatternTexture = value; }); let Configuration = function () { this.visibleEdgeColor = '#ffffff'; this.hiddenEdgeColor = '#190a05'; }; let conf = new Configuration(); gui.addColor(conf, 'visibleEdgeColor').onChange(function (value) { outlinePass.visibleEdgeColor.set(value); }); gui.addColor(conf, 'hiddenEdgeColor').onChange(function (value) { outlinePass.hiddenEdgeColor.set(value); }); } // gui gui(); } // 初始化帮手 function initPostprocessing() { composer = new EffectComposer(renderer); let renderPass = new RenderPass(scene, camera); composer.addPass(renderPass); outlinePass = new OutlinePass(new THREE.Vector2(window.innerWidth, window.innerHeight), scene, camera); composer.addPass(outlinePass); let onLoad = function (texture) { outlinePass.patternTexture = texture; texture.wrapS = THREE.RepeatWrapping; texture.wrapT = THREE.RepeatWrapping; }; let loader = new THREE.TextureLoader(); loader.load('../../three.js-r115/examples/textures/tri_pattern.jpg', onLoad); // effectFXAA = new ShaderPass(FXAAShader); // 自定义了后期 // effectFXAA.uniforms['resolution'].value.set(1 / window.innerWidth, 1 / window.innerHeight); // composer.addPass(effectFXAA); window.addEventListener('mousemove', onTouchMove); window.addEventListener('touchmove', onTouchMove); function onTouchMove(event) { let x, y; if (event.changedTouches) { x = event.changedTouches[0].pageX; y = event.changedTouches[0].pageY; } else { x = event.clientX; y = event.clientY; } mouse.x = (x / window.innerWidth) * 2 - 1; mouse.y = -(y / window.innerHeight) * 2 + 1; checkIntersection(); } function addSelectedObject(object) { selectedObjects = []; selectedObjects.push(object); } function checkIntersection() { raycaster.setFromCamera(mouse, camera); let intersects = raycaster.intersectObjects([scene], true); if (intersects.length > 0) { let selectedObject = intersects[0].object; addSelectedObject(selectedObject); outlinePass.selectedObjects = selectedObjects; } else { outlinePass.selectedObjects = []; } } } //postprocessing 初始化后期处理 function onWindowResize() { let width = window.innerWidth; let height = window.innerHeight; camera.aspect = width / height; camera.updateProjectionMatrix(); renderer.setSize(width, height); composer.setSize(width, height); // effectFXAA.uniforms['resolution'].value.set(1 / window.innerWidth, 1 / window.innerHeight); } // 控制窗口大小 function render() { let timer = performance.now(); if (params.rotate) { group.rotation.y = timer * 0.0001; } controls.update(); composer.render(); } // 加载器 function animate() { requestAnimationFrame(animate); render() stats.update(); }// 动画 (function () { initBase(); initControls(); initPostprocessing(); initLight(); initModel(); initHelper() window.addEventListener('resize', onWindowResize, false); animate(); })()// 启动 </script> </html>
最新回复(0)