three.js流动线

2023-05-16

效果:

先看最基本的

 function initThree(el, options) {
        options = options || {}
        const t = this
        appInstance  = this
        const width = el.offsetWidth
        const height = el.offsetHeight
        const asp = width / height

        // scene
        const scene = new THREE.Scene()

        // camera
        let camera
        if (options.camera) {
            camera = options.camera
        } else {
            camera = new THREE.PerspectiveCamera(45, asp, 1, 100000)
            window.addEventListener('resize', function() {
                camera.aspect = el.offsetWidth / el.offsetHeight
                renderer.setSize(el.offsetWidth, el.offsetHeight) // 重新获取
                camera.updateProjectionMatrix()
                renderer.render(scene, camera)
            }, false)
        }
        camera.position.set(30, 30, 30)

        // renderer
        const renderer = new THREE.WebGLRenderer({ antialias: true, alpha: true })
        renderer.setPixelRatio(window.devicePixelRatio)
        renderer.setSize(width, height)
        el.append(renderer.domElement)
        renderer.setClearColor(options.clearColor || '#000')

        // 辅助
        if (options.axes) scene.add(new THREE.AxesHelper(10))// 坐标轴辅助红x 绿y 蓝z
        if (options.gridHelper) scene.add(new THREE.GridHelper(100, 100))// 网格参考线

        //按序渲染
        renderer.sortObjects = options.sortObjects

        // to the instance
        t.renderer = renderer
        t.scene = scene
        t.camera = camera
        t.el = el
    }

    const el = document.getElementById('box')

    const app = new initThree(el,{
        // gridHelper:true,//网格参考线
        // axes:true,//坐标辅助
        clearColor:'#000'//画布颜色
    })
    const camera = app.camera
    const renderer = app.renderer
    const scene = app.scene
    function initControls(scene,camera,renderer) {
        const controls = new THREE.OrbitControls( camera, renderer.domElement );
        // 如果使用animate方法时,将此函数删除
        controls.addEventListener( 'change', ()=>{
            renderer.render( scene, camera );
        });
        // // 使动画循环使用时阻尼或自转 意思是否有惯性
        // controls.enableDamping = true;
        // //动态阻尼系数 就是鼠标拖拽旋转灵敏度
        // //controls.dampingFactor = 0.25;
        // //是否可以缩放
        // controls.enableZoom = true;
        // //是否自动旋转
        // controls.autoRotate = true;
        // controls.autoRotateSpeed = 0.5;
        // //设置相机距离原点的最远距离
        // controls.minDistance  = 1;
        // //设置相机距离原点的最远距离
        // controls.maxDistance  = 200;
        // //是否开启右键拖拽
        //controls.enablePan = true;
        return controls
    }
    var controls = initControls(scene,camera,renderer)
    const clock = new THREE.Clock()

    //add light
    const directionalLight = new THREE.DirectionalLight( '#fff' )
    directionalLight.position.set( 30, 30, 30 ).normalize()
    scene.add( directionalLight )
    const ambientLight = new THREE.AmbientLight('#fff',0.3) // obj 唯一 id
    scene.add(ambientLight)
   const pointList1 = [
        [20,5,10],
        [10,5,-9],
        [10,5,20],
        [-40,5,-40]
    ]
    let line1
    textureLoader.load( '../../images/ysThree/green_line.png', function (texture1) {
        const material1 = new MeshLineMaterial({
            color: "green",
            map: texture1,
            useMap: true,
            lineWidth: 4,
            resolution: resolution,
            dashArray: 0.8,  // 破折号之间的长度和间距。(0 -无破折号)
            dashRatio: 0.5, // 定义可见和不可见之间的比率(0 -更可见,1 -更不可见)。
            dashOffset: 0,
            transparent: true,
            sizeAttenuation: 1, //使线宽不变,不管距离(1个单位是屏幕上的1px)(0 -衰减,1 -不衰减)
            side: THREE.FrontSide,
            depthTest: true,
            blending: THREE.AdditiveBlending,
            near: camera.near,
            far: camera.far,
        })
        const l = []
        pointList1.forEach(e => l.push(new THREE.Vector3(e[0], e[1], e[2])))
        let curve = new THREE.CatmullRomCurve3(l) // 曲线路径
        const geo = new THREE.Geometry()
        geo.vertices = curve.getPoints( 50)
        console.log(geo)
        const meshLine = new MeshLine()
        meshLine.setGeometry(geo)
        console.log(meshLine.geometry)
        line1=new THREE.Mesh(meshLine.geometry, material1)
        scene.add(line1)
    })

   function render() {
        controls.update(clock.getDelta())
        renderer.render( scene,camera)
        requestAnimationFrame(render)
        //
        if(line1){
            line1.material.uniforms.dashOffset.value -= 0.01
        }

    }
    render()

由上文可以看到,其实核心就是基于meshline作者提供的插件来完成的。

完成代码如下:

<script src="../../plugins/threeLibrary/three.min.js"></script>
<script src="../../plugins/threeLibrary/js/controls/OrbitControls.js"></script>
<script src="../../plugins/threeLibrary/js/lines/MeshLine.js"></script>

<script>

    function initThree(el, options) {
        options = options || {}
        const t = this
        appInstance  = this
        const width = el.offsetWidth
        const height = el.offsetHeight
        const asp = width / height

        // scene
        const scene = new THREE.Scene()

        // camera
        let camera
        if (options.camera) {
            camera = options.camera
        } else {
            camera = new THREE.PerspectiveCamera(45, asp, 1, 100000)
            window.addEventListener('resize', function() {
                camera.aspect = el.offsetWidth / el.offsetHeight
                renderer.setSize(el.offsetWidth, el.offsetHeight) // 重新获取
                camera.updateProjectionMatrix()
                renderer.render(scene, camera)
            }, false)
        }
        camera.position.set(30, 30, 30)

        // renderer
        const renderer = new THREE.WebGLRenderer({ antialias: true, alpha: true })
        renderer.setPixelRatio(window.devicePixelRatio)
        renderer.setSize(width, height)
        el.append(renderer.domElement)
        renderer.setClearColor(options.clearColor || '#000')

        // 辅助
        if (options.axes) scene.add(new THREE.AxesHelper(10))// 坐标轴辅助红x 绿y 蓝z
        if (options.gridHelper) scene.add(new THREE.GridHelper(100, 100))// 网格参考线

        //按序渲染
        renderer.sortObjects = options.sortObjects

        // to the instance
        t.renderer = renderer
        t.scene = scene
        t.camera = camera
        t.el = el
    }

    const el = document.getElementById('box')

    const app = new initThree(el,{
        // gridHelper:true,//网格参考线
        // axes:true,//坐标辅助
        clearColor:'#000'//画布颜色
    })
    const camera = app.camera
    const renderer = app.renderer
    const scene = app.scene
    function initControls(scene,camera,renderer) {
        const controls = new THREE.OrbitControls( camera, renderer.domElement );
        // 如果使用animate方法时,将此函数删除
        controls.addEventListener( 'change', ()=>{
            renderer.render( scene, camera );
        });
        // // 使动画循环使用时阻尼或自转 意思是否有惯性
        // controls.enableDamping = true;
        // //动态阻尼系数 就是鼠标拖拽旋转灵敏度
        // //controls.dampingFactor = 0.25;
        // //是否可以缩放
        // controls.enableZoom = true;
        // //是否自动旋转
        // controls.autoRotate = true;
        // controls.autoRotateSpeed = 0.5;
        // //设置相机距离原点的最远距离
        // controls.minDistance  = 1;
        // //设置相机距离原点的最远距离
        // controls.maxDistance  = 200;
        // //是否开启右键拖拽
        //controls.enablePan = true;
        return controls
    }
    var controls = initControls(scene,camera,renderer)
    const clock = new THREE.Clock()

    //add light
    const directionalLight = new THREE.DirectionalLight( '#fff' )
    directionalLight.position.set( 30, 30, 30 ).normalize()
    scene.add( directionalLight )
    const ambientLight = new THREE.AmbientLight('#fff',0.3) // obj 唯一 id
    scene.add(ambientLight)


    camera.position.set(100,100,100)
    const resolution = new THREE.Vector2( el.offsetWidth,  el.offsetHeight );
    const textureLoader = new THREE.TextureLoader()


    function getSphereHeightPoints (v0, v3, n1, n2, p0) {
        // 夹角
        const angle = (v0.angleTo(v3) * 180) / Math.PI / 10 // 0 ~ Math.PI
        const aLen = angle * (n1 || 10)
        const hLen = angle * angle * (n2 || 120)
        p0 = p0 || new THREE.Vector3(0, 0, 0) // 默认以 坐标原点为参考对象
        // 法线向量
        const rayLine = new THREE.Ray(p0, v0.clone().add(v3.clone()).divideScalar(2))
        // 顶点坐标
        const vtop = rayLine.at(hLen / rayLine.at(1).distanceTo(p0))
        // 计算制高点
        const getLenVector = (v1, v2, len) => v1.lerp(v2, len / v1.distanceTo(v2))
        // 控制点坐标
        return [getLenVector(v0.clone(), vtop, aLen), getLenVector(v3.clone(), vtop, aLen)]
    }

    /*  **** **** ****   ****/
   function createAnimateLine (option) {
        let curve
        if (option.kind === 'sphere') { // 由两点之间连线成贝塞尔曲线
            const sphereHeightPointsArgs = option.sphereHeightPointsArgs
            const pointList = this.getSphereHeightPoints(...sphereHeightPointsArgs) // v0,v3,n1,n2,p0
            curve = new THREE.CubicBezierCurve3(sphereHeightPointsArgs[0], pointList[0], pointList[1], sphereHeightPointsArgs[1])
        } else { // 由多个点数组构成的曲线 通常用于道路
            const l = []
            option.pointList.forEach(e => l.push(new THREE.Vector3(e[0], e[1], e[2])))
            curve = new THREE.CatmullRomCurve3(l) // 曲线路径
        }
        if (option.type === 'pipe') { // 使用管道线
            // 管道体
            const tubeGeometry = new THREE.TubeGeometry(curve, option.number || 50, option.radius || 1, option.radialSegments)
            return new THREE.Mesh(tubeGeometry, option.material)
        } else { // 使用 meshLine
            if (!MeshLine || !MeshLineMaterial) console.error('you need import MeshLine & MeshLineMaterial!')
            else {
                const geo = new THREE.Geometry()
                geo.vertices = curve.getPoints(option.number || 50)
                const meshLine = new MeshLine()
                meshLine.setGeometry(geo)
                return new THREE.Mesh(meshLine.geometry, option.material)
            }
        }
    }

    const pointList1 = [
        [20,5,10],
        [10,5,-9],
        [10,5,20],
        [-40,5,-40]
    ]
    let line1
    textureLoader.load( '../../images/ysThree/green_line.png', function (texture1) {
        const material1 = new MeshLineMaterial({
            color: "green",
            map: texture1,
            useMap: true,
            lineWidth: 4,
            resolution: resolution,
            dashArray: 0.8,  // 破折号之间的长度和间距。(0 -无破折号)
            dashRatio: 0.5, // 定义可见和不可见之间的比率(0 -更可见,1 -更不可见)。
            dashOffset: 0,
            transparent: true,
            sizeAttenuation: 1, //使线宽不变,不管距离(1个单位是屏幕上的1px)(0 -衰减,1 -不衰减)
            side: THREE.FrontSide,
            depthTest: true,
            blending: THREE.AdditiveBlending,
            near: camera.near,
            far: camera.far,
        })
        const l = []
        pointList1.forEach(e => l.push(new THREE.Vector3(e[0], e[1], e[2])))
        let curve = new THREE.CatmullRomCurve3(l) // 曲线路径
        const geo = new THREE.Geometry()
        geo.vertices = curve.getPoints( 50)
        console.log(geo)
        const meshLine = new MeshLine()
        meshLine.setGeometry(geo)
        console.log(meshLine.geometry)
        line1=new THREE.Mesh(meshLine.geometry, material1)
        scene.add(line1)
    })

    /** 2:绘制普通pipeLine**/

    const pointList2 = [
        [-20,5,-10],
        [30,5,-15],
        [10,5,20],
        [40,5,40]
    ]
    const texture2 = textureLoader.load("../../images/ysThree/red_line.png")
    texture2.wrapS = texture2.wrapT = THREE.RepeatWrapping; //每个都重复
    texture2.repeat.set(1, 1)
    const  material2 = new THREE.MeshBasicMaterial({map:texture2,side:THREE.BackSide,transparent:true})
    texture2.needsUpdate = true
    const line2 = createAnimateLine({
        // kind: 'sphere',//默认不填 为普通 ; 如为sphere,则表示球面建点
        type: 'pipe',//默认不填 为MeshLine ; 如为pipe,则表示管道线
        pointList: pointList2,
        material: material2,
        number: 100
    })
    scene.add(line2)

    /** 1:在球面上绘制meshLine**/
    const v0 =  new THREE.Vector3( -80, 10,  0 )
    const v3 =  new THREE.Vector3( 80, 10,  0 )

    let line3
    textureLoader.load( '../../images/ysThree/green_line.png', function (texture3) {
        const material3 = new MeshLineMaterial({
            color: "green",
            map: texture3,
            useMap: true,
            lineWidth: 4,
            resolution: resolution,
            dashArray: 0.8,  // 破折号之间的长度和间距。(0 -无破折号)
            dashRatio: 0.5, // 定义可见和不可见之间的比率(0 -更可见,1 -更不可见)。
            dashOffset: 0,
            transparent: true,
            sizeAttenuation: 1, //使线宽不变,不管距离(1个单位是屏幕上的1px)(0 -衰减,1 -不衰减)
            side: THREE.FrontSide,
            depthTest: true,
            blending: THREE.AdditiveBlending,
            near: camera.near,
            far: camera.far,
        })
        line3 = createAnimateLine({
            kind: 'sphere',//默认不填 为普通 ; 如为sphere,则表示球面建点
            // type: 'pipe',//默认不填 为MeshLine ; 如为pipe,则表示管道线
            sphereHeightPointsArgs: [v0,v3],
            material: material3
        })
        scene.add(line3)
    })

    /** 1:在球面上绘制pipeLine**/

    const v0_1 =  new THREE.Vector3( -60, 10,  0 )
    const v3_1 =  new THREE.Vector3( 60, 10,  0 )

    const texture4 = textureLoader.load("../../images/ysThree/red_line.png")
    texture4.wrapS = texture4.wrapT = THREE.RepeatWrapping; //每个都重复
    texture4.repeat.set(1, 1)
    const  materia4 = new THREE.MeshBasicMaterial({map:texture4,side:THREE.BackSide,transparent:true})
    texture4.needsUpdate = true
    const line4 = createAnimateLine({
        kind: 'sphere',//默认不填 为普通 ; 如为sphere,则表示球面建点
        type: 'pipe',//默认不填 为MeshLine ; 如为pipe,则表示管道线
        sphereHeightPointsArgs: [v0_1,v3_1],
        material: materia4,
        number: 100,
        radius: 1 // 默认
    })
    scene.add(line4)

    /*  **** **** ****   ****/
    function render() {
        controls.update(clock.getDelta())
        renderer.render( scene,camera)
        requestAnimationFrame(render)
        //
        if(line1){
            line1.material.uniforms.dashOffset.value -= 0.01
        }

        //
        texture2.offset.x -= 0.01

        //
        if(line3){
            line3.material.uniforms.dashOffset.value -= 0.01
        }

        texture4.offset.x -= 0.01
    }
    render()
</script>

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

three.js流动线 的相关文章

  • 水下图像色彩还原(基于可见光衰减及图像去雾算法)

    参考源 参考论文 xff1a UnderwaterHazeLines BMVC2017 Github项目地址 xff1a https github com danaberman underwater hl git 对论文的一些重述 水下图像
  • 强化学习TD3算法笔记1——论文解读

    相关论文 TD3 xff1a TD3 Double DQN Double DQN DDPG DDPG TD3论文结构 摘要 xff1a 提出Actor Critic面对的问题 xff0c 概括了TD3算法和效果引言 xff1a 提出当前对于
  • Efficientnet_pytorch_cbam_gui

    大致说明 这是一个基于efficientnet模型的图像分类方案 模型融入了cbam注意力机制模块 xff0c cutmix CrossEntropyLabelSmooth auto augment等tricks帮助原生的effcientn
  • 可靠性udp传输大文件

    高级计算机网络大作业 可靠性udp传输大文件 实验数据zstd压缩1G文件 xff08 延迟100ms 丢包1 xff09 0 1G文件 xff08 延迟100ms 丢包1 xff09 0 01G文件 xff08 延迟100ms 丢包1 x
  • 一些奇怪问题的解决汇总

    vscode ssh远程连接 问题描述 xff1a Setting up SSH Host 192 168 78 133 details Initializing VS Code Server 一开始尝试了网络的各种方式 xff0c 比如删

随机推荐

  • 控制系统--系统结构图

    结构图基本单元 信号线 表示信号流向 引出点 表示信号引出 xff0c 被引出信号与原信号完全相同 或 从同一位置引出信号完全相同 比较点 将所有输入信号做代数运算 方框 表示信号经过传递函数为 H s
  • 字符串及处理之三: 使用TCHAR系列方案

    使用TCHAR系列方案编写程序 TCHAR是一种字符串类型 xff0c 它让你在以MBCS和UNNICODE来build程序时可以使用同样的代码 xff0c 不需要使用繁琐的宏定义来包含你的代码 TCHAR的引入 xff0c 主要是在Tch
  • Chrome解决“github.com拒绝了我们的访问请求”

    目录 1 网站查询特定IP 2 host文件修改 3 刷新DNS 如果你在Chrome访问github com时出现以下错误 xff1a 本博主之前的Chrome和Edge都无法访问github官网 xff0c 然后就来到了万能的C站找到了
  • STC12C5A60S2_LCD1602驱动

    文章目录 LCD1602 HLCD1602 cmain c LCD1602 H 代码如下 xff1a span class token macro property span class token directive hash span
  • 猿创征文|机器学习实战(8)——随机森林

    目录 1 随机森林 2 极端随机树 3 特征重要性 4 提升法 4 1 AdaBoost 4 2 梯度提升 机器学习实战 xff08 7 xff09 中我们已经提到 xff0c 随机森林是决策树的集成 xff0c 通常用bagging方法训
  • 总结2014——迷茫以及迷茫过后的坚持

    首先 xff0c 借用一句话和大家共勉 xff1a 少一些功利主义的追求 xff0c 多一些不为什么的坚持 xff01 xff01 不知不觉15年也快过了1个月了 xff0c 还是想着要为14年做一下总结 xff1a 记录一下自己的历程 今
  • 汇编总结:lea指令

    ea指令变种 按大小分类 leaw 2个字节 leal 4个字节 leaq 8个字节 lea的用法 leaq a b c d rax 首先lea指令是mov指令的变种 xff0c 据说 xff0c lea指令是x86体系结构中 xff0c
  • CMake语法—选项(option)

    CMake语法 选项 xff08 option xff09 1 选项 1 1 定义 1 2 说明 variable 选项名help text 描述 解释 备注value 选项初始化值 xff08 除ON而外全为OFF xff09 2 应用注
  • C++工程:总结 CMake 添加第三方库依赖方式git submodule、 find_library、FetchContent、CPM等

    CMake 已经成为了C 43 43 工程管理的主流方式 xff0c 功能非常强大 xff0c 现在大多数的 C 43 43 库都已经支持CMake xff0c 下面以 jsoncpp 为例 xff0c 介绍几种引入第三方库的方式 1 代码
  • 医学图像——DCMTK、VTK、ITK、RTK、SimpleITK

    1 引言 https github com SINTEFMedtek ITK VTK xff0c 相关童鞋应该很熟悉的 xff0c 而CTK是一个较新的界面库 xff0c 主要用于方便前面两个 TK的界面设计 xff0c 当然也可以作为通用
  • C++中的volatile

    volatile的本意是 易变的 volatile关键字是一种类型修饰符 xff0c 用它声明的类型变量表示可以被某些编译器未知的因素更改 xff0c 比如操作系统 硬件或者其它线程等 遇到这个关键字声明的变量 xff0c 编译器对访问该变
  • 3DTiles】关于GeometricError几何度量误差

    在 3DTiles 的官方文档中详细介绍了关于几何度量误差 Geometric Error 的一些理念和内涵 xff0c 概括来说可以翻译为如下定义 xff1a 几何度量误差 xff0c Geometric Error xff0c 简称 G
  • glPixelStorei 详解 包括像素传输

    3 glPixelStore 像glPixelStorei GL PACK ALIGNMENT 1 这样的调用 xff0c 通常会用于像素传输 PACK UNPACK 的场合 尤其是导入纹理 glTexImage2D 的时候 xff1a C
  • ESLint 简介

    ESLint简介 ESLint是一个用来识别 ECMAScript 并且按照规则给出报告的代码检测工具 xff0c 使用它可以避免低级错误和统一代码的风格 如果每次在代码提交之前都进行一次eslint代码检查 xff0c 就不会因为某个字段
  • IOS VasSonic 粗略见解

    因为项目需求需要在本地缓存html页面 xff0c 优化用户体验 了解到VasSonic 百度了下源码解析但是没有发现IOS的所以只有自己慢慢摸索了 一 类的简单关系 1 SonicEngine 引擎类 代理为 UIWebViewContr
  • axios的详细讲解

    一 axios的特性 axios 是一个基于Promise 用于浏览器和 nodejs 的 HTTP 客户端 xff0c 简单的理解就是ajax的封装 特性 xff1a 从浏览器中创建 XMLHttpRequests从 node js 创建
  • 无人机飞控算法-姿态估计-欧拉角-旋转矩阵-四元数

    无人机飞控算法 姿态估计 此系列记录了我理解的卡尔曼滤波从0到1的过程 xff0c 从姿态估计到位置估计 xff0c 我们从核心点一个个出发 xff0c 并结合实际模块的应用来一一揭开卡尔曼滤波的神秘面纱 提示 xff1a 在系列文章中 x
  • BMP格式详解

    介绍 数字图像在外存储器设备中的存储形式是图像文件 xff0c 图像必须按照某个已知的 公认的数据存储顺序和结构进行存储 xff0c 才能使不同的程序对图像文件顺利进行打开或存盘操作 xff0c 实现数据共享 图像数据在文件中的存储顺序和结
  • WinHex使用方法详解

    WinHex是由X Ways软件技术公司 xff08 官方网站http www x ways net xff09 开发的一款专业的磁盘编辑工具 xff0c 该工具文如其名 xff0c 是在Windows下运行的十六进制 xff08 hex
  • three.js流动线

    效果 xff1a 先看最基本的 function initThree el options options 61 options const t 61 this appInstance 61 this const width 61 el o