Browse Source

Editor: Add morph target support. (#32844)

Michael Herzog 4 weeks ago
parent
commit
c58d044b00

+ 3 - 0
editor/js/Editor.js

@@ -93,6 +93,9 @@ function Editor() {
 
 		pathTracerUpdated: new Signal(),
 
+		morphTargetsUpdated: new Signal()
+
+
 	};
 
 	this.config = new Config();

+ 82 - 3
editor/js/Sidebar.Geometry.js

@@ -1,6 +1,6 @@
 import * as THREE from 'three';
 
-import { UIPanel, UIRow, UIText, UIInput, UIButton, UISpan, UITextArea } from './libs/ui.js';
+import { UIPanel, UIRow, UIText, UIInput, UIButton, UISpan, UITextArea, UINumber, UIDiv, UIBreak } from './libs/ui.js';
 
 import { SetGeometryValueCommand } from './commands/SetGeometryValueCommand.js';
 
@@ -244,6 +244,20 @@ function SidebarGeometry( editor ) {
 	} );
 	container.add( exportJson );
 
+	// Morph Targets
+
+	const morphContainer = new UIDiv();
+	morphContainer.setMarginTop( '20px' );
+	morphContainer.setDisplay( 'none' );
+	container.add( morphContainer );
+
+	morphContainer.add( new UIText( strings.getKey( 'sidebar/geometry/morph' ) ).setTextTransform( 'uppercase' ) );
+	morphContainer.add( new UIBreak() );
+	morphContainer.add( new UIBreak() );
+
+	const morphList = new UIDiv();
+	morphContainer.add( morphList );
+
 	//
 
 	async function build() {
@@ -307,9 +321,73 @@ function SidebarGeometry( editor ) {
 
 			}
 
-		} else {
+			//
+
+			morphUIElements.length = 0;
+			morphList.clear();
+
+			if ( object.morphTargetInfluences ) {
+
+				const morphTargetDictionary = object.morphTargetDictionary;
+				const morphTargetInfluences = object.morphTargetInfluences;
+				const morphNames = Object.keys( morphTargetDictionary );
+
+				for ( let i = 0; i < morphNames.length; i ++ ) {
+
+					const name = morphNames[ i ];
+					morphList.add( new Morph( i, name, morphTargetInfluences ) );
 
-			container.setDisplay( 'none' );
+				}
+
+				morphContainer.setDisplay( '' );
+
+			} else {
+
+				morphContainer.setDisplay( 'none' );
+
+			}
+
+		}
+
+	}
+
+	const morphUIElements = [];
+
+	function Morph( index, name, morphTargetInfluences ) {
+
+		const container = new UIRow();
+
+		const morphName = new UIText( name ).setWidth( '200px' );
+		container.add( morphName );
+
+		const morphInfluence = new UINumber().setWidth( '60px' ).setRange( 0, 1 ).onChange( function updateMorphInfluence() {
+
+			morphTargetInfluences[ index ] = morphInfluence.getValue();
+			signals.objectChanged.dispatch( editor.selected );
+
+		} );
+		morphInfluence.setValue( morphTargetInfluences[ index ] );
+
+		container.add( morphInfluence );
+		morphUIElements.push( morphInfluence );
+
+		return container;
+
+	}
+
+
+	function refreshUI() {
+
+		const object = editor.selected;
+
+		if ( object !== null && object.morphTargetInfluences ) {
+
+			for ( let i = 0; i < morphUIElements.length; i ++ ) {
+
+				const element = morphUIElements[ i ];
+				element.setValue( object.morphTargetInfluences[ i ] );
+
+			}
 
 		}
 
@@ -324,6 +402,7 @@ function SidebarGeometry( editor ) {
 	} );
 
 	signals.geometryChanged.add( build );
+	signals.morphTargetsUpdated.add( refreshUI );
 
 	return container;
 

+ 6 - 0
editor/js/Strings.js

@@ -171,6 +171,7 @@ function Strings( config ) {
 			'sidebar/geometry/compute_vertex_tangents': 'محاسبه مماس ها',
 			'sidebar/geometry/center': 'وسط',
 			'sidebar/geometry/export': 'اکسپورت جیسون',
+			'sidebar/geometry/morph': 'Morph Targets',
 
 			'sidebar/geometry/box_geometry/width': 'عرض',
 			'sidebar/geometry/box_geometry/height': 'ارتفاع',
@@ -587,6 +588,7 @@ function Strings( config ) {
 			'sidebar/geometry/compute_vertex_tangents': 'Compute Tangents',
 			'sidebar/geometry/center': 'Center',
 			'sidebar/geometry/export': 'Export JSON',
+			'sidebar/geometry/morph': 'Morph Targets',
 
 			'sidebar/geometry/box_geometry/width': 'Width',
 			'sidebar/geometry/box_geometry/height': 'Height',
@@ -1004,6 +1006,7 @@ function Strings( config ) {
 			'sidebar/geometry/compute_vertex_tangents': 'Compute Tangents',
 			'sidebar/geometry/center': 'Center',
 			'sidebar/geometry/export': 'Exporter JSON',
+			'sidebar/geometry/morph': 'Morph Targets',
 
 			'sidebar/geometry/box_geometry/width': 'Largeur',
 			'sidebar/geometry/box_geometry/height': 'Hauteur',
@@ -1421,6 +1424,7 @@ function Strings( config ) {
 			'sidebar/geometry/compute_vertex_tangents': '计算切线',
 			'sidebar/geometry/center': '居中',
 			'sidebar/geometry/export': '导出JSON',
+			'sidebar/geometry/morph': 'Morph Targets',
 
 			'sidebar/geometry/box_geometry/width': '宽度',
 			'sidebar/geometry/box_geometry/height': '高度',
@@ -1838,6 +1842,7 @@ function Strings( config ) {
 			'sidebar/geometry/compute_vertex_tangents': '接線を計算',
 			'sidebar/geometry/center': '中央',
 			'sidebar/geometry/export': 'JSONをエクスポート',
+			'sidebar/geometry/morph': 'Morph Targets',
 
 			'sidebar/geometry/box_geometry/width': '幅',
 			'sidebar/geometry/box_geometry/height': '高さ',
@@ -2254,6 +2259,7 @@ function Strings( config ) {
 			'sidebar/geometry/compute_vertex_tangents': '접선 계산',
 			'sidebar/geometry/center': '중앙',
 			'sidebar/geometry/export': 'JSON으로 내보내기',
+			'sidebar/geometry/morph': 'Morph Targets',
 
 			'sidebar/geometry/box_geometry/width': '너비',
 			'sidebar/geometry/box_geometry/height': '높이',

+ 2 - 0
editor/js/Viewport.js

@@ -831,6 +831,8 @@ function Viewport( editor ) {
 
 			}
 
+			signals.morphTargetsUpdated.dispatch();
+
 		}
 
 		// View Helper

+ 3 - 0
src/core/Object3D.js

@@ -1314,6 +1314,9 @@ class Object3D extends EventDispatcher {
 
 		if ( this.matrixAutoUpdate === false ) object.matrixAutoUpdate = false;
 
+		if ( this.morphTargetDictionary !== undefined ) object.morphTargetDictionary = Object.assign( {}, this.morphTargetDictionary );
+		if ( this.morphTargetInfluences !== undefined ) object.morphTargetInfluences = this.morphTargetInfluences.slice();
+
 		// object specific properties
 
 		if ( this.isInstancedMesh ) {

+ 3 - 0
src/loaders/ObjectLoader.js

@@ -1117,6 +1117,9 @@ class ObjectLoader extends Loader {
 
 		if ( data.pivot !== undefined ) object.pivot = new Vector3().fromArray( data.pivot );
 
+		if ( data.morphTargetDictionary !== undefined ) object.morphTargetDictionary = Object.assign( {}, data.morphTargetDictionary );
+		if ( data.morphTargetInfluences !== undefined ) object.morphTargetInfluences = data.morphTargetInfluences.slice();
+
 		if ( data.castShadow !== undefined ) object.castShadow = data.castShadow;
 		if ( data.receiveShadow !== undefined ) object.receiveShadow = data.receiveShadow;
 

粤ICP备19079148号