threejs例子、解析与总结

前言

目前没有找到特别系统且免费threejs课程,现阶段看一下官方的demo和源码,官方的demo都是开源的,这点还不错。

然后还搜罗了基本大家推荐的书

《threejs入门指南》
https://www.ituring.com.cn/book/1272

例子一

实例
https://threejs.org/examples/#webgl_multiple_elements

源码解析:

import * as THREE from '../../node_modules/three/build/three.module.js'
import {
    
     OrbitControls } from '../../node_modules/three/examples/jsm/controls/OrbitControls.js';

let canvas, renderer;

const scenes = [];

init();
animate();

function init() {
    
    


    /*
        构建一个三维空间
            Three中称之为场景(Scene)选择一个观察点,并确定观察方向/角度等
            Three中称之为相机(Camera)在场景中添加供观察的物体
            Three中的物体有很多种,包括Mesh,Line,Points等,它们都继承自Object3D类将观察到的场景渲染到屏幕上的指定区域
            Three中使用Renderer完成这一工作
    */ 
    canvas = document.getElementById( "c" );

    const geometries = [
        //立方缓冲几何体
        new THREE.BoxBufferGeometry( 1, 1, 1 ),
        //球缓冲几何体
        new THREE.SphereBufferGeometry( 0.5, 12, 8 ),
        //十二面缓冲几何体
        new THREE.DodecahedronBufferGeometry( 0.5 ),
        //圆柱缓冲几何体
        new THREE.CylinderBufferGeometry( 0.5, 0.5, 1, 12 )
    ];

    const content = document.getElementById( 'content' );

    for ( let i = 0; i < 40; i ++ ) {
    
    
        //场景
        const scene = new THREE.Scene();

        // make a list item
        const element = document.createElement( 'div' );
        element.className = 'list-item';

        const sceneElement = document.createElement( 'div' );
        element.appendChild( sceneElement );

        const descriptionElement = document.createElement( 'div' );
        descriptionElement.innerText = 'Scene ' + ( i + 1 );
        element.appendChild( descriptionElement );

        // the element that represents the area we want to render the scene
        // console.log("scene:")
        // console.log(scene)
        scene.userData.element = sceneElement;
        content.appendChild( element );
        //透视相机
        const camera = new THREE.PerspectiveCamera( 50, 1, 1, 10 );
        camera.position.z = 2;
        scene.userData.camera = camera;
        //  Orbit controls(轨道控制器)可以使得相机围绕目标进行轨道运动
        const controls = new OrbitControls( scene.userData.camera, scene.userData.element );
        // console.log("controls:")
        // console.log(controls)
        controls.minDistance = 2;
        controls.maxDistance = 5;
        //摄像机平移
        controls.enablePan = true;
        //摄像机缩放
        controls.enableZoom = true;
        scene.userData.controls = controls;

        // add one random mesh to each scene
        //随机获取一个几何体
        const geometry = geometries[ geometries.length * Math.random() | 0 ];
        //规定材质  标准网格材质
        const material = new THREE.MeshStandardMaterial( {
    
    
            // 颜色
            color: new THREE.Color().setHSL( Math.random(), 1, 0.75 ),
            // 材质的粗糙程度
            roughness: 0.5,
            // 材质与金属的相似度,金属为1,非金属为0
            metalness: 0.5,
            flatShading: true

        } );

        scene.add( new THREE.Mesh( geometry, material ) );
        //半球光    HemisphereLight
        scene.add( new THREE.HemisphereLight( 0xaaaaaa, 0x444444 ) );
        //平行光    DirectionalLight
        const light = new THREE.DirectionalLight( 0xffffff, 0.5 );
        light.position.set( 1, 1, 1 );
        scene.add( light );
        //添加到scenes数组
        scenes.push( scene );

    }


    renderer = new THREE.WebGLRenderer( {
    
     canvas: canvas, antialias: true } );
    //设置颜色及其透明度
    renderer.setClearColor( 0xffffff, 1 );
    //设置设备像素比。通常用于避免HiDPI设备上绘图模糊
    renderer.setPixelRatio( window.devicePixelRatio );

}

function updateSize() {
    
    
    //页面大小改变时会改动这里,但是实时监听
    const width = canvas.clientWidth;
    const height = canvas.clientHeight;
    if ( canvas.width !== width || canvas.height !== height ) {
    
    

        renderer.setSize( width, height, false );

    }

}

function animate() {
    
    

    render();
    requestAnimationFrame( animate );

}

function render() {
    
    
    //更新renderer的大小尺寸
    updateSize();
    //使canvas与页面位置保持一致,下拉时更新
    canvas.style.transform = `translateY(${
      
      window.scrollY}px)`;

    renderer.setClearColor( 0xffffff );
    renderer.setScissorTest( false );
    //清除缓存
    renderer.clear();
    // 设置颜色及其透明度
    renderer.setClearColor( 0xfffffff );
    renderer.setScissorTest( true );

    scenes.forEach( function ( scene ) {
    
    

        // so something moves
        // scene.children[ 0 ].rotation.y = Date.now() * 0.001;

        // get the element that is a place holder for where we want to
        // draw the scene
        const element = scene.userData.element;

        // get its position relative to the page's viewport
        // getBoundingClientRect用于获取某个元素相对于视窗的位置集合
        const rect = element.getBoundingClientRect();

        // check if it's offscreen. If so skip it
        if ( rect.bottom < 0 || rect.top > renderer.domElement.clientHeight ||
                rect.right < 0 || rect.left > renderer.domElement.clientWidth ) {
    
    

            return; // it's off screen

        }

        // set the viewport
        const width = rect.right - rect.left;
        const height = rect.bottom - rect.top;
        const left = rect.left;
        const bottom = renderer.domElement.clientHeight - rect.bottom;

        renderer.setViewport( left, bottom, width, height );
        renderer.setScissor( left, bottom, width, height );

        const camera = scene.userData.camera;

        //camera.aspect = width / height; // not changing in this example
        //camera.updateProjectionMatrix();

        //scene.userData.controls.update();

        renderer.render( scene, camera );

    } );

}

猜你喜欢

转载自blog.csdn.net/lzl980111/article/details/112788113