本章讲解editor\js\Sidebar.Scene.js场景面板,场景面板展示了场景图的节点关系,以及场景背景色、雾。
场景节点会根据Object3D的具体的类型显示不同的信息,包括camera、scene、light、group、mesh、skinedmesh、bone等,节点的样式会根据节点的类型不同而不同,使用的ui文件是ui.three.js,css文件为editor\css\main.css,其中针对mesh节点,会在节点信息中显示对象名称--几何体名称--材质名称--脚本名称,对于多材质同时会显示多个材质名称。
//场景控件
Sidebar.Scene = function ( editor ) {
//获取事件、字符串
var signals = editor.signals;
var strings = editor.strings;
//创建一个面板
var container = new UI.Panel();
container.setBorderTop( '0' );
container.setPaddingTop( '20px' );
// outliner
//构建选项(对象、是否可以拖拽)
function buildOption( object, draggable ) {
//创建div
var option = document.createElement( 'div' );
//div
option.draggable = draggable;
//构建tree项
option.innerHTML = buildHTML( object );
//项的id
option.value = object.id;
return option;
}
//获取材质名称
function getMaterialName( material ) {
//如果材质是数组
if ( Array.isArray( material ) ) {
var array = [];
//遍历材质(获取材质名称)
for ( var i = 0; i < material.length; i ++ ) {
array.push( material[ i ].name );
}
//,号分割材质名称
return array.join( ',' );
}
return material.name;
}
//替换到名称当中的特殊字符
function escapeHTML( html ) {
return html
.replace( /&/g, '&' )
.replace( /"/g, '"' )
.replace( /'/g, ''' )
.replace( /</g, '<' )
.replace( />/g, '>' );
}
//对象名称--几何体名称--材质名称--脚本名称,这些东西组成了tree的一行
//对象可以是camera、scene、object、mesh
function buildHTML( object ) {
//对象的类型
var html = '<span class="type ' + object.type + '"></span> ' + escapeHTML( object.name );
//如果对象时mesh
if ( object.isMesh ) {
//对象的几何体、材质
var geometry = object.geometry;
var material = object.material;
//对象当中的几何体名称、材质名称
html += ' <span class="type ' + geometry.type + '"></span> ' + escapeHTML( geometry.name );
html += ' <span class="type ' + material.type + '"></span> ' + escapeHTML( getMaterialName( material ) );
}
//获取脚本
html += getScript( object.uuid );
return html;
}
//获取对象关联的脚本(如果存在)
function getScript( uuid ) {
if ( editor.scripts[ uuid ] !== undefined ) {
return ' <span class="type Script"></span>';
}
return '';
}
//忽略选择的对象时使用
var ignoreObjectSelectedSignal = false;
//创建大纲
var outliner = new UI.Outliner( editor );
outliner.setId( 'outliner' );
//添加改变事件
outliner.onChange( function () {
//忽略对象被选择
ignoreObjectSelectedSignal = true;
//设置选择的对象??
editor.selectById( parseInt( outliner.getValue() ) );
//启用对象被选择
ignoreObjectSelectedSignal = false;
} );
//添加双击事件
outliner.onDblClick( function () {
//关注选择的对象
editor.focusById( parseInt( outliner.getValue() ) );
} );
//添加到面板当中
container.add( outliner );
//创建分割线
container.add( new UI.Break() );
// background
//背景改变
function onBackgroundChanged() {
//背景改变消息
signals.sceneBackgroundChanged.dispatch( backgroundColor.getHexValue() );
}
// 创建
var backgroundRow = new UI.Row();
// 背景颜色,颜色改变的处理
var backgroundColor = new UI.Color().setValue( '#aaaaaa' ).onChange( onBackgroundChanged );
// 添加颜色文字标签、背景色编辑框
backgroundRow.add( new UI.Text( strings.getKey( 'sidebar/scene/background' ) ).setWidth( '90px' ) );
backgroundRow.add( backgroundColor );
//将背景
container.add( backgroundRow );
// fog类型改变
function onFogChanged() {
// /发送场景雾改变的消息
signals.sceneFogChanged.dispatch(
fogType.getValue(), //雾类型
fogColor.getHexValue(), //雾的颜色
fogNear.getValue(), //雾的近面
fogFar.getValue(), //雾的远面
fogDensity.getValue() //雾的衰减
);
}
//雾div
var fogTypeRow = new UI.Row();
//列表框
var fogType = new UI.Select().setOptions( {
'None': 'None', //不使用雾
'Fog': 'Linear', //线性雾
'FogExp2': 'Exponential' //扩展的雾
} ).setWidth( '150px' );
//雾类型改变
fogType.onChange( function () {
// /雾类型改变刷新
onFogChanged();
refreshFogUI();
} );
// 设置雾控件
fogTypeRow.add( new UI.Text( strings.getKey( 'sidebar/scene/fog' ) ).setWidth( '90px' ) );
fogTypeRow.add( fogType );
//将控件添加到容器
container.add( fogTypeRow );
// fog color
// 设置雾颜色控件
var fogPropertiesRow = new UI.Row();
fogPropertiesRow.setDisplay( 'none' );
fogPropertiesRow.setMarginLeft( '90px' );
container.add( fogPropertiesRow );
var fogColor = new UI.Color().setValue( '#aaaaaa' );
fogColor.onChange( onFogChanged );
fogPropertiesRow.add( fogColor );
// fog near
// /设置雾的近面
var fogNear = new UI.Number( 0.1 ).setWidth( '40px' ).setRange( 0, Infinity ).onChange( onFogChanged );
fogPropertiesRow.add( fogNear );
// fog far
// 设置雾的远面
var fogFar = new UI.Number( 50 ).setWidth( '40px' ).setRange( 0, Infinity ).onChange( onFogChanged );
fogPropertiesRow.add( fogFar );
// fog density
// 设置雾的衰减
var fogDensity = new UI.Number( 0.05 ).setWidth( '40px' ).setRange( 0, 0.1 ).setStep( 0.001 ).setPrecision( 3 ).onChange( onFogChanged );
fogPropertiesRow.add( fogDensity );
//
//刷新ui
function refreshUI() {
//相机、场景
var camera = editor.camera;
var scene = editor.scene;
//选项
var options = [];
//相机、场景的大纲项
options.push( buildOption( camera, false ) );
options.push( buildOption( scene, false ) );
//对象的大纲项
( function addObjects( objects, pad ) {
//遍历场景子节点列表
for ( var i = 0, l = objects.length; i < l; i ++ ) {
//获取一个对象
var object = objects[ i ];
// /构建选项
var option = buildOption( object, true );
//距离左边的间距
option.style.paddingLeft = ( pad * 10 ) + 'px';
options.push( option );
//递归添加
addObjects( object.children, pad + 1 );
}
} )( scene.children, 1 ); //传递场景子节点
// 大纲中设置选项
outliner.setOptions( options );
//编辑器中选择的对象不为null
if ( editor.selected !== null ) {
//设置选中的对象
outliner.setValue( editor.selected.id );
}
//场景背景改变
if ( scene.background ) {
//设置背景改变
backgroundColor.setHexValue( scene.background.getHex() );
}
//场景中的雾改变
if ( scene.fog ) {
//设置雾的颜色
fogColor.setHexValue( scene.fog.color.getHex() );
//根据雾的类型设置雾
if ( scene.fog.isFog ) {
fogType.setValue( "Fog" );
fogNear.setValue( scene.fog.near );
fogFar.setValue( scene.fog.far );
} else if ( scene.fog.isFogExp2 ) {
fogType.setValue( "FogExp2" );
fogDensity.setValue( scene.fog.density );
}
} else {
//没有设置雾
fogType.setValue( "None" );
}
//刷新雾
refreshFogUI();
}
//刷新雾的ui
function refreshFogUI() {
// 雾类型
var type = fogType.getValue();
//设置雾相关控件参数
fogPropertiesRow.setDisplay( type === 'None' ? 'none' : '' );
fogNear.setDisplay( type === 'Fog' ? '' : 'none' );
fogFar.setDisplay( type === 'Fog' ? '' : 'none' );
fogDensity.setDisplay( type === 'FogExp2' ? '' : 'none' );
}
//刷新ui
refreshUI();
// events
// 编辑器清空时刷新ui
signals.editorCleared.add( refreshUI );
//场景图改变,刷新ui
signals.sceneGraphChanged.add( refreshUI );
//对象改变
signals.objectChanged.add( function ( object ) {
//
var options = outliner.options;
//遍历选项
for ( var i = 0; i < options.length; i ++ ) {
//
var option = options[ i ];
//找到与对象相关的option
if ( option.value === object.id ) {
//更新选项
option.innerHTML = buildHTML( object );
return;
}
}
} );
//对象被选择后,tree会跟着改变
signals.objectSelected.add( function ( object ) {
//如果忽略就返回,避免循环
if ( ignoreObjectSelectedSignal === true ) return;
//tree上设置选择的对象
outliner.setValue( object !== null ? object.id : null );
} );
return container;
};