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

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>

  • 3
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 4
    评论
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

淋雨一直走~

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值