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
devwiki:three_js [2022/06/13 19:15] – [Common Code] yingdevwiki:three_js [2022/07/17 11:49] (current) – [Browse Support] ying
Line 28: Line 28:
       * 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
 +
 +  * check webgl2 support <code javascript>
 +// check webgl2 support for multi sample version
 +const gl = document.createElement('canvas').getContext('webgl2');
 +if (!gl) {
 +  alert('your browser/OS/drivers do not support WebGL2');
 +  console.log('your browser/OS/drivers do not support WebGL2');
 +} else {
 +  console.log('webgl2 works!');
 +}
 +</code>
 ====== Tools ====== ====== Tools ======
  
Line 92: Line 108:
 const main_axis = new THREE.AxesHelper() const main_axis = new THREE.AxesHelper()
 scene.add(main_axis) 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 159: Line 345:
 child.material.map.inFilter = THREE.NearestFilter child.material.map.inFilter = THREE.NearestFilter
 child.material.map.generateMipmaps = false 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.1655147721.txt.gz
  • Last modified: 2022/06/13 19:15
  • by ying