eManagerNYC / 3D-Model-Viewer

va3c for wordpress
20 stars 13 forks source link

First Person Flight Controls #3

Open ibuilder opened 10 years ago

ibuilder commented 10 years ago

Add keyboard controls for flight, maybe:

http://webmaestro.fr/character-controls-three-js/

or

http://stackoverflow.com/questions/13261270/first-person-simulation-with-three-js-using-keyboard-arrows

ibuilder commented 9 years ago

This code handles keyboard controls

viewer.php

<?php 
/*
Plugin Name: 3d Model Viewer
Plugin URI: http://turneremanager.com
Description: Model viewer using three.js for CAD files
Author: Matthew M. Emma & Robert Carmosino
Version: 0.3
Author URI: http://www.turneremanager.com
Credits: va3c - http://va3c.github.io/
*/
/*-------------------------------------------------------*/
/* Enqueue scripts
/*-------------------------------------------------------*/
/*function modelscripts() {
  wp_register_script('Detector', plugins_url('assets/Detector.js', __FILE__), false);
  wp_register_script('Three', plugins_url('assets/three.min.js', __FILE__), false);
  wp_register_script('TrackballControls', plugins_url('assets/TrackballControls.js', __FILE__), false);
  wp_register_script('Stats', plugins_url('assets/stats.min.js', __FILE__), false);
  wp_register_script('jama-materials', plugins_url('assets/jama-materials.js', __FILE__), false);
  wp_register_script('jama-materials-data', plugins_url('assets/jama-materials-data.js', __FILE__), false);

  wp_enqueue_script('Detector');
  wp_enqueue_script('Three');
  wp_enqueue_script('TrackballControls');
  wp_enqueue_script('Stats');
  wp_enqueue_script('jama-materials');
  wp_enqueue_script('jama-materials-data');
}

if ( shortcode_exists( 'gallery' ) ) {
    add_action( 'wp_enqueue_scripts', 'modelscripts' );
}*/
/*-------------------------------------------------------*/
/* 3d Modelv viewer
/*-------------------------------------------------------*/
/*function ModelViewer( $atts ) {
  extract( shortcode_atts( array(
    'url' => plugins_url('assets/rac_basic_sample_project.rvt.js', __FILE__),
    'loc' => 'New York',
    'width' => '800',
    'height' => '600'
  ), $atts, 'model' ) );
*/

$width = 800;
$height = 600;
$url = 'assets/rac_basic_sample_project.rvt.js';

echo '

<!DOCTYPE html>
<html>
<head>
<title>Model Viewer</title>
<link rel="stylesheet" href="css/bootstrap.min.css" />
<link rel="stylesheet" href="css/font-awesome.min.css" />
<script src="js/jquery.1.10.2.min.js"></script>
<script src="js/bootstrap.min.js"></script>
<script src="assets/Detector.js"></script>
<script src="assets/three.min.js"></script>
<script src="assets/TrackballControls.js"></script>
<script src="assets/stats.min.js"></script>
<script src="assets/jama-materials.js"></script>
<script src="assets/jama-materials-data.js"></script>
<script src="js/Three.FirstPersonControls.js"></script>
</head>

<body>

<div id="threejs" style="position:relative; width:'.$width.'; height:'.$height.'; border:2px solid black">
    <div class="controls" style="background:#ccc; text-align:center; 
    font-weight:bold; padding:10px; 
    position:absolute; bottom:0; width:100%; zIndex:100">

        <div class="controls-left" style="float: left; width: 15%">
            <i class="fa fa-undo fa-2x"></i>
            <br /><strong>Rotate [Left Button]</strong>
        </div>

        <div class="controls-center" style="float: left; width: 15%">
            <i class="fa fa-search-plus fa-2x"></i>
            <br /><strong>Zoom [Mouse Wheel]</strong>
        </div>

        <div class="controls-right" style="float: left; width: 15%">
            <i class="fa fa-arrows fa-2x"></i>
            <br /><strong>Pan [Right Button]</strong>
        </div>

        <div class="controls-load" style="float: left; width: 25%">
            <button id="control-load" type="button" 
                class="btn btn-primary btn-lg" 
                onclick="loadFile(\''.$url.'\')">Load Model
            </button>

            <div class="progress" id="progress" style="visibility:hidden; display:none">
                <div class="progress-bar progress-bar-striped active" 
                id="progressbar" role="progressbar" 
                style="width: 0%">
                    <span class="sr-only">Loading</span>
                </div>
            </div>
        </div>

        <div class="controls-download" style="float: left; width: 30%">
            <a id="control-download" type="button" 
            class="btn btn-primary btn-lg" href="'.$url.'" download>
                Download Model
            </a>
        </div>
    </div>
</div>

<script>
var renderer, stats, scene, camera, controls;
var WIDTH = '.$width.',
    HEIGHT = '.$height.',
    ASPECT = '.$width.' / '.$height.',
    UNITSIZE = 250,
    MOVESPEED = 5000,
    LOOKSPEED = 0.035;
var t = THREE, scene, cam, renderer, controls, fcontrols, clock, projector, model, skin;
var runAnim = true, mouse = { x: 0, y: 0 };
var mx, mz, mlon, mlat;
var msearchz = msearchx = msearchlon = msearchlat = false;

$(document).ready(function(){
    init();
    animate();
});

function init() {
    clock = new t.Clock(); 
    projector = new t.Projector(); 
    scene = new t.Scene(); 

    var elem, geometry, material, mesh;
    if(!Detector.webgl){ renderer = new t.CanvasRenderer({alpha:1, antialias:true, clearColor:0xffffff}); }
    else{ renderer = new t.WebGLRenderer({alpha:1, antialias:true, clearColor:0xffffff}); }
    renderer.setSize( '.$width.', '.$height.' );
    renderer.shadowMapEnabled = true;

    stats = new Stats();
    stats.domElement.style.cssText = "position: absolute; right: 0; top: 0; zIndex: 100;";
    elem = document.getElementById( "threejs" );
    elem.appendChild( renderer.domElement );
    elem.appendChild( stats.domElement );

    camera = new t.PerspectiveCamera( 40, '.($width/$height).', 1, 100000 );
    camera.position.set( 20000, 5000, 20000 );

    //controls = new t.TrackballControls( camera, renderer.domElement );

    fcontrols = new t.FirstPersonControls(camera);
    fcontrols.movementSpeed = MOVESPEED;
    fcontrols.lookSpeed = LOOKSPEED;
    fcontrols.lookVertical = true; 
    fcontrols.noFly = false;
    fcontrols.lon = 225;
    //elem.appendChild(renderer.domElement);
    //elem.addEventListener( "mousemove", onDocumentMouseMove, false );

    light = new t.AmbientLight( 0x888888 ); 
    scene.add( light );
    light = new t.PointLight( 0xffffff, 0.5 );
    scene.add( light );
    light = new t.DirectionalLight( 0xffffff );
    light.position.set( 10000, 10000, 10000 ).normalize();
    scene.add( light );
}

function loadFile( file ) {
    renderer.setSize( document.getElementById("threejs").clientWidth, document.getElementById("threejs").clientHeight );
    document.getElementById("control-load").style.visibility = "hidden";
    document.getElementById("control-load").style.display = "none";
    document.getElementById("progress").style.removeProperty("visibility");
    document.getElementById("progress").style.removeProperty("display");

    var data = requestFile(file);
    document.getElementById("progressbar").style.width = "25%";

    data = JSON.parse(data);
    document.getElementById("progressbar").style.width = "50%";

    if(data.metadata===undefined){ data.metadata = { type: "Geometry" };} // 2.0
    if(data.metadata.type===undefined){ data.metadata.type = "Geometry";} // 3.0
    if(data.metadata.version===undefined){data.metadata.version = data.metadata.formatVersion;}

    if(data.metadata.type.toLowerCase()==="geometry"){
        console.log( "found geometry" );
        loader = new t.JSONLoader();
        contents = loader.parse( data );
        geometry = contents.geometry;

        if(contents.materials!==undefined){
        console.log( "found geometry", contents.materials );
            if(contents.materials.length>1){
                material=new t.MeshFaceMaterial( contents.materials );
            }else{ material=contents.materials[0]; }
        }else{
            material=JAMA.materials.NormalSmooth.set();
        }
        var mesh = new t.Mesh( geometry, material );
        document.getElementById("progressbar").style.width = "75%";
        scene.add( mesh );
        document.getElementById("progressbar").style.width = "100%";
    }else if(data.metadata.type.toLowerCase()==="object"){
        loader = new t.ObjectLoader();
        contents = loader.parse( data );
        document.getElementById("progressbar").style.width = "75%";
        if(contents instanceof t.Scene){
            console.log( "found scene" );
            scene.add( contents );
            document.getElementById("progressbar").style.width = "100%";
        }else{
            console.log( "found object", contents );
            scene.add( contents );
            document.getElementById("progressbar").style.width = "100%";
        }
    }else if(data.metadata.type.toLowerCase()==="scene"){
        console.log( "found deprecated");
        // DEPRECATED
        var loader = new t.SceneLoader();
        loader.load(bundle.src, function(contents){
            document.getElementById("progressbar").style.width = "75%";
            scene.add( contents );
            document.getElementById("progressbar").style.width = "100%";
        },"");
    }else{
        console.log( "found a whoopsie");
        document.getElementById("progressbar").style.width = "100%";
    }
}

function requestFile ( fname ) {
    var xmlhttp = new XMLHttpRequest();
    xmlhttp.crossOrigin = "Anonymous"; 
    xmlhttp.open( "GET", fname, false );
    xmlhttp.send( null );
    return xmlhttp.responseText;
}

function animate() {
    if(runAnim){ requestAnimationFrame(animate); }
    //controls.update();
    var delta = clock.getDelta(), speed = delta * MOVESPEED * 5;
    fcontrols.update(delta);
    renderer.render(scene, camera); 
}

function onDocumentMouseMove(e) {
    e.preventDefault();
    mouse.x = (e.clientX / WIDTH) * 2 - 1;
    mouse.y = - (e.clientY / HEIGHT) * 2 + 1;
}

var btnforward=false;
var btnleft=false;
var btnright=false;
var btnbackward=false;

function lookleft(){if(btnleft){myobject.mouseX=-(event.pageX-myobject.viewHalfX)} else {myobject.mouseX=false;}}
function gobackward(){if(btnbackward){myobject.moveBackward=true;}else{myobject.moveBackward=false;}}
function goforward(){if(btnforward){myobject.moveForward=true;}else{myobject.moveForward = false;}}
function lookright(){if(btnright){myobject.mouseX=event.pageX-myobject.viewHalfX}else{myobject.mouseX=false;}}
// Stop moving around when the window is unfocused (keeps my sanity!)
$(window).focus(function(){if (fcontrols) fcontrols.freeze = false;});
$(window).blur(function(){if (fcontrols) fcontrols.freeze = true;});

</script>

</body>
</html>
';

this is the javascript file Three.FirstPersonControls.js

var myobject = new Object(); 

THREE.FirstPersonControls = function ( object, domElement ) {
    this.object = object;
    this.target = new THREE.Vector3( 0, 0, 0 );
    this.domElement = ( domElement !== undefined ) ? domElement : document;
    this.movementSpeed = MOVESPEED;
    this.lookSpeed = LOOKSPEED;
    this.noFly = false;
    this.lookVertical = true;
    this.autoForward = false;
    // this.invertVertical = false;
    this.activeLook = true;
    this.clickMove = false;
    this.heightSpeed = false;
    this.heightCoef = 1.0;
    this.heightMin = -1;
    this.constrainVertical = false;
    this.verticalMin = 0;
    this.verticalMax = Math.PI;
    this.autoSpeedFactor = 0.0;
    this.mouseX = 0;
    this.mouseY = 0;

    this.lat = 0;
    this.lon = 0;
    this.phi = 0;
    this.theta = 0;

    this.moveForward = false;
    this.moveBackward = false;
    this.moveLeft = false;
    this.moveRight = false;
    this.freeze = false;
    this.mouseDragOn = false;
    var mousemovement = false;

    if ( this.domElement === document ) {
        this.viewHalfX = window.innerWidth / 2;
        this.viewHalfY = window.innerHeight / 2;
    } else {
        this.viewHalfX = this.domElement.offsetWidth / 2;
        this.viewHalfY = this.domElement.offsetHeight / 2;
        this.domElement.setAttribute( 'tabindex', -1 );
    }

/*
    this.onMouseMove = function ( event ) {

        if ( mousemovement ) {
            if ( this.domElement === document ) {
                this.mouseX = event.pageX - this.viewHalfX;
                this.mouseY = event.pageY - this.viewHalfY;

        }   else {
                this.mouseX = event.pageX - this.domElement.offsetLeft - this.viewHalfX;
                this.mouseY = event.pageY - this.domElement.offsetTop - this.viewHalfY;

        }
    }

};

    this.onMouseDown = function ( event ) {
        var etype = $(event.target).prop("tagName");
        if(etype=="CANVAS"){
            switch ( event.button ) {
                case 0: mousemovement = true; break;
            }
        }
    }

    this.onMouseUp = function ( event ) {
        switch ( event.button ) {
            case 0: mousemovement = false; this. mouseX = false; this.mouseY = false; break;
        }
    }
    */
    this.onKeyDown = function ( event ) {
        switch( event.keyCode ) {
            case 38: /*up*/ this.moveForward = true; break;
            //case 87: /*W*/  this.mouseY = event.pageY - this.viewHalfY; break;
            case 37: /*left*/this.mouseX = event.pageX - this.viewHalfX; break;
            case 65: /*A*/ this.moveLeft = true; break;
            case 40: /*down*/ this.moveBackward = true; break;
            //case 83: /*S*/ this.mouseY = event.pageY + this.viewHalfY; break;
            case 39: /*right*/this.mouseX = this.mouseX = event.pageX + this.viewHalfX; break;
            case 68: /*D*/ this.moveRight = true; break;
            case 82: /*F*/ this.moveUp = true; break;
            case 70: /*R*/ this.moveDown = true; break;
            case 81: /*Q*/ this.freeze = !this.freeze; break;
        }
    };

    this.onKeyUp = function ( event ) {
        switch( event.keyCode ) {
            case 38: /*up*/ this.moveForward = false; break;
            //case 87: /*W*/  this.mouseY = false; break;
            case 37: /*left*/this.mouseX = false; break; 
            case 65: /*A*/ this.moveLeft = false; break;
            case 40: /*down*/ this.moveBackward = false; break;
            //case 83: /*S*/ this.mouseY = false; break;
            case 39: /*right*/this.mouseX = false; break; 
            case 68: /*D*/ this.moveRight = false; break;
            case 82: /*F*/ this.moveUp = false; break;
            case 70: /*R*/ this.moveDown = false; break;
        }
    };

    this.update = function( delta ) { 
        var actualMoveSpeed = 0;
        if ( this.freeze ) {  return;  } 
        else {
            if ( this.heightSpeed ) {
                var y = THREE.Math.clamp( this.object.position.y, this.heightMin, this.heightMax );
                var heightDelta = y - this.heightMin;
                this.autoSpeedFactor = delta * ( heightDelta * this.heightCoef );
            } else {
                this.autoSpeedFactor = 0.0;
            }
            actualMoveSpeed = delta * this.movementSpeed;

            var vx = this.object.position.x;
            var vy = this.object.position.y;
            var vz = this.object.position.z;

            //$("#listener").html(vx + "</br>" + vy + "</br>" + vz + "</br>" + this.lon + "</br>" + this.lat);

            if ( this.moveForward || ( this.autoForward && !this.moveBackward ) ) { 
                this.object.translateZ( - ( actualMoveSpeed + this.autoSpeedFactor ) );
                //this.object.position.y = 120;
                //if(vz < -1145 || vz > 1050 || vx < -1581 || vx > 1761){
                    /*this.object.translateZ( actualMoveSpeed + this.autoSpeedFactor )
                    if(vz < -1145) {this.object.position.z = -1144.9999;}
                    if(vz > 1050) {this.object.position.z = 1049.9999;}
                    if(vx < -1581) {this.object.position.x = -1580.9999;}
                    if(vx > 1761) {this.object.position.x = 1760.9999;}*/
                //}
            }

            if ( this.moveBackward || ( this.autoBackward && !this.moveBackward ) ) {
                this.object.translateZ(actualMoveSpeed + this.autoSpeedFactor);
                //this.object.position.y = 120;
                //if(vz < -1145 || vz > 1050 || vx < -1581 || vx > 1761){
                    /*this.object.translateZ(- (actualMoveSpeed + this.autoSpeedFactor ) );
                    if(vz < -1145) {this.object.position.z = -1144.9999;}
                    if(vz > 1050) {this.object.position.z = 1049.9999;}
                    if(vx < -1581) {this.object.position.x = -1580.9999;}
                    if(vx > 1761) {this.object.position.x = 1760.9999;}*/
                //}
            }

            if ( this.moveLeft || ( this.autoBackward && !this.moveBackward ) ) {
                this.object.translateX( - (actualMoveSpeed + this.autoSpeedFactor ) );
                //this.object.position.y = 120;
                //if(vz < -1145 || vz > 1050 || vx < -1581 || vx > 1761){
                    /*this.object.translateX( actualMoveSpeed + this.autoSpeedFactor )
                    if(vz < -1145) {this.object.position.z = -1144.9999;}
                    if(vz > 1050) {this.object.position.z = 1049.9999;}
                    if(vx < -1581) {this.object.position.x = -1580.9999;}
                    if(vx > 1761) {this.object.position.x = 1760.9999;} */
                //}
            }
            if ( this.moveRight ) {
                this.object.translateX( actualMoveSpeed + this.autoSpeedFactor );
                //this.object.position.y = 120;
                /*if(vz < -1145 || vz > 1050 || vx < -1581 || vx > 1761){
                    this.object.translateX(-(actualMoveSpeed + this.autoSpeedFactor) );
                    if(vz < -1145) {this.object.position.z = -1144.9999;}
                    if(vz > 1050) {this.object.position.z = 1049.9999;}
                    if(vx < -1581) {this.object.position.x = -1580.9999;}
                    if(vx > 1761) {this.object.position.x = 1760.9999;}
                }*/
            }

            if ( this.moveDown ) {
                this.object.translateY(-(actualMoveSpeed+this.autoSpeedFactor));
            }
            if ( this.moveUp ) {
                this.object.translateY((actualMoveSpeed+this.autoSpeedFactor));
            }

            if (msearchz) {
                if (this.object.position.z > mz) {
                    this.object.position.z += ( -1 * ( actualMoveSpeed + this.autoSpeedFactor ) );
                    if( this.object.position.z < mz){
                        this.object.position.z = mz;
                        msearchz = false;
                    }
                } else {
                    this.object.position.z += ( 1 * ( actualMoveSpeed + this.autoSpeedFactor ) );
                    if( this.object.position.z > mz) {
                        this.object.position.z = mz;
                        msearchz = false;
                    }
                }
            }
            if (msearchx) {
                if (this.object.position.x > mx) {
                    this.object.position.x += (-1 * ( actualMoveSpeed + this.autoSpeedFactor ) );
                    if( this.object.position.x < mx) {
                        this.object.position.x = mx;
                        msearchx = false;
                    }
                } else {
                    this.object.position.x += ( 1 * ( actualMoveSpeed + this.autoSpeedFactor ) );
                    if( this.object.position.x > mx) {
                        this.object.position.x = mx;
                        msearchx = false;
                    }
                }
            }
            if (this.lon > 360) {
                this.lon = this.lon - 360;
            } else if (this.lon < 0) {
                this.lon = 360 + this.lon;
            }

            if (msearchlon) {
                if (this.lon - mlon > 0) {
                    this.lon += ( -1.5 );
                    if (this.lon <= mlon) {
                        //alert("negative");
                        this.lon = mlon;
                        msearchlon = false;
                    }
                } else {
                    this.lon += ( 1.5 );
                    if (this.lon >= mlon) {
                        //alert("positive");
                        this.lon = mlon;
                        msearchlon = false;
                    }
                }
            }
            if (msearchlat) {
                if (this.lat > mlat) {
                    this.lat += ( -0.5 );
                    if (this.lat < mlat) {
                        this.lat = mlat;
                        msearchlat = false;
                    }
                } else {
                    this.lat += ( 0.5 );
                    if (this.lat > mlat) {
                        this.lat = mlat;
                        msearchlat = false;
                    }
                }
            }
            if (!this.noFly) {
                if ( this.moveUp ) {
                    this.object.translateY( actualMoveSpeed );
                }
                if ( this.moveDown ) {
                    this.object.translateY( - actualMoveSpeed );
                }
            }

            var actualLookSpeed = delta * this.lookSpeed;

            if ( !this.activeLook ) {

                actualLookSpeed = 0;

            }

            this.lon += this.mouseX * actualLookSpeed;
            if( this.lookVertical ) this.lat -= this.mouseY * actualLookSpeed; // * this.invertVertical?-1:1;

            this.lat = Math.max( - 85, Math.min( 85, this.lat ) );
            this.phi = ( 90 - this.lat ) * Math.PI / 180;
            this.theta = this.lon * Math.PI / 180;

            var targetPosition = this.target,
                position = this.object.position;

            targetPosition.x = position.x + 100 * Math.sin( this.phi ) * Math.cos( this.theta );
            targetPosition.y = position.y + 100 * Math.cos( this.phi );
            targetPosition.z = position.z + 100 * Math.sin( this.phi ) * Math.sin( this.theta );

        }

        var verticalLookRatio = 1;

        if ( this.constrainVertical ) {
            verticalLookRatio = Math.PI / ( this.verticalMax - this.verticalMin );
        }

        this.lon += this.mouseX * actualLookSpeed;
        if( this.lookVertical ) this.lat -= this.mouseY * actualLookSpeed * verticalLookRatio;

        this.lat = Math.max( - 85, Math.min( 85, this.lat ) );
        this.phi = ( 90 - this.lat ) * Math.PI / 180;
        this.theta = this.lon * Math.PI / 180;

        if ( this.constrainVertical ) {

            this.phi = THREE.Math.mapLinear( this.phi, 0, Math.PI, this.verticalMin, this.verticalMax );

        }

        var targetPosition = this.target,
            position = this.object.position;

        targetPosition.x = position.x + 100 * Math.sin( this.phi ) * Math.cos( this.theta );
        targetPosition.y = position.y + 100 * Math.cos( this.phi );
        targetPosition.z = position.z + 100 * Math.sin( this.phi ) * Math.sin( this.theta );

        myobject.object.lookAt ( targetPosition );
    };

    this.domElement.addEventListener( 'contextmenu', function ( event ) { event.preventDefault(); }, false );
    //this.domElement.addEventListener( 'mousemove', bind( this, this.onMouseMove ), false );
    //this.domElement.addEventListener( 'mousedown', bind( this, this.onMouseDown ), false );
    //this.domElement.addEventListener( 'mouseup', bind( this, this.onMouseUp ), false );
    this.domElement.addEventListener( 'keydown', bind( this, this.onKeyDown ), false );
    this.domElement.addEventListener( 'keyup', bind( this, this.onKeyUp ), false );

    function bind( scope, fn ) {
        return function(){
            fn.apply( scope, arguments );
        };
    };

    myobject = this;
};