Commit 6b88f019 by Иван Кубота

initial commit

parents
# 8th Wall Web Examples - three.js - Tap to place
This interactive example allows the user to grow trees on the ground by tapping. This showcases raycasting, instantiating objects, importing 3D models, and animation.
![tapplace-threejs-screenshot](../../../images/screenshot-tap.jpg)
[Try the live demo here](https://templates.8thwall.app/placeground-threejs)
## Overview
On 'touchstart' (when the user taps the screen), a THREE.Raycaster() is used to determine where the intersection with the ground (a transparent THREE.PlaneGeometry residing at a height of Y=0) occurs. THREE.GLTFLoader() is then used to load a .glb file and place it at the tap location on the ground. The model is instantiated with a random Y-rotation and the initial scale is set to a very small value. tween.js is then used to apply a scale-up animation to the model.
window.apearingChild = function(from, to) {
return function( child ){
var newMaterial = child.material.clone();
newMaterial.transparent = true;
newMaterial.onBeforeCompile = function( shader ){
shader.transparent = true;
shader.vertexShader = shader.vertexShader
.replace( `void main() {`, `varying vec4 vPosition;
void main() {
vPosition = modelMatrix * vec4(position, 1.0);` )
;
var Ffrom = from.toFixed(1),
Fto = to.toFixed(1),
Fdiff = (to-from).toFixed(1);
shader.fragmentShader = shader.fragmentShader.replace(
`uniform float`,
`
varying vec4 vPosition;
varying float noise;
uniform float`
).replace(
'#include <dithering_fragment>',
`#include <dithering_fragment>
float time = opacity;
vec4 pos = vPosition;
if(time<${Ffrom}){
gl_FragColor.a = 0.0;// *= sin(vUv.y*10.0+uTime)>0.5?1.0:0.0;
}else if(time >${Fto}){
gl_FragColor.a = 1.0;
}else{
vec3 color = mix(vec3(gl_FragColor), vec3(1.0,1.0,1.0), (${Fto}-time)/${Fdiff});
gl_FragColor = vec4( color.rgb, -pos.y/(time-372.0)*10.0 );
}
` );
}
child.material = newMaterial;
/*child.children[0].material = newMaterial*/
this.newMaterial = newMaterial;
}
}
window.initScene = function({scene, camera, renderer}){
const GLTFLoader = THREE.GLTFLoader;
const loader = new GLTFLoader();
Object.assign( camera.position, window.cameraPosition || {
x: -1.7743804661688403,
y: 1.1573565480428425,
z: -5.243816954496617
} );
Object.assign( camera.rotation, { x: -3.10768077311436387, y: -0.49165510718706528, z: -0.009893627612469875 } );
window.camera = camera
var mixers = [];
var clock;
var lines = [];
var mat1, sha1;
var cachedMaterials = {};
var version = false;
var GetMaterial = function( i ){
var lm = new MeshLineMaterial( {
"useMap": false,
"color": new THREE.Color( 0xffffee ),
"opacity": 0,
"resolution": {
"x": 1920,
"y": 1080
},
"sizeAttenuation": false,
"lineWidth": 15,
"depthWrite": false,
"depthTest": true,
"alphaTest": 0,
"transparent": true,
"side": THREE.DoubleSide
} );
if( version !== false )
lm.version = version;
version = lm.version;
return lm;
}
var LineFromVtx = function( vtx ){
var lineObj = {
lines: [],
points: [ [ 0, 0, 0 ], [ 1, 1, 1 ] ].flat(),
vtx: vtx
};
var i = 0.52;
var line = new MeshLine();
//line.setPoints( lineObj.points );
lineObj.lines.push( line )
var material = GetMaterial( i );
line.mesh = new THREE.Mesh( line, material )
line.mesh.line = line
line.opacity = 1 - i * 1.4;
line._opacity = line.mesh.material._opacity;
return lineObj;
}
var subScenes = [];
var inFps = 30, outFps = 30;
var keyMaterial;
var setLoopTime = function( time ){
time *= inFps;
var cfg = this.loopTimeCfg;
if( !cfg )
return this.setTime( time * outFps );
if( time < cfg.start ){
return this.setTime( 0 );
}else if( cfg.loop === false ){
time = Math.min( time, cfg.to - 0.001 );
}
time = ( ( ( time - cfg.start ) % ( cfg.to - cfg.from ) ) + cfg.from ) / outFps;
if( cfg.fn )
cfg.fn( time * outFps, this );
return this.setTime( time );
};
var sceneLines = [];
var loops = window.modelCfg;
loader.load(
window.modelFileName,
function( gltf ){
var subScene = gltf.scene.clone();
var group = new THREE.Group();
outer.group = group;
var notUsedAnimations = gltf.animations[ 0 ].clone(),
notUsedAnimationsHash = {};
notUsedAnimations.tracks.forEach( clip => notUsedAnimationsHash[ clip.name ] = clip );
if( window.childExtractor ){
subScene.children = window.childExtractor( subScene.children );
}
subScene.children = subScene.children.filter( ( child, n ) => {
var wLines = window.lines;
for( var key in wLines ){
if( child.name.indexOf( key ) === 0 ){
var lineScene = sceneLines[ key ];
if( !lineScene ){
sceneLines[ key ] = {
scene: gltf.scene.clone(),
lines: []
};
lineScene = sceneLines[ key ];
lineScene.scene.children.length = 0;
}
var lineObj = {
vtx: child,
line: LineFromVtx( child ),
points: []
};
lineObj.mixer = new THREE.AnimationMixer( lineScene.scene );
lineObj.mixer.setLoopTime = setLoopTime;
lineObj.mixer.loopTimeCfg = wLines[ key ];
lineScene.lines.push( lineObj );
return false;
}
}
if( child.name in window.objects ){
window.objects[ child.name ].name = child.name;
window.objects[ child.name ].obj = child;
if( !child ){
debugger
}
window.objects[ child.name ].fn( child, subScene );
}
return true;
} );
for( var key in sceneLines ){
var lineScene = sceneLines[ key ];
lineScene.lines.forEach( line => {
var child = line.vtx, lineObj = line;
lineScene.scene.add( line.line.vtx );
var trackStart = child.name + '.'
child.animations = [ gltf.animations[ 0 ].clone() ].map( a => {
a.tracks = a.tracks.filter( t => {
if( t.name.indexOf( trackStart ) === 0 ){
delete notUsedAnimationsHash[ t.name ]
return true;
}
return false;
} );
lineObj.mixer.clipAction( a ).play();
return a;
} )
line.line.lines.forEach( line => {
group.add( line.mesh );
} );
} );
}
subScene.mixer = new THREE.AnimationMixer( subScene );
notUsedAnimations.tracks = Object.values( notUsedAnimationsHash );
subScene.mixer.clipAction( notUsedAnimations ).play();
group.add( subScene );
scene.add(group);
scene.mixer = subScene.mixer;
clock = new THREE.Clock()
animate();
window.lateCB && window.lateCB();
} );
window.addEventListener( 'resize', () => {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize( window.innerWidth, window.innerHeight );
render();
}, false );
const stats = Stats();
document.body.appendChild( stats.dom );
var TIME = 0;
var animateScene = false;
var animate = function(){
var delta = clock.getDelta();
if(animateScene){
TIME += delta;
for( var key in window.lines ){
var lineScene = sceneLines[ key ];
for( var j = 0, _j = lineScene.lines.length; j < _j; j++ ){
var line = lineScene.lines[ j ];
var timeLength = line.vtx.scale.x * 1.5, interpolations = 40;
var _p = 0;
var linePoints = line.points,
lineVtxPosition = line.vtx.position;
for( var i = 0; i < interpolations; i++ ){
line.mixer.setLoopTime( TIME + timeLength / interpolations * i );
linePoints[ _p++ ] = lineVtxPosition.x;
linePoints[ _p++ ] = lineVtxPosition.y;
linePoints[ _p++ ] = lineVtxPosition.z;
}
var cfg = line.mixer.loopTimeCfg, time = TIME * inFps - cfg.start;
if( cfg.opacity ){
var children = line.line.lines,
opacity = time > cfg.opacity + cfg.start ? 1 : ( time - cfg.start < cfg.opacity - 90 ? 0 : 1 + ( time - cfg.opacity - cfg.start ) / 90 );
for( var i = 0, _i = children.length; i < _i; i++ ){
var child = children[ i ];
child._opacity.value = opacity * child.opacity;
}
}
for( var k = 0, _k = line.line.lines.length; k < _k; k++ ){
line.line.lines[ k ].setPoints( line.points );
}
line.mixer.setLoopTime( TIME );
}
}
scene.mixer.setTime( Math.min( TIME, window.sceneAnimationLength / inFps ) );
for( var i in window.objects ){
if( window.objects[ i ].step ){
window.objects[ i ].step( TIME * inFps )
}
}
}
requestAnimationFrame( animate );
/*controls.update();*/
//render();
stats.update();
};
function render(){
renderer.render( scene, camera );
}
var outer = {
show: function() {
animateScene = true;
},
setTime: function(time) {
TIME = time;
},
getTime: function() {
return TIME;
},
scene,
camera
};
return outer;
}
\ No newline at end of file
body {
overflow: hidden;
width: 100%;
height: 100%;
margin: -1px 0px 0px 0px !important;
padding: 0;
}
<!doctype html>
<html>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no">
<title>8th Wall Web: three.js</title>
<link rel="stylesheet" type="text/css" href="index.css">
<script src="./build/three.js"></script>
<script src="./js/controls/OrbitControls.js"></script>
<script src="./js/loaders/GLTFLoader.js"></script>
<script src="./js/libs/stats.min.js"></script>
<script src="./THREE.MeshLine.js"></script>
<script type="importmap">
{
"imports": {
"three": "./build/three.module.js",
"three/examples/jsm/controls/OrbitControls":"./jsm/controls/OrbitControls.js",
"three/examples/jsm/loaders/GLTFLoader":"./jsm/loaders/GLTFLoader.js",
"three/examples/jsm/libs/stats.module":"./jsm/libs/stats.module.js"
}
}
</script>
<!-- Javascript tweening engine -->
<script src="//cdnjs.cloudflare.com/ajax/libs/tween.js/16.3.5/Tween.min.js"></script>
<!-- XR Extras - provides utilities like load screen, almost there, and error handling.
See github.com/8thwall/web/tree/master/xrextras -->
<script src="//cdn.8thwall.com/web/xrextras/xrextras.js"></script>
<!-- 8thWall Web - Replace the app key here with your own app key -->
<script async src="//apps.8thwall.com/xrweb?appKey=klnDucOXOK7ZT5PAQR6JjXlAhABM7iBIvCwYLwPr66HcYAmklUYgMZush6qvISq89ixmlt"></script>
<!-- client code -->
<script>
var modelFileName = 'MainSceneKey.glb',
lines = {
/* 'Key': { from: 0, to: 500, start: 0, loop: false, fn: function(time, smth) {
/!*keyMaterial && (keyMaterial.opacity = time);*!/
/!*if(time<350){
coolMaterial.uniforms[ 'time' ].value = time;
smth._root.children[0].material = coolMaterial;
}else{
smth._root.children[0].material = keyMaterial;
}*!/
} },*/
'Point': { from: 0, to: 370, start: 0, loop: false, opacity: 30},
'Birdoak10':{ from: 0, to: 300, start: 0, opacity: 320 },
'Birdoak1_': { from: 0, to: 300, start: 100, opacity: 50000 },
'Birdoak2': { from: 0, to: 330, start: 0, opacity: 100 },
'Birdoak3': { from: 0, to: 300, start: 92220, opacity: 50 },
'Birdoak4': { from: 0, to: 300, start: 22260, opacity: 30 },
'Birdoak5': { from: 0, to: 300, start: 0, opacity: 460 },
'Birdoak6': { from: 0, to: 300, start: 10440, opacity: 5000 },
'Birdoak7': { from: 0, to: 300, start: 83330, opacity: 18000 },
'Birdloak8': { from: 0, to: 330, start: 51110, opacity: 133310 },
'Birdoak9': { from: 0, to: 300, start: 0, opacity: 65000 },
},
objects = {
'KeyLP001': {
step: function(time) {
if(!this.newMaterial)
return;
this.newMaterial.opacity = time;
this.obj.material.opacity = time;
//this.obj.children[0].material.opacity = time;
},
fn: function(child) {
this.fn = apearingChild(272,370);
this.fn(child)
}
}
},
sceneAnimationLength = 480;
var sceneItems = ['Key','Point','Birdoak1','Birdoak2','Birdoak3','Birdoak4','Birdoak5','Birdoak6','Birdoak7','Birdoak8','Birdoak9','Birdoak10'];
</script>
<script type="module" src="client5.js"></script>
<script src="index.js"></script>
<style>
#distance {
text-align: right;
position: absolute;
right: 0;
background: rgba(0,0,0,0.5);
color: #fff;
padding: 6px 8px;
font-family: monospace;
}
</style>
</head>
<body>
<canvas id="camerafeed"></canvas>
<div id="distance"></div>
</body>
</html>
This diff is collapsed. Click to expand it.
File added
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment