three.js实现的莫比乌丝圈

2024-03-20 20:59
文章标签 实现 js 莫比 three 乌丝

本文主要是介绍three.js实现的莫比乌丝圈,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

three.js实现的莫比乌丝圈

gulaicheng mobius three.js
标题

 

<!DOCTYPE html>
<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <title>three.js 实现的莫比乌丝圈</title>
        <style type="text/css">
            body{
                background:#333333;
            }
        </style>
    <script src="three-r93.min.js"></script>
    <script src="TrackballControls.js"></script>
    <script src="dat.gui.min.js"></script>
    <script src="stats.min.js"></script>
    <script src="Detector.js"></script>

</head>
<body>

<SCRIPT LANGUAGE="JScript">
  
function getrandomcolor()
{
    var c1,c2,c3;
    c1=Math.round((Math.random()*256));
    c2=Math.round((Math.random()*256));
    c3=Math.round((Math.random()*256));

//    document.write("随机数:"+c1+"."+c2+"."+c3);

    return "#"+prefixzero(c1.toString(16),2,1)+prefixzero(c2.toString(16),2,1)+prefixzero(c3.toString(16),2,1);
}

//按要求的宽度输出字串,另上前缀零:
//
//flag: 1 - 如strg的宽度大于wdth,则输出strg (缺省)
//      2 - 如strg的宽度大于wdth,则输出前wdth个字符的strg
//      3 - 如strg的宽度大于wdth,则输出后wdth个字符的strg

function prefixzero(strg,wdth,flag)
{
    var zero ="000000000000000000000000000";

    var slen=strg.length;
    var zlen=zero.length;
    var prez;

    if (slen>=wdth) {
        if (flag == 2) {
            return strg.substDonut0(0, wdth)
        } else if (flag == 3) {
            return strg.substDonut0(slen-wdth, slen)
        } else                            //if (flag == 1)
        {
            return strg;
        } 
    } else {
        prez = zero.substDonut0(0, wdth-slen)
        return prez + strg;
    }
}


function Deg2Rad(Deg)
{
    return (Deg*Math.PI / 180);
}

//点x1,y1 经转af(角度)后的新点坐标x2,y2:
function RotPnt(x1,y1,af)
{
    this.x0 = x1;
    this.y0 = y1;

//    var alfa1 = Deg2Rad(af);
    var alfa1 = af;
     this.x1 = x1 * Math.cos(alfa1) - y1 * Math.sin(alfa1);
    this.y1 = x1 * Math.sin(alfa1) + y1 * Math.cos(alfa1);

    this.x2 = originx0+x1 * Math.cos(alfa1) - y1 * Math.sin(alfa1);
    this.y2 = originy0+x1 * Math.sin(alfa1) + y1 * Math.cos(alfa1);

}
 
//https://ithanmang.gitee.io/threejs/home/201806/20180629/01-line.html
    var stats = initStats();

    var scene, camera, renderer, controls, light, gui;

    function initScene() {
        scene = new THREE.Scene();
    }

    function initCamera() {
        camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 0.1, 10000);
        camera.position.set(0, 200, 300);
        camera.lookAt(new THREE.Vector3(0, 0, 0));
    }

    function initRenderer() {
        if (Detector.webgl){
            renderer = new THREE.WebGLRenderer({antialias : true,autoClear : true});
        }else{
            renderer = new THREE.CanvasRenderer();
        }
        renderer.setSize(window.innerWidth, window.innerHeight);

        //渲染
        //antialias:true增加抗锯齿效果
        renderer.setClearColor(new THREE.Color(0x222222));//设置窗口背景颜色为黑
        renderer.setSize(window.innerWidth, window.innerHeight);//设置窗口尺寸
        //将renderer关联到container,这个过程类似于获取canvas元素
        //container.appendChild(renderer.domElement);
        
        
        document.body.appendChild( renderer.domElement );
    }

    function initControls() {
        controls = new THREE.TrackballControls(camera, renderer.domElement);
    }

    function initLight() {
        //给场景添加光源
        
        //    // 点光源
        //    light = new THREE.SpotLight( 0xEAEAEA );
        //    light.position.set(-100, 200, 200);
        //    scene.add(light);        
        
        //自然光
        var ambientLight = new THREE.AmbientLight( 0xffffff );
        scene.add( ambientLight );
        
        //平行光源
        var directionalLight = new THREE.DirectionalLight( 0xffffff );
        directionalLight.position.set( 1, 0.75, 0.5 ).normalize();
        scene.add( directionalLight );
        
    }

    function drawline(p)
    {
        // 构造线段
        var lineGeometry = new THREE.Geometry();
        lineGeometry.vertices.push(new THREE.Vector3(p[0][0],p[0][1],p[0][2]));
        lineGeometry.vertices.push(new THREE.Vector3(p[1][0],p[1][1],p[1][2]));

        var lineMaterial = new THREE.LineDashedMaterial({ color : 0x9B3333 });
        var line = new THREE.Line(lineGeometry, lineMaterial);
        //line.computeLineDistances();    // 计算线条间的距离
        scene.add(line);    
    }
        
    function drawCircle(scene, meshMaterial, x,y,z,r,s,a1,a2)
    {
        var circle = new THREE.Mesh(new THREE.CircleGeometry(r, s, a1,a2), meshMaterial);
        //circle.translateOnAxis(axis,100)
        circle.translateX(x);
        circle.translateY(y);
        circle.translateZ(z);
        
        circle.rotateX(0);
        circle.rotateY(Math.PI/3);
        circle.rotateZ(0);
        
        scene.add(circle);
    }         
    
    function initContent() {
        var helperXZ = new THREE.GridHelper(1200, 120, 0x404040, 0x404040 );
        helperXZ.position.set( 600,0 ,600);
        scene.add(helperXZ);
        
        var helperXY = new THREE.GridHelper(1200, 120, 0x404040, 0x404040 );
        helperXY.position.set( 600,600,0 );
        helperXY.rotation.x = Math.PI/2;
        scene.add(helperXY);
        
        var helperYZ = new THREE.GridHelper(1200, 120, 0x404040, 0x404040 );
        helperYZ.position.set( 0,600,600 );
        helperYZ.rotation.z = Math.PI/2;
        scene.add(helperYZ);
        
        
        var axesHelper = new THREE.AxesHelper(1200);
        scene.add(axesHelper);
 
}   


//    radius:圆环半径
//    tube:管道半径
//    radialSegments:径向的分段数
//    tubularSegments:管的分段数,详见下图
//    arc:圆环面的弧度,缺省值为Math.PI * 2

    //创建一个球
    function TorusGeometry(x,y,z,radius, tube, radialSegments, tubularSegments, arc){
        var TorusGeo = new THREE.TorusGeometry(radius, tube, radialSegments, tubularSegments, arc);
        var sphereMat = new THREE.MeshLambertMaterial({//创建材料
            color:0x788085,
            wireframe:false
        });
        var TorusMesh = new THREE.Mesh(TorusGeo, sphereMat);//创建球体网格模型
        TorusMesh.position.set(x, y, z);//设置球的坐标
        //scene.add(sphereMesh);//将球体添加到场景
        return TorusMesh;
    }
    
    //创建一个球
    function sphere(x,y,z,r){
        var sphereGeo = new THREE.SphereGeometry(r, 40, 40);//创建球体 半径、经度、纬度
        var sphereMat = new THREE.MeshLambertMaterial({//创建材料
            color:0x0000FF,
            wireframe:false
        });
        var sphereMesh = new THREE.Mesh(sphereGeo, sphereMat);//创建球体网格模型
        sphereMesh.position.set(x, y, z);//设置球的坐标
        //scene.add(sphereMesh);//将球体添加到场景
        return sphereMesh;
    }
    
  
    //创建圆柱体
    function cylinder(x,y,z,r,l){
        //创建圆柱体,括号里的参数分别对应:顶圆半径、底圆半径、圆柱体高度、经度、纬度;
        var cylinderGeo = new THREE.CylinderGeometry(r, r ,l ,20 ,20);
        
//        console.log(r,l);
        
        //var texture = THREE.ImageUtils.loadTexture("img/5.jpg",null,function(t){});    //图片地址可使用本地,同根目录下文件夹即可 deprecated
        
        var cylinderMat = new THREE.MeshLambertMaterial({//创建材料
            //map:new THREE.TextureLoader().load("img/5.jpg"),
            color:0xFF6600,
            wireframe:false
        });
        
//        var cylinderMat = new THREE.MeshBasicMaterial({//创建材料
//            //map:new THREE.TextureLoader().load("img/0.jpg"),
//            //side: THREE.DoubleSide,
//            color: 0XFF7700,
//            wireframe:false
//        });
        
        //创建圆柱体网格模型
        var cylinderMesh = new THREE.Mesh(cylinderGeo, cylinderMat);
        cylinderMesh.position.set(x,y,z);//设置圆柱坐标

        cylinderMesh.rotation.x = Math.PI/2;
//        cylinderMesh.rotation.y = Math.PI/4;
//        cylinderMesh.rotation.z = Math.PI/6;
        
        //scene.add(cylinderMesh);//向场景添加圆柱体
        return cylinderMesh;
    }
        
     function initStats() {
        var stats = new Stats();

        stats.setMode(0);

        stats.domElement.style.position = 'absolute';
        stats.domElement.style.left = '0px';
        stats.domElement.style.top = '0px';

        document.body.appendChild(stats.domElement);
        return stats;
    }

    function update() {
        stats.update();
        controls.update();
        controls.handleResize();
    }

    function init() {
    
    
        initScene();
        initRenderer();
        initCamera();
        initLight();
        initControls();
        initContent();
        initStats();
     
        var X=300,Y=300,Z=200;
        var R=150,x,y,z;
        var p =[];
        var alfa;
        var group=[];
        var sph1;
        var sph2;
        var cyli;
        
        var MOBIUS = 0;            //莫比乌丝圈反转个数
        var BETA = Math.PI/6.0;    //沿中轴的倾斜角
        
        var Torus = TorusGeometry(X,Y,Z,R, 1, 20 , 360, Math.PI * 2);
        scene.add(Torus);

        for(var i=0;i<360;i=i+2)
        { 
            alfa = i*Math.PI/180.0;
            x = X + R * Math.cos(alfa);
            y = Y + R * Math.sin(alfa);
            
            z = Z ;
            
            //    if(i<180)
            //        z=Z*i/360
            //    else
            //        z=Z*(360-i)/360
            
    //        drawline(p[i]);
            //console.log(i,x,y,z,alfa);

            group = new THREE.Group();
        
            sph1 = sphere    (0,0,0+60, 3);
            sph2 = sphere    (0,0,0-60, 3);
            cyli = cylinder    (0,0,0,       2,120    );

            group.add(sph1  );
            group.add(sph2  );
            group.add(cyli  );

            group.rotateOnAxis(new THREE.Vector3(-1*Math.sin(alfa), 1*Math.cos(alfa),0), alfa*MOBIUS/2+BETA);
            group.position.set(x,y,z);

            scene.add(group);
            
        }
    }

    function animate() {
        requestAnimationFrame(animate);
        renderer.render(scene, camera);
        update();
    }
    init();
    animate(); 
</script>
</body>
</html>

这篇关于three.js实现的莫比乌丝圈的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/830710

相关文章

基于C++的UDP网络通信系统设计与实现详解

《基于C++的UDP网络通信系统设计与实现详解》在网络编程领域,UDP作为一种无连接的传输层协议,以其高效、低延迟的特性在实时性要求高的应用场景中占据重要地位,下面我们就来看看如何从零开始构建一个完整... 目录前言一、UDP服务器UdpServer.hpp1.1 基本框架设计1.2 初始化函数Init详解

Java中Map的五种遍历方式实现与对比

《Java中Map的五种遍历方式实现与对比》其实Map遍历藏着多种玩法,有的优雅简洁,有的性能拉满,今天咱们盘一盘这些进阶偏基础的遍历方式,告别重复又臃肿的代码,感兴趣的小伙伴可以了解下... 目录一、先搞懂:Map遍历的核心目标二、几种遍历方式的对比1. 传统EntrySet遍历(最通用)2. Lambd

springboot+redis实现订单过期(超时取消)功能的方法详解

《springboot+redis实现订单过期(超时取消)功能的方法详解》在SpringBoot中使用Redis实现订单过期(超时取消)功能,有多种成熟方案,本文为大家整理了几个详细方法,文中的示例代... 目录一、Redis键过期回调方案(推荐)1. 配置Redis监听器2. 监听键过期事件3. Redi

SpringBoot全局异常拦截与自定义错误页面实现过程解读

《SpringBoot全局异常拦截与自定义错误页面实现过程解读》本文介绍了SpringBoot中全局异常拦截与自定义错误页面的实现方法,包括异常的分类、SpringBoot默认异常处理机制、全局异常拦... 目录一、引言二、Spring Boot异常处理基础2.1 异常的分类2.2 Spring Boot默

基于SpringBoot实现分布式锁的三种方法

《基于SpringBoot实现分布式锁的三种方法》这篇文章主要为大家详细介绍了基于SpringBoot实现分布式锁的三种方法,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 目录一、基于Redis原生命令实现分布式锁1. 基础版Redis分布式锁2. 可重入锁实现二、使用Redisso

SpringBoo WebFlux+MongoDB实现非阻塞API过程

《SpringBooWebFlux+MongoDB实现非阻塞API过程》本文介绍了如何使用SpringBootWebFlux和MongoDB实现非阻塞API,通过响应式编程提高系统的吞吐量和响应性能... 目录一、引言二、响应式编程基础2.1 响应式编程概念2.2 响应式编程的优势2.3 响应式编程相关技术

C#实现将XML数据自动化地写入Excel文件

《C#实现将XML数据自动化地写入Excel文件》在现代企业级应用中,数据处理与报表生成是核心环节,本文将深入探讨如何利用C#和一款优秀的库,将XML数据自动化地写入Excel文件,有需要的小伙伴可以... 目录理解XML数据结构与Excel的对应关系引入高效工具:使用Spire.XLS for .NETC

Nginx更新SSL证书的实现步骤

《Nginx更新SSL证书的实现步骤》本文主要介绍了Nginx更新SSL证书的实现步骤,包括下载新证书、备份旧证书、配置新证书、验证配置及遇到问题时的解决方法,感兴趣的了解一下... 目录1 下载最新的SSL证书文件2 备份旧的SSL证书文件3 配置新证书4 验证配置5 遇到的http://www.cppc

Nginx之https证书配置实现

《Nginx之https证书配置实现》本文主要介绍了Nginx之https证书配置的实现示例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起... 目录背景介绍为什么不能部署在 IIS 或 NAT 设备上?具体实现证书获取nginx配置扩展结果验证

SpringBoot整合 Quartz实现定时推送实战指南

《SpringBoot整合Quartz实现定时推送实战指南》文章介绍了SpringBoot中使用Quartz动态定时任务和任务持久化实现多条不确定结束时间并提前N分钟推送的方案,本文结合实例代码给大... 目录前言一、Quartz 是什么?1、核心定位:解决什么问题?2、Quartz 核心组件二、使用步骤1