diff --git a/gz3d/build/gz3d.js b/gz3d/build/gz3d.js
index 09b199b8296af9149d3443a8f89aa16395a6163d..38c6e53e7d24c2160dc5fc55983338ffa4bf07eb 100644
--- a/gz3d/build/gz3d.js
+++ b/gz3d/build/gz3d.js
@@ -1,5 +1,7 @@
var GZ3D = GZ3D || {
- REVISION : '1'
+ REVISION : '1',
+ assetsPath: 'http://localhost:8080/assets',
+ webSocketUrl: 'ws://localhost:7681'
};
/*global $:false */
@@ -9,7 +11,7 @@ var guiEvents = new EventEmitter2({ verbose: true });
var emUnits = function(value)
{
- return value*parseFloat($('body').css('font-size'));
+ return value*parseFloat($('#gz3d-body').css('font-size'));
};
var isTouchDevice = 'ontouchstart' in window || 'onmsgesturechange' in window;
@@ -29,160 +31,15 @@ var tabColors = {selected: 'rgb(34, 170, 221)', unselected: 'rgb(42, 42, 42)'};
var modelList =
[
- {path:'buildings', title:'Buildings',
- examplePath1:'fast_food', examplePath2:'kitchen_dining', examplePath3:'house_1', models:
+ {path:'virtual_room', title:'Virtual Room Objects',
+ examplePath1:'library_model', examplePath2:'hosta_potted_plant', examplePath3:'vr_lamp', models:
[
- {modelPath:'fast_food', modelTitle:'Fast Food'},
- {modelPath:'gas_station', modelTitle:'Gas Station'},
- {modelPath:'house_1', modelTitle:'House 1'},
- {modelPath:'house_2', modelTitle:'House 2'},
- {modelPath:'house_3', modelTitle:'House 3'},
- {modelPath:'iss', modelTitle:'International Space Station'},
- {modelPath:'iss_half', modelTitle:'ISS half'},
- {modelPath:'kitchen_dining', modelTitle:'Kitchen and Dining'},
- {modelPath:'office_building', modelTitle:'Office Building'},
- {modelPath:'powerplant', modelTitle:'Power Plant'},
- {modelPath:'starting_pen', modelTitle:'Starting Pen'},
- {modelPath:'willowgarage', modelTitle:'Willow Garage'}
- ]},
-
- {path:'furniture', title:'Furniture',
- examplePath1:'hinged_door', examplePath2:'bookshelf', examplePath3:'table', models:
- [
- {modelPath:'bookshelf', modelTitle:'Book Shelf'},
- {modelPath:'cabinet', modelTitle:'Cabinet'},
- {modelPath:'drc_practice_door_4x8', modelTitle:'4x8 Doorway'},
- {modelPath:'drc_practice_ladder', modelTitle:'Ladder'},
- {modelPath:'hinged_door', modelTitle:'Hinged Door'},
- {modelPath:'table', modelTitle:'Table'},
- {modelPath:'table_marble', modelTitle:'Table Marble'},
-
- {modelPath:'drc_practice_ball_valve', modelTitle:'Ball Valve'},
- {modelPath:'drc_practice_handle_wheel_valve', modelTitle:'Handle Wheel Valve'},
- {modelPath:'drc_practice_hand_wheel_valve', modelTitle:'Hand Wheel Valve'},
- {modelPath:'drc_practice_wheel_valve', modelTitle:'Wheel Valve'},
- {modelPath:'drc_practice_wheel_valve_large', modelTitle:'Wheel Valve Large'},
- {modelPath:'door_handle', modelTitle:'Door Handle'},
-
- {modelPath:'drc_practice_ball_valve_wall', modelTitle:'Wall (Ball Valve)'},
- {modelPath:'drc_practice_handle_wheel_valve_wall', modelTitle:'Wall (Handle Wheel Valve)'},
- {modelPath:'drc_practice_hand_wheel_valve_wall', modelTitle:'Wall (Hand Wheel Valve)'},
- {modelPath:'drc_practice_valve_wall', modelTitle:'Wall (Valve)'},
- {modelPath:'drc_practice_wheel_valve_wall', modelTitle:'Wall (Wheel Valve)'},
- {modelPath:'drc_practice_wheel_valve_large_wall', modelTitle:'Wall (Wheel Valve Large)'},
- {modelPath:'grey_wall', modelTitle:'Grey Wall'},
- {modelPath:'asphalt_plane', modelTitle:'Asphalt Plane'},
- {modelPath:'drc_practice_base_4x8', modelTitle:'Debris base'},
- {modelPath:'ground_plane', modelTitle:'Ground Plane'},
- {modelPath:'nist_maze_wall_120', modelTitle:'120 Maze Wall'},
- {modelPath:'nist_maze_wall_240', modelTitle:'240 Maze Wall'},
- {modelPath:'nist_maze_wall_triple_holes_120', modelTitle:'120 Maze Wall Triple Holes'},
- {modelPath:'nist_simple_ramp_120', modelTitle:'Simple Ramp'},
- {modelPath:'nist_stairs_120', modelTitle:'Stairs'}
- ]},
-
- {path:'kitchen', title:'Kitchen',
- examplePath1:'saucepan', examplePath2:'beer', examplePath3:'bowl', models:
- [
- {modelPath:'beer', modelTitle:'Beer'},
- {modelPath:'bowl', modelTitle:'Bowl'},
- {modelPath:'coke_can', modelTitle:'Coke Can'},
- {modelPath:'saucepan', modelTitle:'Saucepan'}
- ]},
-
- {path:'robocup', title:'Robocup', examplePath1:'robocup_3Dsim_ball',
- examplePath2:'robocup14_spl_goal', examplePath3:'robocup09_spl_field', models:
- [
- {modelPath:'robocup09_spl_field', modelTitle:'2009 SPL Field'},
- {modelPath:'robocup14_spl_field', modelTitle:'2014 SPL Field'},
- {modelPath:'robocup_3Dsim_field', modelTitle:'3D Sim. Field'},
- {modelPath:'robocup14_spl_goal', modelTitle:'SPL Goal'},
- {modelPath:'robocup_3Dsim_goal', modelTitle:'3D Sim. Goal'},
- {modelPath:'robocup_spl_ball', modelTitle:'SPL Ball'},
- {modelPath:'robocup_3Dsim_ball', modelTitle:'3D Sim. Ball'}
- ]},
-
- {path:'robots', title:'Robots',
- examplePath1:'pioneer3at', examplePath2:'turtlebot', examplePath3:'pr2', models:
- [
- {modelPath:'create', modelTitle:'Create'},
- {modelPath:'husky', modelTitle:'Husky'},
- {modelPath:'irobot_hand', modelTitle:'iRobot Hand'},
- {modelPath:'pioneer2dx', modelTitle:'Pioneer 2DX'},
- {modelPath:'pioneer3at', modelTitle:'Pioneer 3AT'},
- {modelPath:'pr2', modelTitle:'PR2'},
- {modelPath:'robonaut', modelTitle:'Robonaut'},
- {modelPath:'simple_arm', modelTitle:'Simple Arm'},
- {modelPath:'simple_arm_gripper', modelTitle:'Simple Arm and Gripper'},
- {modelPath:'simple_gripper', modelTitle:'Simple Gripper'},
- {modelPath:'turtlebot', modelTitle:'TurtleBot'},
- {modelPath:'youbot', modelTitle:'YouBot'}
- ]},
-
- {path:'sensors', title:'Sensors',
- examplePath1:'camera', examplePath2:'hokuyo', examplePath3:'kinect', models:
- [
- {modelPath:'camera', modelTitle:'Camera'},
- {modelPath:'stereo_camera', modelTitle:'Stereo Camera'},
- {modelPath:'hokuyo', modelTitle:'Hokuyo'},
- {modelPath:'kinect', modelTitle:'Kinect'}
- ]},
-
- {path:'street', title:'Street', examplePath1:'dumpster',
- examplePath2:'drc_practice_angled_barrier_45', examplePath3:'fire_hydrant', models:
- [
- {modelPath:'cinder_block', modelTitle:'Cinder Block'},
- {modelPath:'cinder_block_2', modelTitle:'Cinder Block 2'},
- {modelPath:'cinder_block_wide', modelTitle:'Cinder Block Wide'},
- {modelPath:'construction_barrel', modelTitle:'Construction Barrel'},
- {modelPath:'construction_cone', modelTitle:'Construction Cone'},
- {modelPath:'drc_practice_angled_barrier_45', modelTitle:'Angled Barrier 45'},
- {modelPath:'drc_practice_angled_barrier_135', modelTitle:'Angled Barrier 135'},
- {modelPath:'drc_practice_block_wall', modelTitle:'Block Wall'},
- {modelPath:'drc_practice_orange_jersey_barrier', modelTitle:'Jersey Barrier (Orange)'},
- {modelPath:'drc_practice_white_jersey_barrier', modelTitle:'Jersey Barrier (White)'},
- {modelPath:'drc_practice_truss', modelTitle:'Truss'},
- {modelPath:'drc_practice_yellow_parking_block', modelTitle:'Parking Block'},
- {modelPath:'dumpster', modelTitle:'Dumpster'},
- {modelPath:'fire_hydrant', modelTitle:'Fire Hydrant'},
- {modelPath:'jersey_barrier', modelTitle:'Jersey Barrier'},
- {modelPath:'lamp_post', modelTitle:'Lamp Post'},
- {modelPath:'mailbox', modelTitle:'Mailbox'},
- {modelPath:'mud_box', modelTitle:'Mud Box'},
- {modelPath:'nist_fiducial_barrel', modelTitle:'Fiducial Barrel'},
- {modelPath:'speed_limit_sign', modelTitle:'Speed Limit Sign'},
- {modelPath:'stop_sign', modelTitle:'Stop Sign'}
-
- ]},
-
- {path:'tools', title:'Tools', examplePath1:'hammer',
- examplePath2:'polaris_ranger_ev', examplePath3:'cordless_drill', models:
- [
- {modelPath:'cordless_drill', modelTitle:'Cordless Drill'},
- {modelPath:'fire_hose_long', modelTitle:'Fire Hose'},
- {modelPath:'fire_hose_long_curled', modelTitle:'Fire Hose Long Curled'},
- {modelPath:'hammer', modelTitle:'Hammer'},
- {modelPath:'monkey_wrench', modelTitle:'Monkey Wrench'},
- {modelPath:'polaris_ranger_ev', modelTitle:'Polaris Ranger EV'},
- {modelPath:'polaris_ranger_xp900', modelTitle:'Polaris Ranger XP900'},
- {modelPath:'polaris_ranger_xp900_no_roll_cage', modelTitle:'Polaris Ranger without roll cage'},
- {modelPath:'utility_cart', modelTitle:'Utility Cart'}
- ]},
-
- {path:'misc', title:'Misc.', examplePath1:'brick_box_3x1x3',
- examplePath2:'drc_practice_4x4x20', examplePath3:'double_pendulum_with_base', models:
- [
- {modelPath:'double_pendulum_with_base', modelTitle:'Double Pendulum With Base'},
- {modelPath:'breakable_test', modelTitle:'Breakable_test'},
- {modelPath:'brick_box_3x1x3', modelTitle:'Brick Box 3x1x3'},
- {modelPath:'cube_20k', modelTitle:'Cube 20k'},
- {modelPath:'drc_practice_2x4', modelTitle:'2x4 Lumber'},
- {modelPath:'drc_practice_2x6', modelTitle:'2x6 Lumber'},
- {modelPath:'drc_practice_4x4x20', modelTitle:'4x4x20 Lumber'},
- {modelPath:'drc_practice_4x4x40', modelTitle:'4x4x40 Lumber'},
- {modelPath:'drc_practice_blue_cylinder', modelTitle:'Blue Cylinder'},
- {modelPath:'drc_practice_wood_slats', modelTitle:'Wood Slats'},
- {modelPath:'nist_elevated_floor_120', modelTitle:'Elevated Floor 120'}
+ {modelPath:'library_model', modelTitle:'Library'},
+ {modelPath:'hosta_potted_plant', modelTitle:'Hosta Plant'},
+ {modelPath:'vr_lamp', modelTitle:'Stand Lamp'},
+ {modelPath:'vr_screen', modelTitle:'Virtual Screen'},
+ {modelPath:'viz_poster', modelTitle:'Poster 1'},
+ {modelPath:'viz_poster_2', modelTitle:'Poster 2'}
]}
];
@@ -191,7 +48,7 @@ $(function()
//Initialize
if ('ontouchstart' in window || 'onmsgesturechange' in window)
{
- $('body').addClass('isTouchDevice');
+ $('#gz3d-body').addClass('isTouchDevice');
}
// Toggle items
@@ -491,6 +348,14 @@ $(function()
guiEvents.emit('show_orbit_indicator');
guiEvents.emit('closeTabs', false);
});
+ $('#view-shadows').click(function()
+ {
+ guiEvents.emit('show_shadows', 'toggle');
+ });
+ $('#view-camera-sensors').click(function()
+ {
+ guiEvents.emit('show_camera_sensors', 'toggle');
+ });
$( '#snap-to-grid' ).click(function() {
guiEvents.emit('snap_to_grid');
guiEvents.emit('closeTabs', false);
@@ -505,13 +370,12 @@ $(function()
});
// Disable Esc key to close panel
- $('body').on('keyup', function(event)
- {
- if (event.which === 27)
- {
- return false;
- }
- });
+ $('#gz3d-body').on('keyup', function(event) {
+ if (event.which === 27)
+ {
+ return false;
+ }
+ });
// Object menu
$( '#view-transparent' ).click(function() {
@@ -839,6 +703,73 @@ GZ3D.Gui.prototype.init = function()
}
);
+ guiEvents.on('show_shadows', function(option)
+ {
+ if (option === 'show')
+ {
+ //that.emitter.emit('setShadows', true);
+ that.scene.setShadowMaps(true);
+ }
+ else if (option === 'hide')
+ {
+ //that.emitter.emit('setShadows', false);
+ that.scene.setShadowMaps(false);
+ }
+ else if (option === 'toggle')
+ {
+ var shadowsEnabled = that.scene.renderer.shadowMapEnabled;
+ //that.emitter.emit('setShadows', !shadowsEnabled);
+ that.scene.setShadowMaps(!shadowsEnabled);
+ }
+
+ if(!that.scene.renderer.shadowMapEnabled)
+ {
+ $('#view-shadows').buttonMarkup({icon: 'false'});
+ guiEvents.emit('notification_popup','Disabling shadows');
+ }
+ else
+ {
+ $('#view-shadows').buttonMarkup({icon: 'check'});
+ guiEvents.emit('notification_popup','Enabling shadows');
+ }
+ }
+ );
+
+ guiEvents.on('show_camera_sensors', function(option)
+ {
+ var camerasShown = false;
+ if (option === 'show')
+ {
+ that.scene.viewManager.showCameras(true);
+ }
+ else if (option === 'hide')
+ {
+ that.scene.viewManager.showCameras(false);
+ }
+ else if (option === 'toggle')
+ {
+ if (that.scene.viewManager.views.length > 1) {
+ camerasShown = that.scene.viewManager.views[1].active;
+ that.scene.viewManager.showCameras(!camerasShown);
+ }
+ }
+
+ if (that.scene.viewManager.views.length > 1) {
+ camerasShown = that.scene.viewManager.views[1].active;
+ }
+ if(!camerasShown)
+ {
+ $('#view-camera-sensors').buttonMarkup({icon: 'false'});
+ guiEvents.emit('notification_popup','Disabling camera views');
+ }
+ else
+ {
+ $('#view-camera-sensors').buttonMarkup({icon: 'check'});
+ guiEvents.emit('notification_popup','Enabling camera views');
+ }
+ }
+ );
+
guiEvents.on('pause', function(paused)
{
that.emitter.emit('pause', paused);
@@ -1081,7 +1012,7 @@ GZ3D.Gui.prototype.init = function()
$( '#notification-popup' ).html(' '+notification+' ');
$( '#notification-popup' ).popup('open', {
y:window.innerHeight-50});
-
+
if (duration === undefined)
{
duration = 2000;
@@ -1140,7 +1071,8 @@ GZ3D.Gui.prototype.init = function()
lastOpenMenu[parentId] = id;
$('.leftPanels').hide();
- $('#'+id).show();
+ //$('#'+id).show(); //defaults as flex, but block is needed
+ $('#'+id).css('display','block');
$('.tab').css('border-left-color', tabColors.unselected);
$('#'+parentId+'Tab').css('border-left-color', tabColors.selected);
@@ -1609,17 +1541,20 @@ GZ3D.Gui.prototype.setModelStats = function(stats, action)
return e.shortName === LinkShortName;
});
- if (link[0].self_collide)
- {
- link[0].self_collide = this.trueOrFalse(stats.link[0].self_collide);
- }
- if (link[0].gravity)
+ if (link[0])
{
- link[0].gravity = this.trueOrFalse(stats.link[0].gravity);
- }
- if (link[0].kinematic)
- {
- link[0].kinematic = this.trueOrFalse(stats.link[0].kinematic);
+ if (link[0].self_collide)
+ {
+ link[0].self_collide = this.trueOrFalse(stats.link[0].self_collide);
+ }
+ if (link[0].gravity)
+ {
+ link[0].gravity = this.trueOrFalse(stats.link[0].gravity);
+ }
+ if (link[0].kinematic)
+ {
+ link[0].kinematic = this.trueOrFalse(stats.link[0].kinematic);
+ }
}
}
@@ -1696,10 +1631,10 @@ GZ3D.Gui.prototype.setLightStats = function(stats, action)
var thumbnail;
switch(type)
{
- case 2:
+ case GZ3D.LIGHT_SPOT:
thumbnail = 'style/images/spotlight.png';
break;
- case 3:
+ case GZ3D.LIGHT_DIRECTIONAL:
thumbnail = 'style/images/directionallight.png';
break;
default:
@@ -1801,7 +1736,10 @@ GZ3D.Gui.prototype.findModelThumbnail = function(instanceName)
GZ3D.Gui.prototype.updateStats = function()
{
var tree = angular.element($('#treeMenu')).scope();
- tree.updateStats();
+ if (typeof(tree) !== 'undefined' && typeof tree.updateStats !== 'undefined')
+ {
+ tree.updateStats();
+ }
};
/**
@@ -1926,10 +1864,12 @@ GZ3D.Gui.prototype.formatStats = function(stats)
colorHex = {};
for (comp in diffuse)
{
- colorHex[comp] = diffuse[comp].toString(16);
- if (colorHex[comp].length === 1)
- {
- colorHex[comp] = '0' + colorHex[comp];
+ if (diffuse.hasOwnProperty(comp)) {
+ colorHex[comp] = diffuse[comp].toString(16);
+ if (colorHex[comp].length === 1)
+ {
+ colorHex[comp] = '0' + colorHex[comp];
+ }
}
}
color.diffuse = '#' + colorHex['r'] + colorHex['g'] + colorHex['b'];
@@ -1942,10 +1882,12 @@ GZ3D.Gui.prototype.formatStats = function(stats)
colorHex = {};
for (comp in specular)
{
- colorHex[comp] = specular[comp].toString(16);
- if (colorHex[comp].length === 1)
- {
- colorHex[comp] = '0' + colorHex[comp];
+ if (specular.hasOwnProperty(comp)) {
+ colorHex[comp] = specular[comp].toString(16);
+ if (colorHex[comp].length === 1)
+ {
+ colorHex[comp] = '0' + colorHex[comp];
+ }
}
}
color.specular = '#' + colorHex['r'] + colorHex['g'] + colorHex['b'];
@@ -2079,6 +2021,8 @@ GZ3D.Gui.prototype.deleteFromStats = function(type, name)
//var GAZEBO_MODEL_DATABASE_URI='http://gazebosim.org/models';
+THREE.ImageUtils.crossOrigin = 'anonymous'; // needed to allow cross-origin loading of textures
+
GZ3D.GZIface = function(scene, gui)
{
this.scene = scene;
@@ -2094,6 +2038,13 @@ GZ3D.GZIface = function(scene, gui)
this.numConnectionTrials = 0;
this.maxConnectionTrials = 30; // try to connect 30 times
this.timeToSleepBtwTrials = 1000; // wait 1 second between connection trials
+
+ this.assetProgressData = {};
+ this.assetProgressData.assets = [];
+ this.assetProgressData.prepared = false;
+ this.assetProgressCallback = undefined;
+
+ this.webSocketConnectionCallbacks = [];
};
GZ3D.GZIface.prototype.init = function()
@@ -2104,11 +2055,35 @@ GZ3D.GZIface.prototype.init = function()
this.connect();
};
+GZ3D.GZIface.prototype.setAssetProgressCallback = function(callback)
+{
+ this.assetProgressCallback = callback;
+};
+
+GZ3D.GZIface.prototype.registerWebSocketConnectionCallback = function(callback) {
+ this.webSocketConnectionCallbacks.push(callback);
+};
+
GZ3D.GZIface.prototype.connect = function()
{
// connect to websocket
+ var url = GZ3D.webSocketUrl;
+ if (!localStorage.getItem('localmode.forceuser')) {
+ var token = [];
+ if (localStorage.getItem('tokens-neurorobotics-ui@https://services.humanbrainproject.eu/oidc')) {
+ try {
+ token = JSON.parse(localStorage.getItem('tokens-neurorobotics-ui@https://services.humanbrainproject.eu/oidc'));
+ } catch(e) {
+ token[0] = { access_token : 'notoken' };
+ }
+ url = url + '/?token=' + token[0].access_token;
+ } else {
+ url = 'ws://' + location.hostname + ':7681';
+ }
+ }
+
this.webSocket = new ROSLIB.Ros({
- url : 'ws://' + location.hostname + ':7681'
+ url : url
});
var that = this;
@@ -2118,6 +2093,9 @@ GZ3D.GZIface.prototype.connect = function()
this.webSocket.on('error', function() {
that.onError();
});
+ this.webSocket.on('close', function() {
+ console.log('Connection closed to websocket server: ' + that.webSocket.socket.url);
+ });
this.numConnectionTrials++;
};
@@ -2142,6 +2120,8 @@ GZ3D.GZIface.prototype.onError = function()
GZ3D.GZIface.prototype.onConnected = function()
{
+ console.log('Connected to websocket server: ' + this.webSocket.socket.url);
+
this.isConnected = true;
this.emitter.emit('connection');
@@ -2163,6 +2143,11 @@ GZ3D.GZIface.prototype.onConnected = function()
setInterval(publishHeartbeat, 5000);
+ // call all the registered callbacks since we are connected now
+ this.webSocketConnectionCallbacks.forEach(function(callback) {
+ callback();
+ });
+
var statusTopic = new ROSLIB.Topic({
ros: this.webSocket,
name: '~/status',
@@ -2208,7 +2193,7 @@ GZ3D.GZIface.prototype.onConnected = function()
if (message.grid === true)
{
- this.gui.guiEvents.emit('show_grid', 'show');
+ //this.gui.guiEvents.emit('show_grid', 'show'); // do not show grid by default for now
}
if (message.ambient)
@@ -2248,6 +2233,7 @@ GZ3D.GZIface.prototype.onConnected = function()
this.gui.setModelStats(model, 'update');
}
+ this.assetProgressData.prepared = true;
this.gui.setSceneStats(message);
this.sceneTopic.unsubscribe();
};
@@ -2356,6 +2342,8 @@ GZ3D.GZIface.prototype.onConnected = function()
}
i++;
}
+ } else {
+ this.updateModelFromMsg(this.scene.getByName(message.name), message);
}
this.gui.setModelStats(message, 'update');
};
@@ -2478,7 +2466,7 @@ GZ3D.GZIface.prototype.onConnected = function()
messageType : 'light',
});
- var publishEntityModify = function(entity)
+ var createEntityModifyMessage = function(entity)
{
var matrix = entity.matrixWorld;
var translation = new THREE.Vector3();
@@ -2505,43 +2493,89 @@ GZ3D.GZIface.prototype.onConnected = function()
z: quaternion.z
}
};
- if (entity.children[0] &&
- entity.children[0] instanceof THREE.Light)
+ return entityMsg;
+ };
+
+ /*
+ TODO: (Sandro Weber)
+ The following functions are used to change all lights at the same time through the light slider of the NRP.
+ Gazebo only knows attenuation factors, not intensity, so we manipulate diffuse color for now.
+ Probably replaced / revamped after a dedicated edit tab is introduced to allow manipulation of lights directly.
+ */
+ var createEntityModifyMessageWithLight = function(entity, diffuse)
+ {
+ var entityMsg = createEntityModifyMessage(entity);
+
+ var lightObj = entity.children[0];
+
+ if (diffuse === undefined) {
+ diffuse = lightObj.color;
+ }
+ entityMsg.diffuse =
{
- entityMsg.diffuse =
- {
- r: entity.children[0].color.r,
- g: entity.children[0].color.g,
- b: entity.children[0].color.b
- };
- entityMsg.specular =
- {
- r: entity.serverProperties.specular.r,
- g: entity.serverProperties.specular.g,
- b: entity.serverProperties.specular.b
- };
- entityMsg.direction = entity.direction;
- entityMsg.range = entity.children[0].distance;
- entityMsg.attenuation_constant = entity.serverProperties.attenuation_constant;
- entityMsg.attenuation_linear = entity.serverProperties.attenuation_linear;
- entityMsg.attenuation_quadratic = entity.serverProperties.attenuation_quadratic;
+ r: diffuse.r,
+ g: diffuse.g,
+ b: diffuse.b
+ };
+ entityMsg.specular =
+ {
+ r: entity.serverProperties.specular.r,
+ g: entity.serverProperties.specular.g,
+ b: entity.serverProperties.specular.b
+ };
+ entityMsg.direction = entity.direction;
+ entityMsg.range = lightObj.distance;
+
+ entityMsg.attenuation_constant = entity.serverProperties.attenuation_constant;
+ entityMsg.attenuation_linear = entity.serverProperties.attenuation_linear;
+ entityMsg.attenuation_quadratic = entity.serverProperties.attenuation_quadratic;
+
+ return entityMsg;
+ };
- that.lightModifyTopic.publish(entityMsg);
+ var publishEntityModify = function(entity)
+ {
+ var lightObj = entity.children[0];
+ if (lightObj && lightObj instanceof THREE.Light)
+ {
+ that.lightModifyTopic.publish(createEntityModifyMessageWithLight(entity, undefined));
}
else
{
- that.modelModifyTopic.publish(entityMsg);
+ that.modelModifyTopic.publish(createEntityModifyMessage(entity));
}
};
this.scene.emitter.on('entityChanged', publishEntityModify);
- // Link messages - for modifying links
- this.linkModifyTopic = new ROSLIB.Topic({
- ros : this.webSocket,
- name : '~/link',
- messageType : 'link',
- });
+ var publishLightModify = function(ratio)
+ {
+ var lights = [];
+ that.scene.scene.traverse(function(node) {
+ if (node instanceof THREE.Light) {
+ lights.push(node);
+ }
+ });
+
+ var numberOfLights = lights.length;
+ for (var i = 0; i < numberOfLights; i+=1) {
+ if( lights[i] instanceof THREE.AmbientLight ) { // we don't change ambient lights
+ continue;
+ }
+ var entity = that.scene.getByName(lights[i].name);
+ var newDiffuse = new THREE.Color();
+ newDiffuse.r = THREE.Math.clamp(ratio * entity.serverProperties.initial.diffuse.r, 0, 1);
+ newDiffuse.g = THREE.Math.clamp(ratio * entity.serverProperties.initial.diffuse.g, 0, 1);
+ newDiffuse.b = THREE.Math.clamp(ratio * entity.serverProperties.initial.diffuse.b, 0, 1);
+
+ that.lightModifyTopic.publish(createEntityModifyMessageWithLight(entity, newDiffuse));
+ }
+ };
+
+ this.scene.emitter.on('lightChanged', publishLightModify);
+ /*
+ end of light slider change functions
+ */
var publishLinkModify = function(entity, type)
{
@@ -2808,6 +2842,16 @@ GZ3D.GZIface.prototype.createModelFromMsg = function(model)
}
}
}
+
+ for (var i = 0; i < link.sensor.length; ++i) {
+ var sensor = link.sensor[i];
+
+ var sensorObj = this.createSensorFromMsg(sensor);
+ if (sensorObj && !sensorObj.parent)
+ {
+ linkObj.add(sensorObj);
+ }
+ }
}
if (model.joint)
{
@@ -2817,6 +2861,24 @@ GZ3D.GZIface.prototype.createModelFromMsg = function(model)
return modelObj;
};
+// This method uses code also to be found at GZ3D.GZIface.prototype.createModelFromMsg.
+// Currently not everything is handled for an update, but this method was introduced to handle
+// the updates of colors of objects; if there should be more functionality one could consider
+// merging the two methods and extracting the different things to parameters (or any other means
+// of configuration).
+GZ3D.GZIface.prototype.updateModelFromMsg = function (modelObj, modelMsg) {
+ for (var j = 0; j < modelMsg.link.length; ++j) {
+ var link = modelMsg.link[j];
+ var linkObj = modelObj.children[j];
+
+ for (var k = 0; k < link.visual.length; ++k) {
+ var visual = link.visual[k];
+ var visualObj = linkObj.getObjectByName(visual.name);
+ this.updateVisualFromMsg(visualObj, visual);
+ }
+ }
+};
+
GZ3D.GZIface.prototype.createVisualFromMsg = function(visual)
{
if (visual.geometry)
@@ -2839,21 +2901,32 @@ GZ3D.GZIface.prototype.createVisualFromMsg = function(visual)
}
};
+GZ3D.GZIface.prototype.updateVisualFromMsg = function (visualObj, visual) {
+ if (visual.geometry) {
+ var obj = visualObj.children[0];
+ var mat = this.parseMaterial(visual.material);
+
+ if (obj && mat) {
+ this.scene.setMaterial(obj, mat);
+ }
+ }
+};
+
GZ3D.GZIface.prototype.createLightFromMsg = function(light)
{
var obj, range, direction;
- if (light.type === 1)
+ if (light.type === this.scene.LIGHT_POINT)
{
direction = null;
range = light.range;
}
- else if (light.type === 2)
+ else if (light.type === this.scene.LIGHT_SPOT)
{
direction = light.direction;
range = light.range;
}
- else if (light.type === 3)
+ else if (light.type === this.scene.LIGHT_DIRECTIONAL)
{
direction = light.direction;
range = null;
@@ -2891,9 +2964,66 @@ GZ3D.GZIface.prototype.createRoadsFromMsg = function(roads)
return roadObj;
};
+GZ3D.GZIface.prototype.createSensorFromMsg = function(sensor)
+{
+ var sensorObj = new THREE.Object3D();
+ sensorObj.name = sensor.name;
+
+ if (sensor.pose) {
+ this.scene.setPose(sensorObj, sensor.pose.position, sensor.pose.orientation);
+ }
+
+ if (sensor.type === 'camera') {
+ // if we have a camera sensor we have a potential view that could be rendered
+ // camera parameters are not published by gazebo right now, so hardcoded until fixed
+ var displayParams = {
+ left: '5%',
+ top: '5%',
+ width: '20%',
+ height: '20%',
+ adjustable: true
+ };
+ var cameraParams = {
+ width: 960,
+ height: 600,
+ fov: 60,
+ near: 0.1,
+ far: 100
+ };
+ var viewName = 'view_' + sensor.name;
+ var view = this.scene.viewManager.createView(viewName, displayParams, cameraParams);
+ if (!view) {
+ console.error('GZ3D.GZIface.createSensorFromMsg() - failed to create view ' + viewName);
+ return;
+ }
+
+ // There is a problem with the width and height; it should be read from the "sensor" object. Also see:
+ // https://bitbucket.org/osrf/gazebo/issues/1663/sensor-camera-elements-from-sdf-not-being
+
+ // camera sensors defined in gazebo .sdf seem to look along positive x axis, so need to adjust the rotation here
+ view.camera.rotateOnAxis(new THREE.Vector3(0, 1, 0), -Math.PI / 2);
+ view.camera.rotateOnAxis(new THREE.Vector3(0, 0, 1), -Math.PI / 2);
+
+ // set view inactive and hide at start
+ this.scene.viewManager.setViewVisibility(view, false);
+
+ // visualization - Deactivated since it causes the robot to be very big and the user
+ // can't barely select other objects on the scene. Reactivate for debug purposes !
+ // var cameraHelper = new THREE.CameraHelper(view.camera);
+ // view.camera.add( cameraHelper );
+
+ view.type = sensor.type;
+ console.log('view type: ' + view.type);
+
+ sensorObj.add(view.camera);
+ }
+
+ return sensorObj;
+};
+
GZ3D.GZIface.prototype.parseUri = function(uri)
{
- var uriPath = 'assets';
+ var uriPath = GZ3D.assetsPath;
var idx = uri.indexOf('://');
if (idx > 0)
{
@@ -2905,7 +3035,7 @@ GZ3D.GZIface.prototype.parseUri = function(uri)
GZ3D.GZIface.prototype.createGeom = function(geom, material, parent)
{
var obj;
- var uriPath = 'assets';
+ var uriPath = GZ3D.assetsPath;
var that = this;
var mat = this.parseMaterial(material);
if (geom.box)
@@ -2985,26 +3115,48 @@ GZ3D.GZIface.prototype.createGeom = function(geom, material, parent)
var modelUri = uriPath + '/' + modelName;
// Use coarse version on touch devices
- if (modelUri.indexOf('.dae') !== -1 && isTouchDevice)
+ if (modelUri.indexOf('.dae') !== -1 /*&& isTouchDevice*/) // Modified for HBP, we do use coarse models all the time
{
modelUri = modelUri.substring(0,modelUri.indexOf('.dae'));
- var checkModel = new XMLHttpRequest();
- checkModel.open('HEAD', modelUri+'_coarse.dae', false);
- checkModel.send();
- if (checkModel.status === 404)
+ if(modelUri.indexOf('_coarse') !== -1) //dae is already a coarse model
{
modelUri = modelUri+'.dae';
}
- else
- {
- modelUri = modelUri+'_coarse.dae';
+ else { // check if a coarse version is available
+ var checkModel = new XMLHttpRequest();
+ // We use a double technique to disable the cache for these requests:
+ // 1. We create a custom url by adding the time as a parameter.
+ // 2. We add the If-Modified-Since header with a date far in the future (end of the HBP project)
+ // Since browsers and servers vary in their behaviour, we use both of these tricks.
+ // PS: These requests do not load the dae files, they just verify if they exist on the server
+ // so that we can choose between coarse or reqular models.
+ checkModel.open('HEAD', modelUri+'_coarse.dae?timestamp=' + new Date().getTime(), false);
+ checkModel.setRequestHeader('If-Modified-Since', 'Sat, 1 Jan 2026 00:00:00 GMT');
+
+ try { checkModel.send(); } catch(err) { console.log(modelUri + ': no coarse version'); }
+
+ if (checkModel.status === 404) {
+ modelUri = modelUri+'.dae';
+ }
+ else {
+ modelUri = modelUri+'_coarse.dae';
+ }
}
}
var materialName = parent.name + '::' + modelUri;
this.entityMaterial[materialName] = mat;
+ // Progress update: Add this asset to the assetProgressArray
+ var element = {};
+ element.id = parent.name;
+ element.url = modelUri;
+ element.progress = 0;
+ element.totalSize = 0;
+ element.done = false;
+ this.assetProgressData.assets.push(element);
+
this.scene.loadMesh(modelUri, submesh,
centerSubmesh, function(dae) {
if (that.entityMaterial[materialName])
@@ -3023,6 +3175,19 @@ GZ3D.GZIface.prototype.createGeom = function(geom, material, parent)
}
parent.add(dae);
loadGeom(parent);
+
+ // Progress update: execute callback
+ element.done = true;
+ if (that.assetProgressCallback) {
+ that.assetProgressCallback(that.assetProgressData);
+ }
+ }, function(progress){
+ element.progress = progress.loaded;
+ element.totalSize = progress.total;
+ element.error = progress.error;
+ if (that.assetProgressCallback) {
+ that.assetProgressCallback(that.assetProgressData);
+ }
});
}
}
@@ -3098,7 +3263,7 @@ GZ3D.GZIface.prototype.createGeom = function(geom, material, parent)
allChildren[c].castShadow = false;
allChildren[c].receiveShadow = false;
- allChildren[c].visible = this.scene.showCollisions;
+ allChildren[c].visible = that.scene.showCollisions;
}
}
}
@@ -3156,7 +3321,7 @@ GZ3D.GZIface.prototype.parseMaterial = function(material)
return null;
}
- var uriPath = 'assets';
+ var uriPath = GZ3D.assetsPath;//'assets';
var texture;
var normalMap;
var textureUri;
@@ -4011,10 +4176,10 @@ GZ3D.Manipulator = function(camera, mobile, domElement, doc)
}
this.object.updateMatrixWorld();
- worldPosition.getPositionFromMatrix(this.object.matrixWorld);
+ worldPosition.setFromMatrixPosition(this.object.matrixWorld);
this.camera.updateMatrixWorld();
- camPosition.getPositionFromMatrix(this.camera.matrixWorld);
+ camPosition.setFromMatrixPosition(this.camera.matrixWorld);
scale = worldPosition.distanceTo(camPosition) / 6 * this.scale;
this.gizmo.position.copy(worldPosition);
@@ -4266,7 +4431,7 @@ GZ3D.Manipulator = function(camera, mobile, domElement, doc)
worldRotationMatrix.extractRotation(scope.object.matrixWorld);
parentRotationMatrix.extractRotation(scope.object.parent.matrixWorld);
- parentScale.getScaleFromMatrix(tempMatrix.getInverse(
+ parentScale.setFromMatrixScale(tempMatrix.getInverse(
scope.object.parent.matrixWorld));
offset.copy(planeIntersect.point);
@@ -4381,7 +4546,7 @@ GZ3D.Manipulator = function(camera, mobile, domElement, doc)
parentRotationMatrix.extractRotation(
scope.object.parent.matrixWorld);
- parentScale.getScaleFromMatrix(tempMatrix.getInverse(
+ parentScale.setFromMatrixScale(tempMatrix.getInverse(
scope.object.parent.matrixWorld));
offset.copy(planeIntersect.point);
@@ -4677,6 +4842,287 @@ GZ3D.Manipulator = function(camera, mobile, domElement, doc)
GZ3D.Manipulator.prototype = Object.create(THREE.EventDispatcher.prototype);
+/**
+ * Created by Sandro Weber (webers@in.tum.de).
+ */
+
+GZ3D.MULTIVIEW_MAX_VIEW_COUNT = 10;
+
+/**
+ * GZ3D.MULTIVIEW_RENDER_VIEWPORTS uses view containers as transparent references to determine viewports for rendering (one single canvas).
+ * This is broken in combination with shadowmaps at the moment. See renderToViewport() method.
+ *
+ * @type {number}
+ */
+GZ3D.MULTIVIEW_RENDER_VIEWPORTS = 1;
+/**
+ * GZ3D.MULTIVIEW_RENDER_COPY2CANVAS renders views offscreen then copies into the view containers (multiple separate canvases).
+ * @type {number}
+ */
+GZ3D.MULTIVIEW_RENDER_COPY2CANVAS = 2;
+
+GZ3D.MultiView = function(gz3dScene, mainContainer, callbackCreateRenderContainer)
+{
+ this.gz3dScene = gz3dScene;
+ this.mainContainer = mainContainer;
+ this.createRenderContainerCallback = callbackCreateRenderContainer;
+
+ this.init();
+};
+
+GZ3D.MultiView.prototype.init = function()
+{
+ this.views = [];
+
+ this.mainContainer.style.zIndex = 0;
+
+ this.renderMethod = GZ3D.MULTIVIEW_RENDER_COPY2CANVAS;
+ if (this.renderMethod === GZ3D.MULTIVIEW_RENDER_VIEWPORTS) {
+ this.mainContainer.appendChild(this.gz3dScene.getDomElement());
+ }
+};
+
+GZ3D.MultiView.prototype.setCallbackCreateRenderContainer = function(callback)
+{
+ this.createRenderContainerCallback = callback;
+};
+
+/**
+ *
+ * @param name
+ * @param displayParams {left, top, width, height, zIndex, adjustable}
+ * @param cameraParams {width, height, fov, near, far}
+ */
+GZ3D.MultiView.prototype.createView = function(name, displayParams, cameraParams)
+{
+ if (this.getViewByName(name) !== undefined) {
+ console.error('GZ3D.MultiView.createView() - a view of that name already exists (' + name + ')');
+ return null;
+ }
+
+ if (this.views.length >= this.MULTIVIEW_MAX_VIEW_COUNT) {
+ console.warn('GZ3D.MultiView.createView() - creating new view will exceed MULTIVIEW_MAX_VIEW_COUNT(' + this.MULTIVIEW_MAX_VIEW_COUNT + '). This may cause z-ordering issues.');
+ }
+
+ var container = this.createViewContainer(displayParams, name);
+ if (container === null) {
+ return;
+ }
+
+ // camera
+ var camera = new THREE.PerspectiveCamera(cameraParams.fov, cameraParams.width / cameraParams.height, cameraParams.near, cameraParams.far);
+ camera.name = name;
+
+ // assemble view
+ var view = {
+ name: name,
+ active: true,
+ container: container,
+ camera: camera
+ };
+
+ this.views.push(view);
+ this.mainContainer.appendChild(view.container);
+
+ return view;
+};
+
+GZ3D.MultiView.prototype.createViewContainer = function(displayParams, name)
+{
+ if (this.createRenderContainerCallback === undefined) {
+ console.error('GZ3D.MultiView.createViewContainer() - no callback for creating view reference container defined');
+ return null;
+ }
+
+ // container div
+ var viewContainer = this.createRenderContainerCallback(displayParams.adjustable, name);
+ if (!viewContainer) {
+ console.error('GZ3D.MultiView.createViewContainer() - could not create view container via callback');
+ return null;
+ }
+
+ // positioning
+ viewContainer.style.position = 'absolute';
+ viewContainer.style.left = displayParams.left;
+ viewContainer.style.top = displayParams.top;
+ // There is a problem with the width and height; it should be read from the "sensor" object. Also see:
+ // https://bitbucket.org/osrf/gazebo/issues/1663/sensor-camera-elements-from-sdf-not-being
+ // Here we use (preliminary) percentual width.
+ viewContainer.style.width = displayParams.width;
+ viewContainer.style.height = displayParams.height;
+
+ // We set 50px as a min-width for now and set the min height accordingly
+ viewContainer.style.minWidth = '50px';
+ viewContainer.style.minHeight = (50 * (parseInt(displayParams.width, 10)/parseInt(displayParams.height, 10))) + 'px';
+ viewContainer.style.maxWidth = '100%';
+ viewContainer.style.maxHeight = '100%';
+
+ // transparent view-container so we can render viewport with one renderer in the same context
+ // view-container is only taken as reference for viewport
+ viewContainer.style.boxShadow = '0px 0px 0px 3px rgba(0,0,0,0.3)';
+ viewContainer.style.borderRadius = '2px';
+ viewContainer.style.background = 'rgba(0,0,0,0)';
+
+ if (this.renderMethod === GZ3D.MULTIVIEW_RENDER_COPY2CANVAS) {
+ // canvas
+ viewContainer.canvas = document.createElement('canvas');
+ viewContainer.appendChild( viewContainer.canvas );
+ viewContainer.canvas.style.width = '100%';
+ viewContainer.canvas.style.height = '100%';
+ }
+
+ // z-index
+ var zIndexTop = parseInt(this.mainContainer.style.zIndex, 10) + this.views.length + 1;
+ viewContainer.style.zIndex = (displayParams.zIndex !== undefined) ? displayParams.zIndex : zIndexTop;
+
+ return viewContainer;
+};
+
+GZ3D.MultiView.prototype.getViewByName = function(name)
+{
+ for (var i = 0; i < this.views.length; i = i+1) {
+ if (this.views[i].name === name) {
+ return this.views[i];
+ }
+ }
+
+ return undefined;
+};
+
+GZ3D.MultiView.prototype.setViewVisibility = function(view, visible)
+{
+ view.active = visible;
+ if (view.active) {
+ view.container.style.visibility = 'visible';
+ } else {
+ view.container.style.visibility = 'hidden';
+ }
+};
+
+GZ3D.MultiView.prototype.updateCamera = function(view)
+{
+ view.camera.aspect = view.container.clientWidth / view.container.clientHeight;
+ view.camera.updateProjectionMatrix();
+};
+
+GZ3D.MultiView.prototype.getViewport = function(view)
+{
+ var viewport = {
+ x: view.container.offsetLeft,
+ y: this.mainContainer.clientHeight - view.container.clientHeight - view.container.offsetTop,
+ w: view.container.clientWidth,
+ h: view.container.clientHeight
+ };
+
+ return viewport;
+};
+
+GZ3D.MultiView.prototype.setWindowSize = function(width, height)
+{
+
+};
+
+GZ3D.MultiView.prototype.renderViews = function()
+{
+ // sort views into rendering order
+ this.views.sort(function(a, b) {
+ return a.container.style.zIndex - b.container.style.zIndex;
+ });
+
+ for (var i = 0, l = this.views.length; i < l; i = i+1) {
+ var view = this.views[i];
+
+ if (view.active) {
+ switch(this.renderMethod) {
+ case GZ3D.MULTIVIEW_RENDER_VIEWPORTS:
+ this.renderToViewport(view);
+ break;
+ case GZ3D.MULTIVIEW_RENDER_COPY2CANVAS:
+ this.renderAndCopyToCanvas(view);
+ break;
+ }
+ }
+ }
+};
+
+/**
+ * !IMPORTANT!
+ * https://github.com/mrdoob/three.js/issues/3532
+ * This is at the moment not a good idea, see issue above. ScissorTest will scramble shadowmaps.
+ *
+ * @param view
+ */
+GZ3D.MultiView.prototype.renderToViewport = function(view)
+{
+ this.updateCamera(view); //TODO: better solution with resize callback, also adjust camera helper
+
+ var webglRenderer = this.gz3dScene.renderer;
+
+ var viewport = this.getViewport(view);
+ webglRenderer.setViewport( viewport.x, viewport.y, viewport.w, viewport.h );
+ webglRenderer.setScissor( viewport.x, viewport.y, viewport.w, viewport.h );
+ webglRenderer.enableScissorTest ( true );
+
+ if (this.gz3dScene.effectsEnabled) {
+ this.gz3dScene.scene.overrideMaterial = this.depthMaterial;
+ this.gz3dScene.renderer.render(this.gz3dScene.scene, view.camera, this.depthTarget);
+ this.gz3dScene.scene.overrideMaterial = null;
+ this.gz3dScene.composer.render();
+ } else {
+ webglRenderer.render(this.gz3dScene.scene, view.camera);
+ }
+};
+
+GZ3D.MultiView.prototype.renderAndCopyToCanvas = function(view)
+{
+ this.updateCamera(view); //TODO: better solution with resize callback, also adjust camera helper
+
+ var webglRenderer = this.gz3dScene.renderer;
+
+ var width = view.container.canvas.clientWidth;
+ var height = view.container.canvas.clientHeight;
+ view.container.canvas.width = width;
+ view.container.canvas.height = height;
+
+ if (webglRenderer.context.canvas.width < width) {
+ webglRenderer.context.canvas.width = width;
+ }
+ if (webglRenderer.context.canvas.height < height) {
+ webglRenderer.context.canvas.height = height;
+ }
+ webglRenderer.setViewport( 0, 0, width, height );
+
+ if (this.gz3dScene.effectsEnabled) {
+ this.gz3dScene.scene.overrideMaterial = this.depthMaterial;
+ this.gz3dScene.renderer.render(this.gz3dScene.scene, view.camera, this.depthTarget);
+ this.gz3dScene.scene.overrideMaterial = null;
+ this.gz3dScene.composer.render();
+ } else {
+ webglRenderer.render(this.gz3dScene.scene, view.camera);
+ }
+
+ // copy rendered image over to view canvas
+ var srcX = 0;
+ var srcY = webglRenderer.context.canvas.height - height + 1;
+ var dstX = 0;
+ var dstY = 0;
+ // no cleaner solution right now, should be coming though: https://github.com/mrdoob/three.js/pull/6723#issuecomment-134129027
+ // this kills performance a little ...
+ if ( srcX >= 0 && srcY >= 0 && width >= 1 && height >= 1 ) {
+ view.container.canvas.getContext('2d').drawImage( webglRenderer.context.canvas,
+ srcX, srcY, width, height,
+ dstX, dstY, width, height );
+ }
+};
+
+GZ3D.MultiView.prototype.showCameras = function(show)
+{
+ for (var i = 0; i < this.views.length; i = i+1) {
+ if (this.views[i].type === 'camera') {
+ this.setViewVisibility(this.views[i], show);
+ }
+ }
+};
/**
* Radial menu for an object
* @constructor
@@ -5079,8 +5525,6 @@ GZ3D.RadialMenu.prototype.setNumberOfItems = function(number)
this.offset = this.numberOfItems - 1 - Math.floor(this.numberOfItems/2);
};
-
-
/**
* The scene is where everything is placed, from objects, to lights and cameras.
* @constructor
@@ -5090,6 +5534,11 @@ GZ3D.Scene = function()
this.init();
};
+GZ3D.Scene.prototype.LIGHT_POINT = 1;
+GZ3D.Scene.prototype.LIGHT_SPOT = 2;
+GZ3D.Scene.prototype.LIGHT_DIRECTIONAL = 3;
+GZ3D.Scene.prototype.LIGHT_UNKNOWN = 4;
+
/**
* Initialize scene
*/
@@ -5113,16 +5562,38 @@ GZ3D.Scene.prototype.init = function()
this.renderer.setSize( window.innerWidth, window.innerHeight);
// shadows
- this.renderer.shadowMapEnabled = true;
+ this.renderer.shadowMapEnabled = false;
this.renderer.shadowMapType = THREE.PCFSoftShadowMap;
+ this.container = document.getElementById( 'container' );
+
+ // create views manager
+ this.viewManager = new GZ3D.MultiView(this, this.container, function(adjustable, name){
+ return document.createElement('div');
+ });
+ // create main view
+ var displayParams = {
+ left: '0px',
+ top: '0px',
+ width: '100%',
+ height: '100%',
+ adjustable: false
+ };
+ var cameraParams = {
+ width: 960,
+ height: 600,
+ fov: 60,
+ near: 0.1,
+ far: 100
+ };
+ this.viewManager.createView('main_view', displayParams, cameraParams);
+
// lights
this.ambient = new THREE.AmbientLight( 0x666666 );
this.scene.add(this.ambient);
// camera
- this.camera = new THREE.PerspectiveCamera(
- 60, window.innerWidth / window.innerHeight, 0.1, 1000 );
+ this.camera = this.viewManager.getViewByName('main_view').camera;
this.defaultCameraPosition = new THREE.Vector3(0, -5, 5);
this.resetView();
@@ -5181,7 +5652,12 @@ GZ3D.Scene.prototype.init = function()
this.timeDown = null;
- this.controls = new THREE.OrbitControls(this.camera);
+ var domElementForKeyBindings = document.getElementsByTagName('body')[0];
+ this.controls = new THREE.FirstPersonControls(this.camera, this.container, domElementForKeyBindings);
+ if (this.controls instanceof THREE.FirstPersonControls) {
+ this.controls.movementSpeed = 0.2;
+ this.controls.lookSpeed = 0.005;
+ }
if (this.controls.targetIndicator !== undefined) {
this.scene.add(this.controls.targetIndicator);
}
@@ -5550,7 +6026,7 @@ GZ3D.Scene.prototype.onPointerDown = function(event)
*/
GZ3D.Scene.prototype.onPointerUp = function(event)
{
- event.preventDefault();
+ //event.preventDefault();
// Clicks (<150ms) outside any models trigger view mode
var millisecs = new Date().getTime();
@@ -5754,7 +6230,7 @@ GZ3D.Scene.prototype.getRayCastModel = function(pos, intersect)
*/
GZ3D.Scene.prototype.getDomElement = function()
{
- return this.renderer.domElement;
+ return this.container;
};
/**
@@ -5784,17 +6260,7 @@ GZ3D.Scene.prototype.render = function()
this.modelManipulator.update();
this.radialMenu.update();
- if (this.effectsEnabled)
- {
- this.scene.overrideMaterial = this.depthMaterial;
- this.renderer.render(this.scene, this.camera, this.depthTarget);
- this.scene.overrideMaterial = null;
- this.composer.render();
- }
- else
- {
- this.renderer.render(this.scene, this.camera);
- }
+ this.viewManager.renderViews();
};
/**
@@ -5808,6 +6274,11 @@ GZ3D.Scene.prototype.setWindowSize = function(width, height)
this.camera.updateProjectionMatrix();
this.renderer.setSize( width, height);
+ this.renderer.context.canvas.width = width;
+ this.renderer.context.canvas.height = height;
+
+ this.viewManager.setWindowSize(width, height);
+
this.render();
};
@@ -5996,6 +6467,8 @@ GZ3D.Scene.prototype.createBox = function(width, height, depth)
* @param {} attenuation_constant
* @param {} attenuation_linear
* @param {} attenuation_quadratic
+ * @param {} spot_angle
+ * @param {} spot_falloff
* @returns {THREE.Object3D}
*/
GZ3D.Scene.prototype.createLight = function(type, diffuse, intensity, pose,
@@ -6024,6 +6497,10 @@ GZ3D.Scene.prototype.createLight = function(type, diffuse, intensity, pose,
specular = color.clone();
}
+ if (typeof(specular) === 'undefined') {
+ specular = 0xffffff;
+ }
+
var matrixWorld;
if (pose)
@@ -6047,17 +6524,17 @@ GZ3D.Scene.prototype.createLight = function(type, diffuse, intensity, pose,
}
var elements;
- if (type === 1)
+ if (type === this.LIGHT_POINT)
{
elements = this.createPointLight(obj, diffuse, intensity,
distance, cast_shadows);
}
- else if (type === 2)
+ else if (type === this.LIGHT_SPOT)
{
elements = this.createSpotLight(obj, diffuse, intensity,
distance, cast_shadows, spot_angle, spot_falloff);
}
- else if (type === 3)
+ else if (type === this.LIGHT_DIRECTIONAL)
{
elements = this.createDirectionalLight(obj, diffuse, intensity,
cast_shadows);
@@ -6092,13 +6569,16 @@ GZ3D.Scene.prototype.createLight = function(type, diffuse, intensity, pose,
obj.serverProperties.attenuation_constant = attenuation_constant;
obj.serverProperties.attenuation_linear = attenuation_linear;
obj.serverProperties.attenuation_quadratic = attenuation_quadratic;
+ obj.serverProperties.initial = {};
+ obj.serverProperties.initial.diffuse = diffuse;
- obj.add(lightObj);
- obj.add(helper);
-
+ helper.visible = false;
lightObj.up = new THREE.Vector3(0,0,1);
lightObj.shadowBias = -0.0005;
+ obj.add(lightObj);
+ obj.add(helper);
+
return obj;
};
@@ -6565,7 +7045,7 @@ GZ3D.Scene.prototype.loadHeightmap = function(heights, width, height,
* @param {function} callback
*/
GZ3D.Scene.prototype.loadMesh = function(uri, submesh, centerSubmesh,
- callback)
+ callback, progressCallback)
{
var uriPath = uri.substring(0, uri.lastIndexOf('/'));
var uriFile = uri.substring(uri.lastIndexOf('/') + 1);
@@ -6573,7 +7053,7 @@ GZ3D.Scene.prototype.loadMesh = function(uri, submesh, centerSubmesh,
// load urdf model
if (uriFile.substr(-4).toLowerCase() === '.dae')
{
- return this.loadCollada(uri, submesh, centerSubmesh, callback);
+ return this.loadCollada(uri, submesh, centerSubmesh, callback, progressCallback);
}
else if (uriFile.substr(-5).toLowerCase() === '.urdf')
{
@@ -6619,7 +7099,7 @@ GZ3D.Scene.prototype.loadMesh = function(uri, submesh, centerSubmesh,
* @param {function} callback
*/
GZ3D.Scene.prototype.loadCollada = function(uri, submesh, centerSubmesh,
- callback)
+ callback, progressCallback)
{
var dae;
var mesh = null;
@@ -6642,6 +7122,7 @@ GZ3D.Scene.prototype.loadCollada = function(uri, submesh, centerSubmesh,
var thatSubmesh = submesh;
var thatCenterSubmesh = centerSubmesh;
+ var that = this;
loader.load(uri, function(collada)
{
// check for a scale factor
@@ -6653,13 +7134,22 @@ GZ3D.Scene.prototype.loadCollada = function(uri, submesh, centerSubmesh,
dae = collada.scene;
dae.updateMatrix();
- this.scene.prepareColladaMesh(dae);
- this.scene.meshes[thatURI] = dae;
+ that.prepareColladaMesh(dae);
+ that.meshes[thatURI] = dae;
dae = dae.clone();
- this.scene.useColladaSubMesh(dae, thatSubmesh, centerSubmesh);
+ that.useColladaSubMesh(dae, thatSubmesh, centerSubmesh);
dae.name = uri;
callback(dae);
+ },function(progress) {
+ if (progressCallback !== undefined) {
+ progress.error = false;
+ progressCallback(progress);
+ }
+ },function(){
+ if (progressCallback !== undefined) {
+ progressCallback({ total: 0, loaded: 0, error: true });
+ }
});
};
@@ -6872,7 +7362,7 @@ GZ3D.Scene.prototype.setManipulationMode = function(mode)
}
else
{
- // Toggle manipulaion space (world / local)
+ // Toggle manipulation space (world / local)
if (this.modelManipulator.mode === this.manipulationMode)
{
this.modelManipulator.space =
@@ -7465,7 +7955,7 @@ GZ3D.Scene.prototype.updateLight = function(entity, msg)
this.setPose(entity, msg.pose.position, msg.pose.orientation);
entity.matrixWorldNeedsUpdate = true;
- if (entity.direction)
+ if (entity.direction && lightObj.target)
{
dir = new THREE.Vector3(entity.direction.x, entity.direction.y,
entity.direction.z);
@@ -7507,6 +7997,18 @@ GZ3D.Scene.prototype.updateLight = function(entity, msg)
entity.serverProperties.attenuation_quadratic = msg.attenuation_quadratic;
lightObj.intensity = lightObj.intensity/(1+msg.attenuation_quadratic);
}
+ if (msg.attenuation_linear && msg.attenuation_quadratic)
+ {
+ // equation taken from
+ // http://wiki.blender.org/index.php/Doc:2.6/Manual/Lighting/Lights/Light_Attenuation
+ var E = 1;
+ var D = 1;
+ var r = 1;
+ var L = msg.attenuation_linear;
+ var Q = msg.attenuation_quadratic;
+ lightObj.intensity = E*(D/(D+L*r))*(Math.pow(D,2)/(Math.pow(D,2)+Q*Math.pow(r,2)));
+ }
+
if (lightObj instanceof THREE.SpotLight) {
if (msg.spot_outer_angle) {
@@ -7518,7 +8020,7 @@ GZ3D.Scene.prototype.updateLight = function(entity, msg)
}
}
- if (msg.direction)
+ if (msg.direction && lightObj.target)
{
dir = new THREE.Vector3(msg.direction.x, msg.direction.y,
msg.direction.z);
@@ -7531,6 +8033,29 @@ GZ3D.Scene.prototype.updateLight = function(entity, msg)
}
};
+GZ3D.Scene.prototype.setShadowMaps = function(enabled) {
+ this.renderer.shadowMapEnabled = enabled;
+
+ var that = this;
+ this.scene.traverse(function(node) {
+ if (enabled) {
+ if (node.material) {
+ node.material.needsUpdate = true;
+ if (node.material.materials) {
+ for (var i = 0; i < node.material.materials.length; i = i+1) {
+ node.material.materials[i].needsUpdate = true;
+ }
+ }
+ }
+ } else {
+ if (node instanceof THREE.Light) {
+ if (node.shadowMap) {
+ that.renderer.clearTarget( node.shadowMap );
+ }
+ }
+ }
+ });
+};
/**
* SDF parser constructor initializes SDF parser with the given parameters
* and defines a DOM parser function to parse SDF XML files
@@ -7542,7 +8067,7 @@ GZ3D.SdfParser = function(scene, gui, gziface)
{
// set the sdf version
this.SDF_VERSION = 1.5;
- this.MATERIAL_ROOT = 'assets/';
+ this.MATERIAL_ROOT = GZ3D.assetsPath + '/';
// set the xml parser function
this.parseXML = function(xmlStr) {
@@ -8072,7 +8597,7 @@ GZ3D.SdfParser.prototype.createGeom = function(geom, mat, parent)
allChildren[c].castShadow = false;
allChildren[c].receiveShadow = false;
- allChildren[c].visible = this.scene.showCollisions;
+ allChildren[c].visible = that.scene.showCollisions;
}
break;
}
diff --git a/gz3d/client/index.html b/gz3d/client/index.html
index 2dd977d34d2e2fc9464126d02bb1b4b653c38900..45175460bd6b5e0b4504899b88c5545ba69efdb2 100644
--- a/gz3d/client/index.html
+++ b/gz3d/client/index.html
@@ -114,7 +114,7 @@
</script>
<body>
- <div data-role="page" data-theme="b" data-content-theme="c">
+ <div id="gz3d-body" data-role="page" data-theme="b" data-content-theme="c">
<!-- left panel -->
<div id="leftPanel" class="gzGUI">
@@ -139,6 +139,8 @@
<li id='view-grid' data-icon="false" data-iconpos="right" style="border: none !important;"><a href="#"><span class="collapsible_item">Grid</span></a></li>
<li id='view-collisions' data-icon="false" data-iconpos="right" style="border: none !important;"><a href="#"><span class="collapsible_item">Collisions</span></a></li>
<li id='view-orbit-indicator' data-icon="false" data-iconpos="right" style="border: none !important;"><a href="#"><span class="collapsible_item">Orbit Indicator</span></a></li>
+ <li id='view-shadows' data-icon="false" data-iconpos="right" style="border: none !important;"><a href="#"><span class="collapsible_item">Shadows</span></a></li>
+ <li id='view-camera-sensors' data-icon="false" data-iconpos="right" style="border: none !important;"><a href="#"><span class="collapsible_item">Camera Sensors</span></a></li>
</ul>
</div>
<div data-role="collapsible" data-inset="false" data-iconpos="left" data-collapsed-icon="carat-r" data-expanded-icon="carat-d">
@@ -1135,7 +1137,7 @@
<!-- header -->
<!-- content -->
- <div data-role="content" id="container">
+ <div data-role="content" id="container" style="position: absolute">
<div data-role="popup" id="notification-popup" data-history="false"></div>
<div data-role="popup" data-corners="false" id="model-popup" data-history="false">
<ul data-role="listview">
@@ -1165,12 +1167,21 @@
function init()
{
scene = new GZ3D.Scene();
+ scene.viewManager.setCallbackCreateRenderContainer(function(adjustable, name) {
+ /*if (adjustable) {
+ return $compile('<div movable resizeable keep-aspect-ratio class="camera-view"><div class="camera-view-label">' + name + '</div></div>')($rootScope)[0];
+ } else {
+ return $compile('<div keep-aspect-ratio class="camera-view"><div class="camera-view-label">' + name + '</div></div>')($rootScope)[0];
+ }*/
+ return document.createElement('div');
+ });
+
gui = new GZ3D.Gui(scene);
iface = new GZ3D.GZIface(scene, gui);
sdfparser = new GZ3D.SdfParser(scene, gui, iface);
- container = document.getElementById( 'container' );
- container.appendChild(scene.getDomElement());
+ //container = document.getElementById( 'container' );
+ //container.appendChild(scene.getDomElement());
// FPS indicator
stats = new Stats();
diff --git a/gz3d/client/js/include/FirstPersonControls.js b/gz3d/client/js/include/FirstPersonControls.js
index 35a202ed19869d807d232809fb98e656e8179299..ab61a1b45387740c13cde55691164f37f7e67372 100644
--- a/gz3d/client/js/include/FirstPersonControls.js
+++ b/gz3d/client/js/include/FirstPersonControls.js
@@ -273,7 +273,7 @@ THREE.FirstPersonControls = function(object, domElement, domElementForKeyBinding
vecForward.normalize();
this.zenith = Math.acos(-vecForward.z);
- this.azimuth = Math.atan(vecForward.y / vecForward.x) + Math.PI;
+ this.azimuth = Math.atan2(vecForward.y, vecForward.x) + Math.PI;
};
function bind(scope, fn) {
diff --git a/gz3d/src/gz.js b/gz3d/src/gz.js
index e8dd0aec0149d76faae58cb7cb9805f32b730069..54989411226664c2788855f82f86f69e4bb538fd 100644
--- a/gz3d/src/gz.js
+++ b/gz3d/src/gz.js
@@ -1,3 +1,5 @@
var GZ3D = GZ3D || {
- REVISION : '1'
+ REVISION : '1',
+ assetsPath: 'http://localhost:8080/assets',
+ webSocketUrl: 'ws://localhost:7681'
};
\ No newline at end of file
diff --git a/gz3d/src/gzgui.js b/gz3d/src/gzgui.js
index 559504cba34f546a21b26132605701df715dfa13..81ae97170e9111e5c06f3f4b2bb84d31c918b69d 100644
--- a/gz3d/src/gzgui.js
+++ b/gz3d/src/gzgui.js
@@ -5,7 +5,7 @@ var guiEvents = new EventEmitter2({ verbose: true });
var emUnits = function(value)
{
- return value*parseFloat($('body').css('font-size'));
+ return value*parseFloat($('#gz3d-body').css('font-size'));
};
var isTouchDevice = 'ontouchstart' in window || 'onmsgesturechange' in window;
@@ -25,160 +25,15 @@ var tabColors = {selected: 'rgb(34, 170, 221)', unselected: 'rgb(42, 42, 42)'};
var modelList =
[
- {path:'buildings', title:'Buildings',
- examplePath1:'fast_food', examplePath2:'kitchen_dining', examplePath3:'house_1', models:
+ {path:'virtual_room', title:'Virtual Room Objects',
+ examplePath1:'library_model', examplePath2:'hosta_potted_plant', examplePath3:'vr_lamp', models:
[
- {modelPath:'fast_food', modelTitle:'Fast Food'},
- {modelPath:'gas_station', modelTitle:'Gas Station'},
- {modelPath:'house_1', modelTitle:'House 1'},
- {modelPath:'house_2', modelTitle:'House 2'},
- {modelPath:'house_3', modelTitle:'House 3'},
- {modelPath:'iss', modelTitle:'International Space Station'},
- {modelPath:'iss_half', modelTitle:'ISS half'},
- {modelPath:'kitchen_dining', modelTitle:'Kitchen and Dining'},
- {modelPath:'office_building', modelTitle:'Office Building'},
- {modelPath:'powerplant', modelTitle:'Power Plant'},
- {modelPath:'starting_pen', modelTitle:'Starting Pen'},
- {modelPath:'willowgarage', modelTitle:'Willow Garage'}
- ]},
-
- {path:'furniture', title:'Furniture',
- examplePath1:'hinged_door', examplePath2:'bookshelf', examplePath3:'table', models:
- [
- {modelPath:'bookshelf', modelTitle:'Book Shelf'},
- {modelPath:'cabinet', modelTitle:'Cabinet'},
- {modelPath:'drc_practice_door_4x8', modelTitle:'4x8 Doorway'},
- {modelPath:'drc_practice_ladder', modelTitle:'Ladder'},
- {modelPath:'hinged_door', modelTitle:'Hinged Door'},
- {modelPath:'table', modelTitle:'Table'},
- {modelPath:'table_marble', modelTitle:'Table Marble'},
-
- {modelPath:'drc_practice_ball_valve', modelTitle:'Ball Valve'},
- {modelPath:'drc_practice_handle_wheel_valve', modelTitle:'Handle Wheel Valve'},
- {modelPath:'drc_practice_hand_wheel_valve', modelTitle:'Hand Wheel Valve'},
- {modelPath:'drc_practice_wheel_valve', modelTitle:'Wheel Valve'},
- {modelPath:'drc_practice_wheel_valve_large', modelTitle:'Wheel Valve Large'},
- {modelPath:'door_handle', modelTitle:'Door Handle'},
-
- {modelPath:'drc_practice_ball_valve_wall', modelTitle:'Wall (Ball Valve)'},
- {modelPath:'drc_practice_handle_wheel_valve_wall', modelTitle:'Wall (Handle Wheel Valve)'},
- {modelPath:'drc_practice_hand_wheel_valve_wall', modelTitle:'Wall (Hand Wheel Valve)'},
- {modelPath:'drc_practice_valve_wall', modelTitle:'Wall (Valve)'},
- {modelPath:'drc_practice_wheel_valve_wall', modelTitle:'Wall (Wheel Valve)'},
- {modelPath:'drc_practice_wheel_valve_large_wall', modelTitle:'Wall (Wheel Valve Large)'},
- {modelPath:'grey_wall', modelTitle:'Grey Wall'},
- {modelPath:'asphalt_plane', modelTitle:'Asphalt Plane'},
- {modelPath:'drc_practice_base_4x8', modelTitle:'Debris base'},
- {modelPath:'ground_plane', modelTitle:'Ground Plane'},
- {modelPath:'nist_maze_wall_120', modelTitle:'120 Maze Wall'},
- {modelPath:'nist_maze_wall_240', modelTitle:'240 Maze Wall'},
- {modelPath:'nist_maze_wall_triple_holes_120', modelTitle:'120 Maze Wall Triple Holes'},
- {modelPath:'nist_simple_ramp_120', modelTitle:'Simple Ramp'},
- {modelPath:'nist_stairs_120', modelTitle:'Stairs'}
- ]},
-
- {path:'kitchen', title:'Kitchen',
- examplePath1:'saucepan', examplePath2:'beer', examplePath3:'bowl', models:
- [
- {modelPath:'beer', modelTitle:'Beer'},
- {modelPath:'bowl', modelTitle:'Bowl'},
- {modelPath:'coke_can', modelTitle:'Coke Can'},
- {modelPath:'saucepan', modelTitle:'Saucepan'}
- ]},
-
- {path:'robocup', title:'Robocup', examplePath1:'robocup_3Dsim_ball',
- examplePath2:'robocup14_spl_goal', examplePath3:'robocup09_spl_field', models:
- [
- {modelPath:'robocup09_spl_field', modelTitle:'2009 SPL Field'},
- {modelPath:'robocup14_spl_field', modelTitle:'2014 SPL Field'},
- {modelPath:'robocup_3Dsim_field', modelTitle:'3D Sim. Field'},
- {modelPath:'robocup14_spl_goal', modelTitle:'SPL Goal'},
- {modelPath:'robocup_3Dsim_goal', modelTitle:'3D Sim. Goal'},
- {modelPath:'robocup_spl_ball', modelTitle:'SPL Ball'},
- {modelPath:'robocup_3Dsim_ball', modelTitle:'3D Sim. Ball'}
- ]},
-
- {path:'robots', title:'Robots',
- examplePath1:'pioneer3at', examplePath2:'turtlebot', examplePath3:'pr2', models:
- [
- {modelPath:'create', modelTitle:'Create'},
- {modelPath:'husky', modelTitle:'Husky'},
- {modelPath:'irobot_hand', modelTitle:'iRobot Hand'},
- {modelPath:'pioneer2dx', modelTitle:'Pioneer 2DX'},
- {modelPath:'pioneer3at', modelTitle:'Pioneer 3AT'},
- {modelPath:'pr2', modelTitle:'PR2'},
- {modelPath:'robonaut', modelTitle:'Robonaut'},
- {modelPath:'simple_arm', modelTitle:'Simple Arm'},
- {modelPath:'simple_arm_gripper', modelTitle:'Simple Arm and Gripper'},
- {modelPath:'simple_gripper', modelTitle:'Simple Gripper'},
- {modelPath:'turtlebot', modelTitle:'TurtleBot'},
- {modelPath:'youbot', modelTitle:'YouBot'}
- ]},
-
- {path:'sensors', title:'Sensors',
- examplePath1:'camera', examplePath2:'hokuyo', examplePath3:'kinect', models:
- [
- {modelPath:'camera', modelTitle:'Camera'},
- {modelPath:'stereo_camera', modelTitle:'Stereo Camera'},
- {modelPath:'hokuyo', modelTitle:'Hokuyo'},
- {modelPath:'kinect', modelTitle:'Kinect'}
- ]},
-
- {path:'street', title:'Street', examplePath1:'dumpster',
- examplePath2:'drc_practice_angled_barrier_45', examplePath3:'fire_hydrant', models:
- [
- {modelPath:'cinder_block', modelTitle:'Cinder Block'},
- {modelPath:'cinder_block_2', modelTitle:'Cinder Block 2'},
- {modelPath:'cinder_block_wide', modelTitle:'Cinder Block Wide'},
- {modelPath:'construction_barrel', modelTitle:'Construction Barrel'},
- {modelPath:'construction_cone', modelTitle:'Construction Cone'},
- {modelPath:'drc_practice_angled_barrier_45', modelTitle:'Angled Barrier 45'},
- {modelPath:'drc_practice_angled_barrier_135', modelTitle:'Angled Barrier 135'},
- {modelPath:'drc_practice_block_wall', modelTitle:'Block Wall'},
- {modelPath:'drc_practice_orange_jersey_barrier', modelTitle:'Jersey Barrier (Orange)'},
- {modelPath:'drc_practice_white_jersey_barrier', modelTitle:'Jersey Barrier (White)'},
- {modelPath:'drc_practice_truss', modelTitle:'Truss'},
- {modelPath:'drc_practice_yellow_parking_block', modelTitle:'Parking Block'},
- {modelPath:'dumpster', modelTitle:'Dumpster'},
- {modelPath:'fire_hydrant', modelTitle:'Fire Hydrant'},
- {modelPath:'jersey_barrier', modelTitle:'Jersey Barrier'},
- {modelPath:'lamp_post', modelTitle:'Lamp Post'},
- {modelPath:'mailbox', modelTitle:'Mailbox'},
- {modelPath:'mud_box', modelTitle:'Mud Box'},
- {modelPath:'nist_fiducial_barrel', modelTitle:'Fiducial Barrel'},
- {modelPath:'speed_limit_sign', modelTitle:'Speed Limit Sign'},
- {modelPath:'stop_sign', modelTitle:'Stop Sign'}
-
- ]},
-
- {path:'tools', title:'Tools', examplePath1:'hammer',
- examplePath2:'polaris_ranger_ev', examplePath3:'cordless_drill', models:
- [
- {modelPath:'cordless_drill', modelTitle:'Cordless Drill'},
- {modelPath:'fire_hose_long', modelTitle:'Fire Hose'},
- {modelPath:'fire_hose_long_curled', modelTitle:'Fire Hose Long Curled'},
- {modelPath:'hammer', modelTitle:'Hammer'},
- {modelPath:'monkey_wrench', modelTitle:'Monkey Wrench'},
- {modelPath:'polaris_ranger_ev', modelTitle:'Polaris Ranger EV'},
- {modelPath:'polaris_ranger_xp900', modelTitle:'Polaris Ranger XP900'},
- {modelPath:'polaris_ranger_xp900_no_roll_cage', modelTitle:'Polaris Ranger without roll cage'},
- {modelPath:'utility_cart', modelTitle:'Utility Cart'}
- ]},
-
- {path:'misc', title:'Misc.', examplePath1:'brick_box_3x1x3',
- examplePath2:'drc_practice_4x4x20', examplePath3:'double_pendulum_with_base', models:
- [
- {modelPath:'double_pendulum_with_base', modelTitle:'Double Pendulum With Base'},
- {modelPath:'breakable_test', modelTitle:'Breakable_test'},
- {modelPath:'brick_box_3x1x3', modelTitle:'Brick Box 3x1x3'},
- {modelPath:'cube_20k', modelTitle:'Cube 20k'},
- {modelPath:'drc_practice_2x4', modelTitle:'2x4 Lumber'},
- {modelPath:'drc_practice_2x6', modelTitle:'2x6 Lumber'},
- {modelPath:'drc_practice_4x4x20', modelTitle:'4x4x20 Lumber'},
- {modelPath:'drc_practice_4x4x40', modelTitle:'4x4x40 Lumber'},
- {modelPath:'drc_practice_blue_cylinder', modelTitle:'Blue Cylinder'},
- {modelPath:'drc_practice_wood_slats', modelTitle:'Wood Slats'},
- {modelPath:'nist_elevated_floor_120', modelTitle:'Elevated Floor 120'}
+ {modelPath:'library_model', modelTitle:'Library'},
+ {modelPath:'hosta_potted_plant', modelTitle:'Hosta Plant'},
+ {modelPath:'vr_lamp', modelTitle:'Stand Lamp'},
+ {modelPath:'vr_screen', modelTitle:'Virtual Screen'},
+ {modelPath:'viz_poster', modelTitle:'Poster 1'},
+ {modelPath:'viz_poster_2', modelTitle:'Poster 2'}
]}
];
@@ -187,7 +42,7 @@ $(function()
//Initialize
if ('ontouchstart' in window || 'onmsgesturechange' in window)
{
- $('body').addClass('isTouchDevice');
+ $('#gz3d-body').addClass('isTouchDevice');
}
// Toggle items
@@ -487,6 +342,14 @@ $(function()
guiEvents.emit('show_orbit_indicator');
guiEvents.emit('closeTabs', false);
});
+ $('#view-shadows').click(function()
+ {
+ guiEvents.emit('show_shadows', 'toggle');
+ });
+ $('#view-camera-sensors').click(function()
+ {
+ guiEvents.emit('show_camera_sensors', 'toggle');
+ });
$( '#snap-to-grid' ).click(function() {
guiEvents.emit('snap_to_grid');
guiEvents.emit('closeTabs', false);
@@ -501,13 +364,12 @@ $(function()
});
// Disable Esc key to close panel
- $('body').on('keyup', function(event)
- {
- if (event.which === 27)
- {
- return false;
- }
- });
+ $('#gz3d-body').on('keyup', function(event) {
+ if (event.which === 27)
+ {
+ return false;
+ }
+ });
// Object menu
$( '#view-transparent' ).click(function() {
@@ -835,6 +697,73 @@ GZ3D.Gui.prototype.init = function()
}
);
+ guiEvents.on('show_shadows', function(option)
+ {
+ if (option === 'show')
+ {
+ //that.emitter.emit('setShadows', true);
+ that.scene.setShadowMaps(true);
+ }
+ else if (option === 'hide')
+ {
+ //that.emitter.emit('setShadows', false);
+ that.scene.setShadowMaps(false);
+ }
+ else if (option === 'toggle')
+ {
+ var shadowsEnabled = that.scene.renderer.shadowMapEnabled;
+ //that.emitter.emit('setShadows', !shadowsEnabled);
+ that.scene.setShadowMaps(!shadowsEnabled);
+ }
+
+ if(!that.scene.renderer.shadowMapEnabled)
+ {
+ $('#view-shadows').buttonMarkup({icon: 'false'});
+ guiEvents.emit('notification_popup','Disabling shadows');
+ }
+ else
+ {
+ $('#view-shadows').buttonMarkup({icon: 'check'});
+ guiEvents.emit('notification_popup','Enabling shadows');
+ }
+ }
+ );
+
+ guiEvents.on('show_camera_sensors', function(option)
+ {
+ var camerasShown = false;
+ if (option === 'show')
+ {
+ that.scene.viewManager.showCameras(true);
+ }
+ else if (option === 'hide')
+ {
+ that.scene.viewManager.showCameras(false);
+ }
+ else if (option === 'toggle')
+ {
+ if (that.scene.viewManager.views.length > 1) {
+ camerasShown = that.scene.viewManager.views[1].active;
+ that.scene.viewManager.showCameras(!camerasShown);
+ }
+ }
+
+ if (that.scene.viewManager.views.length > 1) {
+ camerasShown = that.scene.viewManager.views[1].active;
+ }
+ if(!camerasShown)
+ {
+ $('#view-camera-sensors').buttonMarkup({icon: 'false'});
+ guiEvents.emit('notification_popup','Disabling camera views');
+ }
+ else
+ {
+ $('#view-camera-sensors').buttonMarkup({icon: 'check'});
+ guiEvents.emit('notification_popup','Enabling camera views');
+ }
+ }
+ );
+
guiEvents.on('pause', function(paused)
{
that.emitter.emit('pause', paused);
@@ -1077,7 +1006,7 @@ GZ3D.Gui.prototype.init = function()
$( '#notification-popup' ).html(' '+notification+' ');
$( '#notification-popup' ).popup('open', {
y:window.innerHeight-50});
-
+
if (duration === undefined)
{
duration = 2000;
@@ -1136,7 +1065,8 @@ GZ3D.Gui.prototype.init = function()
lastOpenMenu[parentId] = id;
$('.leftPanels').hide();
- $('#'+id).show();
+ //$('#'+id).show(); //defaults as flex, but block is needed
+ $('#'+id).css('display','block');
$('.tab').css('border-left-color', tabColors.unselected);
$('#'+parentId+'Tab').css('border-left-color', tabColors.selected);
@@ -1605,17 +1535,20 @@ GZ3D.Gui.prototype.setModelStats = function(stats, action)
return e.shortName === LinkShortName;
});
- if (link[0].self_collide)
+ if (link[0])
{
- link[0].self_collide = this.trueOrFalse(stats.link[0].self_collide);
- }
- if (link[0].gravity)
- {
- link[0].gravity = this.trueOrFalse(stats.link[0].gravity);
- }
- if (link[0].kinematic)
- {
- link[0].kinematic = this.trueOrFalse(stats.link[0].kinematic);
+ if (link[0].self_collide)
+ {
+ link[0].self_collide = this.trueOrFalse(stats.link[0].self_collide);
+ }
+ if (link[0].gravity)
+ {
+ link[0].gravity = this.trueOrFalse(stats.link[0].gravity);
+ }
+ if (link[0].kinematic)
+ {
+ link[0].kinematic = this.trueOrFalse(stats.link[0].kinematic);
+ }
}
}
@@ -1692,10 +1625,10 @@ GZ3D.Gui.prototype.setLightStats = function(stats, action)
var thumbnail;
switch(type)
{
- case 2:
+ case GZ3D.LIGHT_SPOT:
thumbnail = 'style/images/spotlight.png';
break;
- case 3:
+ case GZ3D.LIGHT_DIRECTIONAL:
thumbnail = 'style/images/directionallight.png';
break;
default:
@@ -1797,7 +1730,10 @@ GZ3D.Gui.prototype.findModelThumbnail = function(instanceName)
GZ3D.Gui.prototype.updateStats = function()
{
var tree = angular.element($('#treeMenu')).scope();
- tree.updateStats();
+ if (typeof(tree) !== 'undefined' && typeof tree.updateStats !== 'undefined')
+ {
+ tree.updateStats();
+ }
};
/**
@@ -1922,10 +1858,12 @@ GZ3D.Gui.prototype.formatStats = function(stats)
colorHex = {};
for (comp in diffuse)
{
- colorHex[comp] = diffuse[comp].toString(16);
- if (colorHex[comp].length === 1)
- {
- colorHex[comp] = '0' + colorHex[comp];
+ if (diffuse.hasOwnProperty(comp)) {
+ colorHex[comp] = diffuse[comp].toString(16);
+ if (colorHex[comp].length === 1)
+ {
+ colorHex[comp] = '0' + colorHex[comp];
+ }
}
}
color.diffuse = '#' + colorHex['r'] + colorHex['g'] + colorHex['b'];
@@ -1938,10 +1876,12 @@ GZ3D.Gui.prototype.formatStats = function(stats)
colorHex = {};
for (comp in specular)
{
- colorHex[comp] = specular[comp].toString(16);
- if (colorHex[comp].length === 1)
- {
- colorHex[comp] = '0' + colorHex[comp];
+ if (specular.hasOwnProperty(comp)) {
+ colorHex[comp] = specular[comp].toString(16);
+ if (colorHex[comp].length === 1)
+ {
+ colorHex[comp] = '0' + colorHex[comp];
+ }
}
}
color.specular = '#' + colorHex['r'] + colorHex['g'] + colorHex['b'];
diff --git a/gz3d/src/gziface.js b/gz3d/src/gziface.js
index e97d0e54ff7413747d719c3a07c153bd9b76a1d8..5e28028356bef6362bd97774cdd8f4bd7f5e525c 100644
--- a/gz3d/src/gziface.js
+++ b/gz3d/src/gziface.js
@@ -1,5 +1,7 @@
//var GAZEBO_MODEL_DATABASE_URI='http://gazebosim.org/models';
+THREE.ImageUtils.crossOrigin = 'anonymous'; // needed to allow cross-origin loading of textures
+
GZ3D.GZIface = function(scene, gui)
{
this.scene = scene;
@@ -15,6 +17,13 @@ GZ3D.GZIface = function(scene, gui)
this.numConnectionTrials = 0;
this.maxConnectionTrials = 30; // try to connect 30 times
this.timeToSleepBtwTrials = 1000; // wait 1 second between connection trials
+
+ this.assetProgressData = {};
+ this.assetProgressData.assets = [];
+ this.assetProgressData.prepared = false;
+ this.assetProgressCallback = undefined;
+
+ this.webSocketConnectionCallbacks = [];
};
GZ3D.GZIface.prototype.init = function()
@@ -25,11 +34,35 @@ GZ3D.GZIface.prototype.init = function()
this.connect();
};
+GZ3D.GZIface.prototype.setAssetProgressCallback = function(callback)
+{
+ this.assetProgressCallback = callback;
+};
+
+GZ3D.GZIface.prototype.registerWebSocketConnectionCallback = function(callback) {
+ this.webSocketConnectionCallbacks.push(callback);
+};
+
GZ3D.GZIface.prototype.connect = function()
{
// connect to websocket
+ var url = GZ3D.webSocketUrl;
+ if (!localStorage.getItem('localmode.forceuser')) {
+ var token = [];
+ if (localStorage.getItem('tokens-neurorobotics-ui@https://services.humanbrainproject.eu/oidc')) {
+ try {
+ token = JSON.parse(localStorage.getItem('tokens-neurorobotics-ui@https://services.humanbrainproject.eu/oidc'));
+ } catch(e) {
+ token[0] = { access_token : 'notoken' };
+ }
+ url = url + '/?token=' + token[0].access_token;
+ } else {
+ url = 'ws://' + location.hostname + ':7681';
+ }
+ }
+
this.webSocket = new ROSLIB.Ros({
- url : 'ws://' + location.hostname + ':7681'
+ url : url
});
var that = this;
@@ -39,6 +72,9 @@ GZ3D.GZIface.prototype.connect = function()
this.webSocket.on('error', function() {
that.onError();
});
+ this.webSocket.on('close', function() {
+ console.log('Connection closed to websocket server: ' + that.webSocket.socket.url);
+ });
this.numConnectionTrials++;
};
@@ -63,6 +99,8 @@ GZ3D.GZIface.prototype.onError = function()
GZ3D.GZIface.prototype.onConnected = function()
{
+ console.log('Connected to websocket server: ' + this.webSocket.socket.url);
+
this.isConnected = true;
this.emitter.emit('connection');
@@ -84,6 +122,11 @@ GZ3D.GZIface.prototype.onConnected = function()
setInterval(publishHeartbeat, 5000);
+ // call all the registered callbacks since we are connected now
+ this.webSocketConnectionCallbacks.forEach(function(callback) {
+ callback();
+ });
+
var statusTopic = new ROSLIB.Topic({
ros: this.webSocket,
name: '~/status',
@@ -129,7 +172,7 @@ GZ3D.GZIface.prototype.onConnected = function()
if (message.grid === true)
{
- this.gui.guiEvents.emit('show_grid', 'show');
+ //this.gui.guiEvents.emit('show_grid', 'show'); // do not show grid by default for now
}
if (message.ambient)
@@ -169,6 +212,7 @@ GZ3D.GZIface.prototype.onConnected = function()
this.gui.setModelStats(model, 'update');
}
+ this.assetProgressData.prepared = true;
this.gui.setSceneStats(message);
this.sceneTopic.unsubscribe();
};
@@ -277,6 +321,8 @@ GZ3D.GZIface.prototype.onConnected = function()
}
i++;
}
+ } else {
+ this.updateModelFromMsg(this.scene.getByName(message.name), message);
}
this.gui.setModelStats(message, 'update');
};
@@ -399,7 +445,7 @@ GZ3D.GZIface.prototype.onConnected = function()
messageType : 'light',
});
- var publishEntityModify = function(entity)
+ var createEntityModifyMessage = function(entity)
{
var matrix = entity.matrixWorld;
var translation = new THREE.Vector3();
@@ -426,43 +472,89 @@ GZ3D.GZIface.prototype.onConnected = function()
z: quaternion.z
}
};
- if (entity.children[0] &&
- entity.children[0] instanceof THREE.Light)
+ return entityMsg;
+ };
+
+ /*
+ TODO: (Sandro Weber)
+ The following functions are used to change all lights at the same time through the light slider of the NRP.
+ Gazebo only knows attenuation factors, not intensity, so we manipulate diffuse color for now.
+ Probably replaced / revamped after a dedicated edit tab is introduced to allow manipulation of lights directly.
+ */
+ var createEntityModifyMessageWithLight = function(entity, diffuse)
+ {
+ var entityMsg = createEntityModifyMessage(entity);
+
+ var lightObj = entity.children[0];
+
+ if (diffuse === undefined) {
+ diffuse = lightObj.color;
+ }
+ entityMsg.diffuse =
{
- entityMsg.diffuse =
- {
- r: entity.children[0].color.r,
- g: entity.children[0].color.g,
- b: entity.children[0].color.b
- };
- entityMsg.specular =
- {
- r: entity.serverProperties.specular.r,
- g: entity.serverProperties.specular.g,
- b: entity.serverProperties.specular.b
- };
- entityMsg.direction = entity.direction;
- entityMsg.range = entity.children[0].distance;
- entityMsg.attenuation_constant = entity.serverProperties.attenuation_constant;
- entityMsg.attenuation_linear = entity.serverProperties.attenuation_linear;
- entityMsg.attenuation_quadratic = entity.serverProperties.attenuation_quadratic;
-
- that.lightModifyTopic.publish(entityMsg);
+ r: diffuse.r,
+ g: diffuse.g,
+ b: diffuse.b
+ };
+ entityMsg.specular =
+ {
+ r: entity.serverProperties.specular.r,
+ g: entity.serverProperties.specular.g,
+ b: entity.serverProperties.specular.b
+ };
+ entityMsg.direction = entity.direction;
+ entityMsg.range = lightObj.distance;
+
+ entityMsg.attenuation_constant = entity.serverProperties.attenuation_constant;
+ entityMsg.attenuation_linear = entity.serverProperties.attenuation_linear;
+ entityMsg.attenuation_quadratic = entity.serverProperties.attenuation_quadratic;
+
+ return entityMsg;
+ };
+
+ var publishEntityModify = function(entity)
+ {
+ var lightObj = entity.children[0];
+ if (lightObj && lightObj instanceof THREE.Light)
+ {
+ that.lightModifyTopic.publish(createEntityModifyMessageWithLight(entity, undefined));
}
else
{
- that.modelModifyTopic.publish(entityMsg);
+ that.modelModifyTopic.publish(createEntityModifyMessage(entity));
}
};
this.scene.emitter.on('entityChanged', publishEntityModify);
- // Link messages - for modifying links
- this.linkModifyTopic = new ROSLIB.Topic({
- ros : this.webSocket,
- name : '~/link',
- messageType : 'link',
- });
+ var publishLightModify = function(ratio)
+ {
+ var lights = [];
+ that.scene.scene.traverse(function(node) {
+ if (node instanceof THREE.Light) {
+ lights.push(node);
+ }
+ });
+
+ var numberOfLights = lights.length;
+ for (var i = 0; i < numberOfLights; i+=1) {
+ if( lights[i] instanceof THREE.AmbientLight ) { // we don't change ambient lights
+ continue;
+ }
+ var entity = that.scene.getByName(lights[i].name);
+ var newDiffuse = new THREE.Color();
+ newDiffuse.r = THREE.Math.clamp(ratio * entity.serverProperties.initial.diffuse.r, 0, 1);
+ newDiffuse.g = THREE.Math.clamp(ratio * entity.serverProperties.initial.diffuse.g, 0, 1);
+ newDiffuse.b = THREE.Math.clamp(ratio * entity.serverProperties.initial.diffuse.b, 0, 1);
+
+ that.lightModifyTopic.publish(createEntityModifyMessageWithLight(entity, newDiffuse));
+ }
+ };
+
+ this.scene.emitter.on('lightChanged', publishLightModify);
+ /*
+ end of light slider change functions
+ */
var publishLinkModify = function(entity, type)
{
@@ -729,6 +821,16 @@ GZ3D.GZIface.prototype.createModelFromMsg = function(model)
}
}
}
+
+ for (var i = 0; i < link.sensor.length; ++i) {
+ var sensor = link.sensor[i];
+
+ var sensorObj = this.createSensorFromMsg(sensor);
+ if (sensorObj && !sensorObj.parent)
+ {
+ linkObj.add(sensorObj);
+ }
+ }
}
if (model.joint)
{
@@ -738,6 +840,24 @@ GZ3D.GZIface.prototype.createModelFromMsg = function(model)
return modelObj;
};
+// This method uses code also to be found at GZ3D.GZIface.prototype.createModelFromMsg.
+// Currently not everything is handled for an update, but this method was introduced to handle
+// the updates of colors of objects; if there should be more functionality one could consider
+// merging the two methods and extracting the different things to parameters (or any other means
+// of configuration).
+GZ3D.GZIface.prototype.updateModelFromMsg = function (modelObj, modelMsg) {
+ for (var j = 0; j < modelMsg.link.length; ++j) {
+ var link = modelMsg.link[j];
+ var linkObj = modelObj.children[j];
+
+ for (var k = 0; k < link.visual.length; ++k) {
+ var visual = link.visual[k];
+ var visualObj = linkObj.getObjectByName(visual.name);
+ this.updateVisualFromMsg(visualObj, visual);
+ }
+ }
+};
+
GZ3D.GZIface.prototype.createVisualFromMsg = function(visual)
{
if (visual.geometry)
@@ -760,21 +880,32 @@ GZ3D.GZIface.prototype.createVisualFromMsg = function(visual)
}
};
+GZ3D.GZIface.prototype.updateVisualFromMsg = function (visualObj, visual) {
+ if (visual.geometry) {
+ var obj = visualObj.children[0];
+ var mat = this.parseMaterial(visual.material);
+
+ if (obj && mat) {
+ this.scene.setMaterial(obj, mat);
+ }
+ }
+};
+
GZ3D.GZIface.prototype.createLightFromMsg = function(light)
{
var obj, range, direction;
- if (light.type === 1)
+ if (light.type === this.scene.LIGHT_POINT)
{
direction = null;
range = light.range;
}
- else if (light.type === 2)
+ else if (light.type === this.scene.LIGHT_SPOT)
{
direction = light.direction;
range = light.range;
}
- else if (light.type === 3)
+ else if (light.type === this.scene.LIGHT_DIRECTIONAL)
{
direction = light.direction;
range = null;
@@ -812,9 +943,66 @@ GZ3D.GZIface.prototype.createRoadsFromMsg = function(roads)
return roadObj;
};
+GZ3D.GZIface.prototype.createSensorFromMsg = function(sensor)
+{
+ var sensorObj = new THREE.Object3D();
+ sensorObj.name = sensor.name;
+
+ if (sensor.pose) {
+ this.scene.setPose(sensorObj, sensor.pose.position, sensor.pose.orientation);
+ }
+
+ if (sensor.type === 'camera') {
+ // if we have a camera sensor we have a potential view that could be rendered
+ // camera parameters are not published by gazebo right now, so hardcoded until fixed
+ var displayParams = {
+ left: '5%',
+ top: '5%',
+ width: '20%',
+ height: '20%',
+ adjustable: true
+ };
+ var cameraParams = {
+ width: 960,
+ height: 600,
+ fov: 60,
+ near: 0.1,
+ far: 100
+ };
+ var viewName = 'view_' + sensor.name;
+ var view = this.scene.viewManager.createView(viewName, displayParams, cameraParams);
+ if (!view) {
+ console.error('GZ3D.GZIface.createSensorFromMsg() - failed to create view ' + viewName);
+ return;
+ }
+
+ // There is a problem with the width and height; it should be read from the "sensor" object. Also see:
+ // https://bitbucket.org/osrf/gazebo/issues/1663/sensor-camera-elements-from-sdf-not-being
+
+ // camera sensors defined in gazebo .sdf seem to look along positive x axis, so need to adjust the rotation here
+ view.camera.rotateOnAxis(new THREE.Vector3(0, 1, 0), -Math.PI / 2);
+ view.camera.rotateOnAxis(new THREE.Vector3(0, 0, 1), -Math.PI / 2);
+
+ // set view inactive and hide at start
+ this.scene.viewManager.setViewVisibility(view, false);
+
+ // visualization - Deactivated since it causes the robot to be very big and the user
+ // can't barely select other objects on the scene. Reactivate for debug purposes !
+ // var cameraHelper = new THREE.CameraHelper(view.camera);
+ // view.camera.add( cameraHelper );
+
+ view.type = sensor.type;
+ console.log('view type: ' + view.type);
+
+ sensorObj.add(view.camera);
+ }
+
+ return sensorObj;
+};
+
GZ3D.GZIface.prototype.parseUri = function(uri)
{
- var uriPath = 'assets';
+ var uriPath = GZ3D.assetsPath;
var idx = uri.indexOf('://');
if (idx > 0)
{
@@ -826,7 +1014,7 @@ GZ3D.GZIface.prototype.parseUri = function(uri)
GZ3D.GZIface.prototype.createGeom = function(geom, material, parent)
{
var obj;
- var uriPath = 'assets';
+ var uriPath = GZ3D.assetsPath;
var that = this;
var mat = this.parseMaterial(material);
if (geom.box)
@@ -906,26 +1094,48 @@ GZ3D.GZIface.prototype.createGeom = function(geom, material, parent)
var modelUri = uriPath + '/' + modelName;
// Use coarse version on touch devices
- if (modelUri.indexOf('.dae') !== -1 && isTouchDevice)
+ if (modelUri.indexOf('.dae') !== -1 /*&& isTouchDevice*/) // Modified for HBP, we do use coarse models all the time
{
modelUri = modelUri.substring(0,modelUri.indexOf('.dae'));
- var checkModel = new XMLHttpRequest();
- checkModel.open('HEAD', modelUri+'_coarse.dae', false);
- checkModel.send();
- if (checkModel.status === 404)
+ if(modelUri.indexOf('_coarse') !== -1) //dae is already a coarse model
{
modelUri = modelUri+'.dae';
}
- else
- {
- modelUri = modelUri+'_coarse.dae';
+ else { // check if a coarse version is available
+ var checkModel = new XMLHttpRequest();
+ // We use a double technique to disable the cache for these requests:
+ // 1. We create a custom url by adding the time as a parameter.
+ // 2. We add the If-Modified-Since header with a date far in the future (end of the HBP project)
+ // Since browsers and servers vary in their behaviour, we use both of these tricks.
+ // PS: These requests do not load the dae files, they just verify if they exist on the server
+ // so that we can choose between coarse or reqular models.
+ checkModel.open('HEAD', modelUri+'_coarse.dae?timestamp=' + new Date().getTime(), false);
+ checkModel.setRequestHeader('If-Modified-Since', 'Sat, 1 Jan 2026 00:00:00 GMT');
+
+ try { checkModel.send(); } catch(err) { console.log(modelUri + ': no coarse version'); }
+
+ if (checkModel.status === 404) {
+ modelUri = modelUri+'.dae';
+ }
+ else {
+ modelUri = modelUri+'_coarse.dae';
+ }
}
}
var materialName = parent.name + '::' + modelUri;
this.entityMaterial[materialName] = mat;
+ // Progress update: Add this asset to the assetProgressArray
+ var element = {};
+ element.id = parent.name;
+ element.url = modelUri;
+ element.progress = 0;
+ element.totalSize = 0;
+ element.done = false;
+ this.assetProgressData.assets.push(element);
+
this.scene.loadMesh(modelUri, submesh,
centerSubmesh, function(dae) {
if (that.entityMaterial[materialName])
@@ -944,6 +1154,19 @@ GZ3D.GZIface.prototype.createGeom = function(geom, material, parent)
}
parent.add(dae);
loadGeom(parent);
+
+ // Progress update: execute callback
+ element.done = true;
+ if (that.assetProgressCallback) {
+ that.assetProgressCallback(that.assetProgressData);
+ }
+ }, function(progress){
+ element.progress = progress.loaded;
+ element.totalSize = progress.total;
+ element.error = progress.error;
+ if (that.assetProgressCallback) {
+ that.assetProgressCallback(that.assetProgressData);
+ }
});
}
}
@@ -1019,7 +1242,7 @@ GZ3D.GZIface.prototype.createGeom = function(geom, material, parent)
allChildren[c].castShadow = false;
allChildren[c].receiveShadow = false;
- allChildren[c].visible = this.scene.showCollisions;
+ allChildren[c].visible = that.scene.showCollisions;
}
}
}
@@ -1077,7 +1300,7 @@ GZ3D.GZIface.prototype.parseMaterial = function(material)
return null;
}
- var uriPath = 'assets';
+ var uriPath = GZ3D.assetsPath;//'assets';
var texture;
var normalMap;
var textureUri;
diff --git a/gz3d/src/gzmanipulator.js b/gz3d/src/gzmanipulator.js
index 84e9cadfbd303cdb19667bda4075bdf3d3c0542d..e48ee73f46322a29e2d2b9872b605566ab35a64e 100644
--- a/gz3d/src/gzmanipulator.js
+++ b/gz3d/src/gzmanipulator.js
@@ -520,10 +520,10 @@ GZ3D.Manipulator = function(camera, mobile, domElement, doc)
}
this.object.updateMatrixWorld();
- worldPosition.getPositionFromMatrix(this.object.matrixWorld);
+ worldPosition.setFromMatrixPosition(this.object.matrixWorld);
this.camera.updateMatrixWorld();
- camPosition.getPositionFromMatrix(this.camera.matrixWorld);
+ camPosition.setFromMatrixPosition(this.camera.matrixWorld);
scale = worldPosition.distanceTo(camPosition) / 6 * this.scale;
this.gizmo.position.copy(worldPosition);
@@ -775,7 +775,7 @@ GZ3D.Manipulator = function(camera, mobile, domElement, doc)
worldRotationMatrix.extractRotation(scope.object.matrixWorld);
parentRotationMatrix.extractRotation(scope.object.parent.matrixWorld);
- parentScale.getScaleFromMatrix(tempMatrix.getInverse(
+ parentScale.setFromMatrixScale(tempMatrix.getInverse(
scope.object.parent.matrixWorld));
offset.copy(planeIntersect.point);
@@ -890,7 +890,7 @@ GZ3D.Manipulator = function(camera, mobile, domElement, doc)
parentRotationMatrix.extractRotation(
scope.object.parent.matrixWorld);
- parentScale.getScaleFromMatrix(tempMatrix.getInverse(
+ parentScale.setFromMatrixScale(tempMatrix.getInverse(
scope.object.parent.matrixWorld));
offset.copy(planeIntersect.point);
diff --git a/gz3d/src/gzmultiview.js b/gz3d/src/gzmultiview.js
new file mode 100644
index 0000000000000000000000000000000000000000..16aaa50efd37119940004316ea4d95248e4dd786
--- /dev/null
+++ b/gz3d/src/gzmultiview.js
@@ -0,0 +1,281 @@
+/**
+ * Created by Sandro Weber (webers@in.tum.de).
+ */
+
+GZ3D.MULTIVIEW_MAX_VIEW_COUNT = 10;
+
+/**
+ * GZ3D.MULTIVIEW_RENDER_VIEWPORTS uses view containers as transparent references to determine viewports for rendering (one single canvas).
+ * This is broken in combination with shadowmaps at the moment. See renderToViewport() method.
+ *
+ * @type {number}
+ */
+GZ3D.MULTIVIEW_RENDER_VIEWPORTS = 1;
+/**
+ * GZ3D.MULTIVIEW_RENDER_COPY2CANVAS renders views offscreen then copies into the view containers (multiple separate canvases).
+ * @type {number}
+ */
+GZ3D.MULTIVIEW_RENDER_COPY2CANVAS = 2;
+
+GZ3D.MultiView = function(gz3dScene, mainContainer, callbackCreateRenderContainer)
+{
+ this.gz3dScene = gz3dScene;
+ this.mainContainer = mainContainer;
+ this.createRenderContainerCallback = callbackCreateRenderContainer;
+
+ this.init();
+};
+
+GZ3D.MultiView.prototype.init = function()
+{
+ this.views = [];
+
+ this.mainContainer.style.zIndex = 0;
+
+ this.renderMethod = GZ3D.MULTIVIEW_RENDER_COPY2CANVAS;
+ if (this.renderMethod === GZ3D.MULTIVIEW_RENDER_VIEWPORTS) {
+ this.mainContainer.appendChild(this.gz3dScene.getDomElement());
+ }
+};
+
+GZ3D.MultiView.prototype.setCallbackCreateRenderContainer = function(callback)
+{
+ this.createRenderContainerCallback = callback;
+};
+
+/**
+ *
+ * @param name
+ * @param displayParams {left, top, width, height, zIndex, adjustable}
+ * @param cameraParams {width, height, fov, near, far}
+ */
+GZ3D.MultiView.prototype.createView = function(name, displayParams, cameraParams)
+{
+ if (this.getViewByName(name) !== undefined) {
+ console.error('GZ3D.MultiView.createView() - a view of that name already exists (' + name + ')');
+ return null;
+ }
+
+ if (this.views.length >= this.MULTIVIEW_MAX_VIEW_COUNT) {
+ console.warn('GZ3D.MultiView.createView() - creating new view will exceed MULTIVIEW_MAX_VIEW_COUNT(' + this.MULTIVIEW_MAX_VIEW_COUNT + '). This may cause z-ordering issues.');
+ }
+
+ var container = this.createViewContainer(displayParams, name);
+ if (container === null) {
+ return;
+ }
+
+ // camera
+ var camera = new THREE.PerspectiveCamera(cameraParams.fov, cameraParams.width / cameraParams.height, cameraParams.near, cameraParams.far);
+ camera.name = name;
+
+ // assemble view
+ var view = {
+ name: name,
+ active: true,
+ container: container,
+ camera: camera
+ };
+
+ this.views.push(view);
+ this.mainContainer.appendChild(view.container);
+
+ return view;
+};
+
+GZ3D.MultiView.prototype.createViewContainer = function(displayParams, name)
+{
+ if (this.createRenderContainerCallback === undefined) {
+ console.error('GZ3D.MultiView.createViewContainer() - no callback for creating view reference container defined');
+ return null;
+ }
+
+ // container div
+ var viewContainer = this.createRenderContainerCallback(displayParams.adjustable, name);
+ if (!viewContainer) {
+ console.error('GZ3D.MultiView.createViewContainer() - could not create view container via callback');
+ return null;
+ }
+
+ // positioning
+ viewContainer.style.position = 'absolute';
+ viewContainer.style.left = displayParams.left;
+ viewContainer.style.top = displayParams.top;
+ // There is a problem with the width and height; it should be read from the "sensor" object. Also see:
+ // https://bitbucket.org/osrf/gazebo/issues/1663/sensor-camera-elements-from-sdf-not-being
+ // Here we use (preliminary) percentual width.
+ viewContainer.style.width = displayParams.width;
+ viewContainer.style.height = displayParams.height;
+
+ // We set 50px as a min-width for now and set the min height accordingly
+ viewContainer.style.minWidth = '50px';
+ viewContainer.style.minHeight = (50 * (parseInt(displayParams.width, 10)/parseInt(displayParams.height, 10))) + 'px';
+ viewContainer.style.maxWidth = '100%';
+ viewContainer.style.maxHeight = '100%';
+
+ // transparent view-container so we can render viewport with one renderer in the same context
+ // view-container is only taken as reference for viewport
+ viewContainer.style.boxShadow = '0px 0px 0px 3px rgba(0,0,0,0.3)';
+ viewContainer.style.borderRadius = '2px';
+ viewContainer.style.background = 'rgba(0,0,0,0)';
+
+ if (this.renderMethod === GZ3D.MULTIVIEW_RENDER_COPY2CANVAS) {
+ // canvas
+ viewContainer.canvas = document.createElement('canvas');
+ viewContainer.appendChild( viewContainer.canvas );
+ viewContainer.canvas.style.width = '100%';
+ viewContainer.canvas.style.height = '100%';
+ }
+
+ // z-index
+ var zIndexTop = parseInt(this.mainContainer.style.zIndex, 10) + this.views.length + 1;
+ viewContainer.style.zIndex = (displayParams.zIndex !== undefined) ? displayParams.zIndex : zIndexTop;
+
+ return viewContainer;
+};
+
+GZ3D.MultiView.prototype.getViewByName = function(name)
+{
+ for (var i = 0; i < this.views.length; i = i+1) {
+ if (this.views[i].name === name) {
+ return this.views[i];
+ }
+ }
+
+ return undefined;
+};
+
+GZ3D.MultiView.prototype.setViewVisibility = function(view, visible)
+{
+ view.active = visible;
+ if (view.active) {
+ view.container.style.visibility = 'visible';
+ } else {
+ view.container.style.visibility = 'hidden';
+ }
+};
+
+GZ3D.MultiView.prototype.updateCamera = function(view)
+{
+ view.camera.aspect = view.container.clientWidth / view.container.clientHeight;
+ view.camera.updateProjectionMatrix();
+};
+
+GZ3D.MultiView.prototype.getViewport = function(view)
+{
+ var viewport = {
+ x: view.container.offsetLeft,
+ y: this.mainContainer.clientHeight - view.container.clientHeight - view.container.offsetTop,
+ w: view.container.clientWidth,
+ h: view.container.clientHeight
+ };
+
+ return viewport;
+};
+
+GZ3D.MultiView.prototype.setWindowSize = function(width, height)
+{
+
+};
+
+GZ3D.MultiView.prototype.renderViews = function()
+{
+ // sort views into rendering order
+ this.views.sort(function(a, b) {
+ return a.container.style.zIndex - b.container.style.zIndex;
+ });
+
+ for (var i = 0, l = this.views.length; i < l; i = i+1) {
+ var view = this.views[i];
+
+ if (view.active) {
+ switch(this.renderMethod) {
+ case GZ3D.MULTIVIEW_RENDER_VIEWPORTS:
+ this.renderToViewport(view);
+ break;
+ case GZ3D.MULTIVIEW_RENDER_COPY2CANVAS:
+ this.renderAndCopyToCanvas(view);
+ break;
+ }
+ }
+ }
+};
+
+/**
+ * !IMPORTANT!
+ * https://github.com/mrdoob/three.js/issues/3532
+ * This is at the moment not a good idea, see issue above. ScissorTest will scramble shadowmaps.
+ *
+ * @param view
+ */
+GZ3D.MultiView.prototype.renderToViewport = function(view)
+{
+ this.updateCamera(view); //TODO: better solution with resize callback, also adjust camera helper
+
+ var webglRenderer = this.gz3dScene.renderer;
+
+ var viewport = this.getViewport(view);
+ webglRenderer.setViewport( viewport.x, viewport.y, viewport.w, viewport.h );
+ webglRenderer.setScissor( viewport.x, viewport.y, viewport.w, viewport.h );
+ webglRenderer.enableScissorTest ( true );
+
+ if (this.gz3dScene.effectsEnabled) {
+ this.gz3dScene.scene.overrideMaterial = this.depthMaterial;
+ this.gz3dScene.renderer.render(this.gz3dScene.scene, view.camera, this.depthTarget);
+ this.gz3dScene.scene.overrideMaterial = null;
+ this.gz3dScene.composer.render();
+ } else {
+ webglRenderer.render(this.gz3dScene.scene, view.camera);
+ }
+};
+
+GZ3D.MultiView.prototype.renderAndCopyToCanvas = function(view)
+{
+ this.updateCamera(view); //TODO: better solution with resize callback, also adjust camera helper
+
+ var webglRenderer = this.gz3dScene.renderer;
+
+ var width = view.container.canvas.clientWidth;
+ var height = view.container.canvas.clientHeight;
+ view.container.canvas.width = width;
+ view.container.canvas.height = height;
+
+ if (webglRenderer.context.canvas.width < width) {
+ webglRenderer.context.canvas.width = width;
+ }
+ if (webglRenderer.context.canvas.height < height) {
+ webglRenderer.context.canvas.height = height;
+ }
+ webglRenderer.setViewport( 0, 0, width, height );
+
+ if (this.gz3dScene.effectsEnabled) {
+ this.gz3dScene.scene.overrideMaterial = this.depthMaterial;
+ this.gz3dScene.renderer.render(this.gz3dScene.scene, view.camera, this.depthTarget);
+ this.gz3dScene.scene.overrideMaterial = null;
+ this.gz3dScene.composer.render();
+ } else {
+ webglRenderer.render(this.gz3dScene.scene, view.camera);
+ }
+
+ // copy rendered image over to view canvas
+ var srcX = 0;
+ var srcY = webglRenderer.context.canvas.height - height + 1;
+ var dstX = 0;
+ var dstY = 0;
+ // no cleaner solution right now, should be coming though: https://github.com/mrdoob/three.js/pull/6723#issuecomment-134129027
+ // this kills performance a little ...
+ if ( srcX >= 0 && srcY >= 0 && width >= 1 && height >= 1 ) {
+ view.container.canvas.getContext('2d').drawImage( webglRenderer.context.canvas,
+ srcX, srcY, width, height,
+ dstX, dstY, width, height );
+ }
+};
+
+GZ3D.MultiView.prototype.showCameras = function(show)
+{
+ for (var i = 0; i < this.views.length; i = i+1) {
+ if (this.views[i].type === 'camera') {
+ this.setViewVisibility(this.views[i], show);
+ }
+ }
+};
\ No newline at end of file
diff --git a/gz3d/src/gzscene.js b/gz3d/src/gzscene.js
index d8a6c0943bdfec4c97378193999a00551369e1b8..fb41118728f91a7a9c8242d45a1033310f244da1 100644
--- a/gz3d/src/gzscene.js
+++ b/gz3d/src/gzscene.js
@@ -1,5 +1,3 @@
-
-
/**
* The scene is where everything is placed, from objects, to lights and cameras.
* @constructor
@@ -9,6 +7,11 @@ GZ3D.Scene = function()
this.init();
};
+GZ3D.Scene.prototype.LIGHT_POINT = 1;
+GZ3D.Scene.prototype.LIGHT_SPOT = 2;
+GZ3D.Scene.prototype.LIGHT_DIRECTIONAL = 3;
+GZ3D.Scene.prototype.LIGHT_UNKNOWN = 4;
+
/**
* Initialize scene
*/
@@ -32,16 +35,38 @@ GZ3D.Scene.prototype.init = function()
this.renderer.setSize( window.innerWidth, window.innerHeight);
// shadows
- this.renderer.shadowMapEnabled = true;
+ this.renderer.shadowMapEnabled = false;
this.renderer.shadowMapType = THREE.PCFSoftShadowMap;
+ this.container = document.getElementById( 'container' );
+
+ // create views manager
+ this.viewManager = new GZ3D.MultiView(this, this.container, function(adjustable, name){
+ return document.createElement('div');
+ });
+ // create main view
+ var displayParams = {
+ left: '0px',
+ top: '0px',
+ width: '100%',
+ height: '100%',
+ adjustable: false
+ };
+ var cameraParams = {
+ width: 960,
+ height: 600,
+ fov: 60,
+ near: 0.1,
+ far: 100
+ };
+ this.viewManager.createView('main_view', displayParams, cameraParams);
+
// lights
this.ambient = new THREE.AmbientLight( 0x666666 );
this.scene.add(this.ambient);
// camera
- this.camera = new THREE.PerspectiveCamera(
- 60, window.innerWidth / window.innerHeight, 0.1, 1000 );
+ this.camera = this.viewManager.getViewByName('main_view').camera;
this.defaultCameraPosition = new THREE.Vector3(0, -5, 5);
this.resetView();
@@ -100,7 +125,12 @@ GZ3D.Scene.prototype.init = function()
this.timeDown = null;
- this.controls = new THREE.OrbitControls(this.camera);
+ var domElementForKeyBindings = document.getElementsByTagName('body')[0];
+ this.controls = new THREE.FirstPersonControls(this.camera, this.container, domElementForKeyBindings);
+ if (this.controls instanceof THREE.FirstPersonControls) {
+ this.controls.movementSpeed = 0.2;
+ this.controls.lookSpeed = 0.005;
+ }
if (this.controls.targetIndicator !== undefined) {
this.scene.add(this.controls.targetIndicator);
}
@@ -469,7 +499,7 @@ GZ3D.Scene.prototype.onPointerDown = function(event)
*/
GZ3D.Scene.prototype.onPointerUp = function(event)
{
- event.preventDefault();
+ //event.preventDefault();
// Clicks (<150ms) outside any models trigger view mode
var millisecs = new Date().getTime();
@@ -673,7 +703,7 @@ GZ3D.Scene.prototype.getRayCastModel = function(pos, intersect)
*/
GZ3D.Scene.prototype.getDomElement = function()
{
- return this.renderer.domElement;
+ return this.container;
};
/**
@@ -703,17 +733,7 @@ GZ3D.Scene.prototype.render = function()
this.modelManipulator.update();
this.radialMenu.update();
- if (this.effectsEnabled)
- {
- this.scene.overrideMaterial = this.depthMaterial;
- this.renderer.render(this.scene, this.camera, this.depthTarget);
- this.scene.overrideMaterial = null;
- this.composer.render();
- }
- else
- {
- this.renderer.render(this.scene, this.camera);
- }
+ this.viewManager.renderViews();
};
/**
@@ -727,6 +747,11 @@ GZ3D.Scene.prototype.setWindowSize = function(width, height)
this.camera.updateProjectionMatrix();
this.renderer.setSize( width, height);
+ this.renderer.context.canvas.width = width;
+ this.renderer.context.canvas.height = height;
+
+ this.viewManager.setWindowSize(width, height);
+
this.render();
};
@@ -915,6 +940,8 @@ GZ3D.Scene.prototype.createBox = function(width, height, depth)
* @param {} attenuation_constant
* @param {} attenuation_linear
* @param {} attenuation_quadratic
+ * @param {} spot_angle
+ * @param {} spot_falloff
* @returns {THREE.Object3D}
*/
GZ3D.Scene.prototype.createLight = function(type, diffuse, intensity, pose,
@@ -943,6 +970,10 @@ GZ3D.Scene.prototype.createLight = function(type, diffuse, intensity, pose,
specular = color.clone();
}
+ if (typeof(specular) === 'undefined') {
+ specular = 0xffffff;
+ }
+
var matrixWorld;
if (pose)
@@ -966,17 +997,17 @@ GZ3D.Scene.prototype.createLight = function(type, diffuse, intensity, pose,
}
var elements;
- if (type === 1)
+ if (type === this.LIGHT_POINT)
{
elements = this.createPointLight(obj, diffuse, intensity,
distance, cast_shadows);
}
- else if (type === 2)
+ else if (type === this.LIGHT_SPOT)
{
elements = this.createSpotLight(obj, diffuse, intensity,
distance, cast_shadows, spot_angle, spot_falloff);
}
- else if (type === 3)
+ else if (type === this.LIGHT_DIRECTIONAL)
{
elements = this.createDirectionalLight(obj, diffuse, intensity,
cast_shadows);
@@ -1011,13 +1042,16 @@ GZ3D.Scene.prototype.createLight = function(type, diffuse, intensity, pose,
obj.serverProperties.attenuation_constant = attenuation_constant;
obj.serverProperties.attenuation_linear = attenuation_linear;
obj.serverProperties.attenuation_quadratic = attenuation_quadratic;
+ obj.serverProperties.initial = {};
+ obj.serverProperties.initial.diffuse = diffuse;
- obj.add(lightObj);
- obj.add(helper);
-
+ helper.visible = false;
lightObj.up = new THREE.Vector3(0,0,1);
lightObj.shadowBias = -0.0005;
+ obj.add(lightObj);
+ obj.add(helper);
+
return obj;
};
@@ -1484,7 +1518,7 @@ GZ3D.Scene.prototype.loadHeightmap = function(heights, width, height,
* @param {function} callback
*/
GZ3D.Scene.prototype.loadMesh = function(uri, submesh, centerSubmesh,
- callback)
+ callback, progressCallback)
{
var uriPath = uri.substring(0, uri.lastIndexOf('/'));
var uriFile = uri.substring(uri.lastIndexOf('/') + 1);
@@ -1492,7 +1526,7 @@ GZ3D.Scene.prototype.loadMesh = function(uri, submesh, centerSubmesh,
// load urdf model
if (uriFile.substr(-4).toLowerCase() === '.dae')
{
- return this.loadCollada(uri, submesh, centerSubmesh, callback);
+ return this.loadCollada(uri, submesh, centerSubmesh, callback, progressCallback);
}
else if (uriFile.substr(-5).toLowerCase() === '.urdf')
{
@@ -1538,7 +1572,7 @@ GZ3D.Scene.prototype.loadMesh = function(uri, submesh, centerSubmesh,
* @param {function} callback
*/
GZ3D.Scene.prototype.loadCollada = function(uri, submesh, centerSubmesh,
- callback)
+ callback, progressCallback)
{
var dae;
var mesh = null;
@@ -1561,6 +1595,7 @@ GZ3D.Scene.prototype.loadCollada = function(uri, submesh, centerSubmesh,
var thatSubmesh = submesh;
var thatCenterSubmesh = centerSubmesh;
+ var that = this;
loader.load(uri, function(collada)
{
// check for a scale factor
@@ -1572,13 +1607,22 @@ GZ3D.Scene.prototype.loadCollada = function(uri, submesh, centerSubmesh,
dae = collada.scene;
dae.updateMatrix();
- this.scene.prepareColladaMesh(dae);
- this.scene.meshes[thatURI] = dae;
+ that.prepareColladaMesh(dae);
+ that.meshes[thatURI] = dae;
dae = dae.clone();
- this.scene.useColladaSubMesh(dae, thatSubmesh, centerSubmesh);
+ that.useColladaSubMesh(dae, thatSubmesh, centerSubmesh);
dae.name = uri;
callback(dae);
+ },function(progress) {
+ if (progressCallback !== undefined) {
+ progress.error = false;
+ progressCallback(progress);
+ }
+ },function(){
+ if (progressCallback !== undefined) {
+ progressCallback({ total: 0, loaded: 0, error: true });
+ }
});
};
@@ -1791,7 +1835,7 @@ GZ3D.Scene.prototype.setManipulationMode = function(mode)
}
else
{
- // Toggle manipulaion space (world / local)
+ // Toggle manipulation space (world / local)
if (this.modelManipulator.mode === this.manipulationMode)
{
this.modelManipulator.space =
@@ -2384,7 +2428,7 @@ GZ3D.Scene.prototype.updateLight = function(entity, msg)
this.setPose(entity, msg.pose.position, msg.pose.orientation);
entity.matrixWorldNeedsUpdate = true;
- if (entity.direction)
+ if (entity.direction && lightObj.target)
{
dir = new THREE.Vector3(entity.direction.x, entity.direction.y,
entity.direction.z);
@@ -2426,6 +2470,18 @@ GZ3D.Scene.prototype.updateLight = function(entity, msg)
entity.serverProperties.attenuation_quadratic = msg.attenuation_quadratic;
lightObj.intensity = lightObj.intensity/(1+msg.attenuation_quadratic);
}
+ if (msg.attenuation_linear && msg.attenuation_quadratic)
+ {
+ // equation taken from
+ // http://wiki.blender.org/index.php/Doc:2.6/Manual/Lighting/Lights/Light_Attenuation
+ var E = 1;
+ var D = 1;
+ var r = 1;
+ var L = msg.attenuation_linear;
+ var Q = msg.attenuation_quadratic;
+ lightObj.intensity = E*(D/(D+L*r))*(Math.pow(D,2)/(Math.pow(D,2)+Q*Math.pow(r,2)));
+ }
+
if (lightObj instanceof THREE.SpotLight) {
if (msg.spot_outer_angle) {
@@ -2437,7 +2493,7 @@ GZ3D.Scene.prototype.updateLight = function(entity, msg)
}
}
- if (msg.direction)
+ if (msg.direction && lightObj.target)
{
dir = new THREE.Vector3(msg.direction.x, msg.direction.y,
msg.direction.z);
@@ -2449,3 +2505,27 @@ GZ3D.Scene.prototype.updateLight = function(entity, msg)
lightObj.target.position.copy(dir);
}
};
+
+GZ3D.Scene.prototype.setShadowMaps = function(enabled) {
+ this.renderer.shadowMapEnabled = enabled;
+
+ var that = this;
+ this.scene.traverse(function(node) {
+ if (enabled) {
+ if (node.material) {
+ node.material.needsUpdate = true;
+ if (node.material.materials) {
+ for (var i = 0; i < node.material.materials.length; i = i+1) {
+ node.material.materials[i].needsUpdate = true;
+ }
+ }
+ }
+ } else {
+ if (node instanceof THREE.Light) {
+ if (node.shadowMap) {
+ that.renderer.clearTarget( node.shadowMap );
+ }
+ }
+ }
+ });
+};
\ No newline at end of file
diff --git a/gz3d/src/gzsdfparser.js b/gz3d/src/gzsdfparser.js
index 9ff775e7ce7b0d8d30ba694a51bc7cdb57884aeb..96d8ed71a8b584943263013faf3bcb5fb64d90d4 100644
--- a/gz3d/src/gzsdfparser.js
+++ b/gz3d/src/gzsdfparser.js
@@ -9,7 +9,7 @@ GZ3D.SdfParser = function(scene, gui, gziface)
{
// set the sdf version
this.SDF_VERSION = 1.5;
- this.MATERIAL_ROOT = 'assets/';
+ this.MATERIAL_ROOT = GZ3D.assetsPath + '/';
// set the xml parser function
this.parseXML = function(xmlStr) {
@@ -539,7 +539,7 @@ GZ3D.SdfParser.prototype.createGeom = function(geom, mat, parent)
allChildren[c].castShadow = false;
allChildren[c].receiveShadow = false;
- allChildren[c].visible = this.scene.showCollisions;
+ allChildren[c].visible = that.scene.showCollisions;
}
break;
}