Differences
This shows you the differences between two versions of the page.
Both sides previous revision Previous revision Next revision | Previous revisionLast revisionBoth sides next revision | ||
devwiki:three_js [2022/06/13 19:00] – [Three.js Problem and Solution] ying | devwiki:three_js [2022/07/15 01:00] – [Quick Start] ying | ||
---|---|---|---|
Line 27: | Line 27: | ||
* wave: | * wave: | ||
* https:// | * https:// | ||
+ | |||
+ | ====== 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:// | ||
+ | |||
====== Tools ====== | ====== Tools ====== | ||
Line 87: | Line 94: | ||
side: THREE.DoubleSide | side: THREE.DoubleSide | ||
}) | }) | ||
+ | </ | ||
+ | * helper indicator <code javascript> | ||
+ | // axis | ||
+ | const main_axis = new THREE.AxesHelper() | ||
+ | scene.add(main_axis) | ||
+ | </ | ||
+ | |||
+ | **Events** | ||
+ | |||
+ | * mouse tracking <code javascript> | ||
+ | //# == add event: mouse position tracking | ||
+ | let mouse = { | ||
+ | x: 0, | ||
+ | y: 0 | ||
+ | } | ||
+ | window.addEventListener(' | ||
+ | // | ||
+ | // top/left to center coordinate | ||
+ | mouse.x = (event.clientX / output_size.width)*2-1 | ||
+ | mouse.y = -(event.clientY / output_size.height)*2+1 | ||
+ | }) | ||
+ | </ | ||
+ | |||
+ | * double click full window <code javascript> | ||
+ | window.addEventListener(' | ||
+ | const full_screen_element = document.fullscreenElement || document.webkitFullscreenElement | ||
+ | // | ||
+ | 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() | ||
+ | } | ||
+ | } | ||
+ | }) | ||
+ | </ | ||
+ | |||
+ | * simple key down event <code javascript> | ||
+ | const xSpeed = 0.1; | ||
+ | const ySpeed = 0.1; | ||
+ | |||
+ | window.addEventListener(" | ||
+ | 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(' | ||
+ | boat_obj.position.x += xSpeed; | ||
+ | } | ||
+ | else if (keyCode == 32) { | ||
+ | boat_obj.position.set(0, | ||
+ | } | ||
+ | }; | ||
+ | </ | ||
+ | * extra offset key event for tick() <code javascript> | ||
+ | const offset_step = 0.02 | ||
+ | |||
+ | if ( keyboard.pressed(" | ||
+ | main_boat_offset.position.y -= offset_step | ||
+ | console.log(main_boat_offset.position.y) | ||
+ | } | ||
+ | if ( keyboard.pressed(" | ||
+ | main_boat_offset.position.y += offset_step | ||
+ | console.log(main_boat_offset.position.y) | ||
+ | } | ||
+ | if ( keyboard.pressed(" | ||
+ | main_boat_offset.position.z -= offset_step | ||
+ | console.log(main_boat_offset.position.z) | ||
+ | } | ||
+ | if ( keyboard.pressed(" | ||
+ | main_boat_offset.position.z += offset_step | ||
+ | console.log(main_boat_offset.position.z) | ||
+ | } | ||
+ | if ( keyboard.pressed(" | ||
+ | main_boat_offset.position.x -= offset_step | ||
+ | console.log(main_boat_offset.position.x) | ||
+ | } | ||
+ | if ( keyboard.pressed(" | ||
+ | main_boat_offset.position.x += offset_step | ||
+ | console.log(main_boat_offset.position.x) | ||
+ | } | ||
+ | |||
+ | </ | ||
+ | |||
+ | **GUI** | ||
+ | |||
+ | * simple gui control <code javascript> | ||
+ | // -- gui | ||
+ | const gui = new dat.GUI({ closed: | ||
+ | dat.GUI.toggleHide(); | ||
+ | const global_ctrl = { | ||
+ | boat: { | ||
+ | x: 0, | ||
+ | y: 0, | ||
+ | z: 0, | ||
+ | color: | ||
+ | slide: ()=>{ | ||
+ | let tl = gsap.timeline(); | ||
+ | const cur_x = green_box_mesh.position.x | ||
+ | tl.to(green_box_mesh.position, | ||
+ | .to(green_box_mesh.position, | ||
+ | }, | ||
+ | } | ||
+ | } | ||
+ | |||
+ | gui.add(global_ctrl.boat, | ||
+ | boat_obj.position.x = global_ctrl.boat.x | ||
+ | } ) | ||
+ | gui.add(global_ctrl.boat, | ||
+ | boat_obj.position.y = global_ctrl.boat.y | ||
+ | } ) | ||
+ | gui.add(global_ctrl.boat, | ||
+ | boat_obj.position.z = global_ctrl.boat.z | ||
+ | } ) | ||
+ | |||
+ | gui.addColor(global_ctrl.boat, | ||
+ | ()=>{ | ||
+ | green_box_mesh.material.color.set(global_ctrl.green_box.color) | ||
+ | } | ||
+ | ) | ||
+ | gui.add(global_ctrl.boat, | ||
+ | </ | ||
+ | |||
+ | **font** | ||
+ | |||
+ | * text <code javascript> | ||
+ | //-- font | ||
+ | const text_mat = new THREE.MeshMatcapMaterial({matcap: | ||
+ | |||
+ | let text_mesh = undefined | ||
+ | const main_fontLoader = new THREE.FontLoader(load_manager) | ||
+ | main_fontLoader.load( | ||
+ | ' | ||
+ | (result_font)=> | ||
+ | console.log(' | ||
+ | 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: | ||
+ | // bevelEnabled: | ||
+ | // bevelThickness: | ||
+ | // bevelSize: bevel_a, | ||
+ | // bevelOffset: | ||
+ | // bevelSegments: | ||
+ | } | ||
+ | ) | ||
+ | text_geo.computeBoundingBox() // max3, min3 | ||
+ | text_geo.center() | ||
+ | |||
+ | text_mesh = new THREE.Mesh(text_geo, | ||
+ | text_mesh.position.y = 1 | ||
+ | text_mesh.position.x = 123 | ||
+ | scene.add(text_mesh) | ||
+ | } | ||
+ | ) | ||
</ | </ | ||
====== 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 | ||
+ | </ | ||
+ | |||
+ | * set texture node filter and optionally disable mip map use<code javascript> | ||
+ | child.material.map.inFilter = THREE.NearestFilter | ||
+ | child.material.map.generateMipmaps = false | ||
+ | </ | ||
+ | |||
+ | * make object ignore camera frustum culling, so that when camera move closer, object won't disappear <code javascript> | ||
+ | if(child.name.startsWith(" | ||
+ | child.frustumCulled = false | ||
+ | } | ||
+ | </ | ||
+ | |||
+ | * video as texture <code javascript> | ||
+ | // ref: https:// | ||
+ | // https:// | ||
+ | |||
+ | // 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.src = " | ||
+ | video.load(); | ||
+ | // video.play(); | ||
+ | videoImage = document.createElement( ' | ||
+ | videoImage.width = 640; | ||
+ | videoImage.height = 480; | ||
+ | videoImageContext = videoImage.getContext( ' | ||
+ | // background color if no video present | ||
+ | videoImageContext.fillStyle = '# | ||
+ | videoImageContext.fillRect( 0, 0, videoImage.width, | ||
+ | videoTexture = new THREE.Texture( videoImage ); | ||
+ | videoTexture.minFilter = THREE.LinearFilter; | ||
+ | videoTexture.magFilter = THREE.LinearFilter; | ||
+ | mov_mat = new THREE.MeshBasicMaterial( { map: videoTexture, | ||
+ | |||
+ | // 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(){ | ||
+ | // | ||
+ | video.currentTime = 0; | ||
+ | video.play(); | ||
+ | } | ||
+ | function video_stop(){ | ||
+ | // | ||
+ | video.pause(); | ||
+ | video.currentTime = 0; | ||
+ | } | ||
+ | </ | ||
+ | |||
+ | * language based texture switch <code javascript> | ||
+ | // method 1: (works in firefox, not in chrome) | ||
+ | if(child.name == " | ||
+ | lang_texture_geo = child | ||
+ | if(main_lang==" | ||
+ | lang_texture_geo.material.map.image.src = " | ||
+ | } | ||
+ | } | ||
+ | // method 2: (works in both firefox and chrome) | ||
+ | const main_texLoader = new THREE.TextureLoader(load_manager) | ||
+ | const cn_text_ctex = main_texLoader.load(" | ||
+ | cn_text_ctex.flipY = false; | ||
+ | if(child.name == " | ||
+ | lang_texture_geo = child | ||
+ | if(main_lang == " | ||
+ | child.material.map = cn_text_ctex; | ||
+ | } | ||
+ | } | ||
</ | </ | ||
====== Template ====== | ====== Template ====== |