0
点赞
收藏
分享

微信扫一扫

three.js简单实现一个3D三角函数学习理解

1.Three.js简介

Three.js是一个基于JavaScript编写的开源3D图形库,利用WebGL技术在网页上渲染3D图形。它提供了许多高级功能,如几何体、纹理、光照、阴影等,以便开发者能够快速地创建复杂且逼真的3D场景。同时,Three.js还具有很好的跨平台和跨浏览器兼容性,让用户无需安装任何插件就可以在现代浏览器上观看3D内容。

2.Three.js的历史

Three.js的发展始于2010年,由Ricardo Cabello(在线别名为mrdoob)创建。当时WebGL刚刚兴起,开发者们对于这项技术的应用充满了好奇和期待。Cabello希望为WebGL开发者提供一个简单易用的工具,因此Three.js应运而生。经过多年的发展和社区贡献,Three.js已经成为了最流行的3D图形库之一,拥有丰富的功能和庞大的用户群体。

3.Three.js可以做什么

3D游戏开发、3D效果展示、物联网3D可视化等等…

4.主要组件

在Three.js中,有了场景(scene)、相机(camera)和渲染器(renderer) 这3个组建才能将物体渲染到网页中去。

1)场景

场景是一个容器,可以看做摄影的房间,在房间中可以布置背景、摆放拍摄的物品、添加灯光设备等。

2)相机

相机是用来拍摄的工具,通过控制相机的位置和方向可以获取不同角度的图像。

3)渲染器

渲染器利用场景和相机进行渲染,渲染过程好比摄影师拍摄图像,如果只渲染一次就是静态的图像,如果连续渲染就能得到动态的画面。在JS中可以使用requestAnimationFrame实现高效的连续渲染。

我们运用以上的基础特性,实现这个3D三角函数,主要是为了方便学生直观的理解数学概念。

这个3D版本包含以下特性:

  1. 三维可视化系统
  • 三维坐标系显示(X:红,Y:绿,Z:蓝)
  • 半透明单位圆平面
  • 正弦波(蓝色)和余弦波(绿色)的三维轨迹
  1. 动态交互功能
  • 鼠标右键拖拽旋转视角
  • 自动旋转动画控制
  • 实时角度调节滑块
  1. 三维元素展示
  • 红色半径线在XY平面上的动态变化
  • 正弦波在XY平面的展开
  • 余弦波在XZ平面的展开

<!DOCTYPE html>
<html>
<head>
    <title>3D三角函数演示</title>
    <style>
        body { 
            margin: 0;
            overflow: hidden;
        }
        #info {
            position: absolute;
            top: 20px;
            left: 20px;
            background: rgba(255,255,255,0.9);
            padding: 15px;
            border-radius: 5px;
        }
        .controls {
            position: absolute;
            top: 20px;
            right: 20px;
            background: rgba(255,255,255,0.9);
            padding: 15px;
            border-radius: 5px;
        }
    </style>
</head>
<body>
    <div id="info">
        <div>θ: <span id="angleValue">0</span>°</div>
        <div>sinθ: <span id="sinValue">0</span></div>
        <div>cosθ: <span id="cosValue">1</span></div>
    </div>
    <div class="controls">
        <input type="range" id="angleSlider" min="0" max="360" value="0">
        <button id="animateBtn">播放</button>
    </div>

    <script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r128/three.min.js"></script>
    <script>
        let scene, camera, renderer;
        let radius = 3;
        let angle = 0;
        let isAnimating = false;
        
        // 初始化场景
        function init() {
            scene = new THREE.Scene();
            camera = new THREE.PerspectiveCamera(75, window.innerWidth/window.innerHeight, 0.1, 1000);
            renderer = new THREE.WebGLRenderer({ antialias: true });
            renderer.setSize(window.innerWidth, window.innerHeight);
            document.body.appendChild(renderer.domElement);

            // 设置相机位置
            camera.position.set(5, 5, 8);
            camera.lookAt(0, 0, 0);

            // 添加坐标系
            const axesHelper = new THREE.AxesHelper(5);
            scene.add(axesHelper);

            // 创建单位圆
            createUnitCircle();
            createSineWave();
            createCosineWave();
            
            // 添加交互控制
            addEventListeners();
            animate();
        }

        // 创建单位圆
        function createUnitCircle() {
            const geometry = new THREE.CircleGeometry(radius, 64);
            const material = new THREE.MeshBasicMaterial({ 
                color: 0x888888,
                transparent: true,
                opacity: 0.3
            });
            const circle = new THREE.Mesh(geometry, material);
            circle.rotation.x = -Math.PI/2;
            scene.add(circle);
        }

        // 创建正弦波轨迹
        function createSineWave() {
            const points = [];
            const material = new THREE.LineBasicMaterial({ color: 0x2194ce });
            
            for(let i = 0; i <= 360; i++) {
                const theta = THREE.MathUtils.degToRad(i);
                points.push(new THREE.Vector3(
                    radius * Math.cos(theta),
                    radius * Math.sin(theta),
                    0
                ));
            }
            
            const geometry = new THREE.BufferGeometry().setFromPoints(points);
            this.sineWave = new THREE.Line(geometry, material);
            scene.add(this.sineWave);
        }

        // 创建余弦波轨迹
        function createCosineWave() {
            const points = [];
            const material = new THREE.LineBasicMaterial({ color: 0x45c945 });
            
            for(let i = 0; i <= 360; i++) {
                const theta = THREE.MathUtils.degToRad(i);
                points.push(new THREE.Vector3(
                    radius * Math.cos(theta),
                    0,
                    radius * Math.sin(theta)
                ));
            }
            
            const geometry = new THREE.BufferGeometry().setFromPoints(points);
            this.cosineWave = new THREE.Line(geometry, material);
            scene.add(this.cosineWave);
        }

        // 更新三角函数可视化
        function updateVisuals() {
            const theta = THREE.MathUtils.degToRad(angle);
            const sin = Math.sin(theta);
            const cos = Math.cos(theta);

            // 更新半径线
            if(this.radiusLine) scene.remove(this.radiusLine);
            const radiusGeometry = new THREE.BufferGeometry().setFromPoints([
                new THREE.Vector3(0, 0, 0),
                new THREE.Vector3(radius*cos, radius*sin, 0)
            ]);
            this.radiusLine = new THREE.Line(
                radiusGeometry,
                new THREE.LineBasicMaterial({ color: 0xff4444 })
            );
            scene.add(this.radiusLine);

            // 更新数值显示
            document.getElementById('angleValue').textContent = angle.toFixed(0);
            document.getElementById('sinValue').textContent = sin.toFixed(3);
            document.getElementById('cosValue').textContent = cos.toFixed(3);
        }

        // 事件监听
        function addEventListeners() {
            // 角度滑块
            document.getElementById('angleSlider').addEventListener('input', (e) => {
                angle = e.target.value;
                updateVisuals();
            });

            // 动画按钮
            document.getElementById('animateBtn').addEventListener('click', () => {
                isAnimating = !isAnimating;
                e.target.textContent = isAnimating ? '暂停' : '播放';
            });

            // 窗口大小调整
            window.addEventListener('resize', () => {
                camera.aspect = window.innerWidth / window.innerHeight;
                camera.updateProjectionMatrix();
                renderer.setSize(window.innerWidth, window.innerHeight);
            });
        }

        // 动画循环
        function animate() {
            requestAnimationFrame(animate);
            
            if(isAnimating) {
                angle = (angle + 0.5) % 360;
                document.getElementById('angleSlider').value = angle;
                updateVisuals();
            }
            
            renderer.render(scene, camera);
        }

        init();
    </script>
</body>
</html>

我们也可以进一步增强

function addAdditionalFeatures() {
    // 1. 添加正切函数可视化
    const tanGeometry = new THREE.BufferGeometry();
    const tanPoints = [];
    for(let i = 0; i < 360; i+=0.5) {
        const theta = THREE.MathUtils.degToRad(i);
        tanPoints.push(new THREE.Vector3(
            Math.cos(theta),
            Math.tan(theta),
            Math.sin(theta)
        ));
    }
    tanGeometry.setFromPoints(tanPoints);
    const tanLine = new THREE.Line(
        tanGeometry,
        new THREE.LineBasicMaterial({ color: 0xffa500 })
    );
    scene.add(tanLine);

    // 2. 添加网格辅助平面
    const gridHelper = new THREE.GridHelper(10, 20);
    scene.add(gridHelper);

    // 3. 添加轨道控制器
    const controls = new THREE.OrbitControls(camera, renderer.domElement);
    controls.enableDamping = true;
    controls.dampingFactor = 0.05;
}

举报

相关推荐

0 条评论