devwiki:three_js

Differences

This shows you the differences between two versions of the page.

Link to this comparison view

Both sides previous revision Previous revision
Next revision
Previous revision
Last revisionBoth sides next revision
devwiki:three_js [2022/06/13 19:00] – [Three.js Problem and Solution] yingdevwiki:three_js [2022/07/15 01:00] – [Quick Start] ying
Line 27: Line 27:
     * wave:     * wave:
       * https://1stwebdesigner.com/examples-of-three-js-in-action/       * https://1stwebdesigner.com/examples-of-three-js-in-action/
 +
 +====== Browse Support ======
 +
 +  * some feature using WebGL 2.0 and some old browser or some mobile browser may not support it,
 +  * you can use code to detect webgl2 support and dynamic change the way of coding to support other browser
 +    * webgl2 support browser tabel: https://caniuse.com/webgl2
 +
  
 ====== Tools ====== ====== Tools ======
Line 87: Line 94:
     side: THREE.DoubleSide     side: THREE.DoubleSide
     })      }) 
 +</code>
 +  * helper indicator <code javascript>
 +// axis
 +const main_axis = new THREE.AxesHelper()
 +scene.add(main_axis)
 +</code>
 +
 +**Events**
 +
 +  * mouse tracking <code javascript>
 +//# == add event: mouse position tracking
 +let mouse = {
 +    x: 0,
 +    y: 0
 +}
 +window.addEventListener('mousemove', (event)=>{
 +    //console.log(event.clientX) // from top left corner
 +    // top/left to center coordinate
 +    mouse.x = (event.clientX / output_size.width)*2-1
 +    mouse.y = -(event.clientY / output_size.height)*2+1
 +})
 +</code>
 +
 +  * double click full window <code javascript>
 +window.addEventListener('dblclick', ()=>{
 +    const full_screen_element = document.fullscreenElement || document.webkitFullscreenElement
 +    //output.requestFullScreen()
 +    if (!full_screen_element){
 +        if (output.requestFullscreen){
 +            // normal browse support
 +            output.requestFullscreen()
 +        } else if (output.webkitRequestFullscreen){
 +            // safari
 +            output.webkitRequestFullscreen()
 +        }
 +    }else{
 +        if (document.exitFullscreen){
 +            // normal browse support
 +            document.exitFullscreen()
 +        } else if (document.webkitExitFullscreen){
 +            // safari
 +            document.webkitExitFullscreen()
 +        }
 +    }
 +})
 +</code>
 +
 +  * simple key down event <code javascript>
 +const xSpeed = 0.1;
 +const ySpeed = 0.1;
 +
 +window.addEventListener("keydown", onDocumentKeyDown, false);
 +function onDocumentKeyDown(event) {
 +    const keyCode = event.which;
 +    console.log(keyCode)
 +    if (keyCode == 40) {
 +        boat_obj.position.z += ySpeed;
 +    } else if (keyCode == 38) {
 +        boat_obj.position.z -= ySpeed;
 +    } else if (keyCode == 37) {
 +        boat_obj.position.x -= xSpeed;
 +    } else if (keyCode == 39) {
 +        console.log('forward')
 +        boat_obj.position.x += xSpeed;
 +    } 
 +    else if (keyCode == 32) {
 +        boat_obj.position.set(0, 0, 0);
 +    }
 +};
 +</code>
 +  * extra offset key event for tick() <code javascript>
 +const offset_step = 0.02
 +
 +if ( keyboard.pressed("w") ){ 
 +    main_boat_offset.position.y -= offset_step 
 +    console.log(main_boat_offset.position.y)
 +}
 +if ( keyboard.pressed("s") ){ 
 +    main_boat_offset.position.y += offset_step
 +    console.log(main_boat_offset.position.y)
 +}
 +if ( keyboard.pressed("e") ){ 
 +    main_boat_offset.position.z -= offset_step
 +    console.log(main_boat_offset.position.z)
 +}
 +if ( keyboard.pressed("q") ){ 
 +    main_boat_offset.position.z += offset_step
 +    console.log(main_boat_offset.position.z)
 +}
 +if ( keyboard.pressed("d") ){ 
 +    main_boat_offset.position.x -= offset_step
 +    console.log(main_boat_offset.position.x)
 +}
 +if ( keyboard.pressed("a") ){ 
 +    main_boat_offset.position.x += offset_step 
 +    console.log(main_boat_offset.position.x)
 +}
 +
 +</code>
 +
 +**GUI**
 +
 +  * simple gui control <code javascript>
 +// -- gui
 +const gui = new dat.GUI({ closed:true, width: 300})
 +dat.GUI.toggleHide();
 +const global_ctrl = {
 +    boat: {
 +        x: 0,
 +        y: 0,
 +        z: 0,
 +        color:0x00ff00,
 +        slide: ()=>{
 +            let tl = gsap.timeline();
 +            const cur_x = green_box_mesh.position.x
 +            tl.to(green_box_mesh.position, {duration: 2, x: cur_x+2})
 +            .to(green_box_mesh.position, {duration: 1, x: cur_x})
 +        },
 +    }
 +}
 +
 +gui.add(global_ctrl.boat, 'x', -10, 10, 0.1).name('posX').onChange( ()=> {
 +    boat_obj.position.x = global_ctrl.boat.x
 +} )
 +gui.add(global_ctrl.boat, 'y', -10, 10, 0.1).name('posY').onChange( ()=> {
 +    boat_obj.position.y = global_ctrl.boat.y
 +} )
 +gui.add(global_ctrl.boat, 'z', -50, 50, 0.1).name('posZ').onChange( ()=> {
 +    boat_obj.position.z = global_ctrl.boat.z
 +} )
 +
 +gui.addColor(global_ctrl.boat, 'color').onChange(
 +    ()=>{
 +        green_box_mesh.material.color.set(global_ctrl.green_box.color)
 +    }
 +)
 +gui.add(global_ctrl.boat, 'slide')
 +</code>
 +
 +**font**
 +
 +  * text <code javascript>
 +//-- font 
 +const text_mat = new THREE.MeshMatcapMaterial({matcap:brown_mctex})
 +
 +let text_mesh = undefined
 +const main_fontLoader = new THREE.FontLoader(load_manager)
 +main_fontLoader.load(
 +    './font/helvetiker_regular.typeface.json',
 +    (result_font)=>{
 +        console.log('font loaded')
 +        const bevel_a = 0.01 //2
 +        const bevel_b = 0.01 //3
 +        const text_geo = new THREE.TextBufferGeometry(
 +            'Drive Through to Next Scene > ',{
 +                font: result_font,
 +                size: 0.2,
 +                height: .05,
 +                curveSegments: 3,
 +                // bevelEnabled: true,
 +                // bevelThickness: bevel_b,
 +                // bevelSize: bevel_a,
 +                // bevelOffset: 0, 
 +                // bevelSegments: 2
 +            }
 +        )
 +        text_geo.computeBoundingBox() // max3, min3
 +        text_geo.center()
 + 
 +        text_mesh = new THREE.Mesh(text_geo, white_2_mat) // text_mat
 +        text_mesh.position.y = 1
 +        text_mesh.position.x = 123
 +        scene.add(text_mesh)
 +    }
 +)
 </code> </code>
 ====== Three.js Problem and Solution====== ====== Three.js Problem and Solution======
Line 149: Line 331:
     * blend mode: alpha clip     * blend mode: alpha clip
     * and set roughness to 1     * and set roughness to 1
 +</code>
 +
 +  * set texture node filter and optionally disable mip map use<code javascript>
 +child.material.map.inFilter = THREE.NearestFilter
 +child.material.map.generateMipmaps = false
 +</code>
 +
 +  * make object ignore camera frustum culling, so that when camera move closer, object won't disappear <code javascript>
 +if(child.name.startsWith("sch_word_")){
 +    child.frustumCulled = false
 +}
 +</code>
 +
 +  * video as texture <code javascript>
 +// ref: https://stemkoski.github.io/Three.js/
 +// https://threejs.org/docs/#api/en/textures/VideoTexture
 +
 +// 1. define global variable for controls
 +let video = undefined
 +let videoImage = undefined
 +let videoImageContext = undefined
 +let videoTexture = undefined
 +let mov_mat = undefined
 +
 +// 2. (after all your model loaded event) create video material
 +video = document.createElement( 'video' );
 +video.src = "video/my_video.mp4";
 +video.load();
 +// video.play(); // (don't play on start)
 +videoImage = document.createElement( 'canvas' );
 +videoImage.width = 640;
 +videoImage.height = 480;
 +videoImageContext = videoImage.getContext( '2d' );
 +// background color if no video present
 +videoImageContext.fillStyle = '#000000';
 +videoImageContext.fillRect( 0, 0, videoImage.width, videoImage.height );
 +videoTexture = new THREE.Texture( videoImage );
 +videoTexture.minFilter = THREE.LinearFilter;
 +videoTexture.magFilter = THREE.LinearFilter;
 +mov_mat = new THREE.MeshBasicMaterial( { map: videoTexture, side:THREE.DoubleSide } ); // overdraw: true,
 +
 +// 3. assign to geo
 +my_video_plane_geo.material = mov_mat;
 +
 +// 4. call video_update() during render each frame
 +function video_update(){
 +    if ( video.readyState === video.HAVE_ENOUGH_DATA ) 
 +    {
 +        videoImageContext.drawImage( video, 0, 0 );
 +        if ( videoTexture ) 
 +            videoTexture.needsUpdate = true;
 +    }
 +}
 +
 +// 5. support functions for call from other event
 +function video_start(){
 +    //bgm_sound.pause(); // option to mute bgm sound if you have any
 +    video.currentTime = 0;
 +    video.play();
 +}
 +function video_stop(){
 +    //bgm_sound.play(); // option to on bgm sound if you have any
 +    video.pause();
 +    video.currentTime = 0;
 +}
 +</code>
 +
 +  * language based texture switch <code javascript>
 +// method 1: (works in firefox, not in chrome)
 +if(child.name == "lang_texture_geo") ){
 +    lang_texture_geo = child
 +    if(main_lang=="cn"){
 +        lang_texture_geo.material.map.image.src = "./img/cn_texture.jpg";
 +    }
 +}
 +// method 2: (works in both firefox and chrome)
 +const main_texLoader = new THREE.TextureLoader(load_manager)
 +const cn_text_ctex = main_texLoader.load("./img/cn_texture.jpg");
 +cn_text_ctex.flipY = false;
 +if(child.name == "lang_texture_geo") ){
 +    lang_texture_geo = child
 +    if(main_lang == "cn"){
 +        child.material.map = cn_text_ctex;
 +    }
 +}
 </code> </code>
 ====== Template ====== ====== Template ======
  • devwiki/three_js.txt
  • Last modified: 2022/07/17 11:49
  • by ying