Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 15 additions & 6 deletions editor/js/Animation.js
Original file line number Diff line number Diff line change
Expand Up @@ -367,7 +367,14 @@ function Animation( editor ) {

clipRow.addEventListener( 'click', function () {

editor.select( root );
if ( editor.selected !== root ) {

signals.objectSelected.remove( selectDefaultClip );
editor.select( root );
signals.objectSelected.add( selectDefaultClip );

}

selectClip( clip, root );
update(); // Refresh to update highlighting

Expand Down Expand Up @@ -578,10 +585,7 @@ function Animation( editor ) {

}

updateTime();

// Auto-select clip when an object with animations is selected
signals.objectSelected.add( function ( object ) {
function selectDefaultClip( object ) {

if ( object !== null && object.animations && object.animations.length > 0 ) {

Expand All @@ -590,7 +594,12 @@ function Animation( editor ) {

}

} );
}

updateTime();

// Auto-select clip when an object with animations is selected
signals.objectSelected.add( selectDefaultClip );

// Update when scene changes
signals.editorCleared.add( clear );
Expand Down
121 changes: 120 additions & 1 deletion editor/js/Menubar.File.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { UIPanel, UIRow, UIHorizontalRule } from './libs/ui.js';
import { FileLoader } from 'three';
import { FileLoader, PropertyBinding } from 'three';

function MenubarFile( editor ) {

Expand Down Expand Up @@ -276,6 +276,15 @@ function MenubarFile( editor ) {
option.onClick( async function () {

const scene = editor.scene;

if ( needsUniqueNames( scene ) ) { // see #25179

if ( confirm( strings.getKey( 'prompt/file/export/duplicateNames' ) ) === false ) return;

ensureUniqueNames( scene );

}

const animations = getAnimations( scene );

const optimizedAnimations = [];
Expand Down Expand Up @@ -307,6 +316,15 @@ function MenubarFile( editor ) {
option.onClick( async function () {

const scene = editor.scene;

if ( needsUniqueNames( scene ) ) { // see #25179

if ( confirm( strings.getKey( 'prompt/file/export/duplicateNames' ) ) === false ) return;

ensureUniqueNames( scene );

}

const animations = getAnimations( scene );

const optimizedAnimations = [];
Expand Down Expand Up @@ -460,6 +478,107 @@ function MenubarFile( editor ) {

}

function needsUniqueNames( scene ) {

const usedNames = new Set();
let duplicate = false;
let animated = false;

scene.traverse( function ( object ) {

if ( object.animations.length > 0 ) animated = true;

if ( object.name === '' ) return;

if ( usedNames.has( object.name ) ) duplicate = true;

usedNames.add( object.name );

} );

return duplicate && animated;

}

// Gives every object a unique name and keeps the animation tracks that
// reference them by name in sync. The renamed scene mirrors the result of a
// glTF round-trip, where the loader makes all names unique, too.

function ensureUniqueNames( scene ) {

// Resolve each track's target object up front, scoped to the object that
// owns the clip. This disambiguates colliding names before they change.

const trackBindings = [];

scene.traverse( function ( owner ) {

for ( const clip of owner.animations ) {

for ( const track of clip.tracks ) {

const nodeName = PropertyBinding.parseTrackName( track.name ).nodeName;
const target = PropertyBinding.findNode( owner, nodeName );

// References by UUID stay valid, so only track name-based ones.

if ( target !== null && target.name === nodeName ) {

trackBindings.push( { track, target, nodeName } );

}

}

}

} );

// Assign a unique name to every named object.

let changed = false;
const usedNames = new Set();

scene.traverse( function ( object ) {

if ( object.name === '' ) return;

if ( usedNames.has( object.name ) ) {

let suffix = 1, name;
do {

name = object.name + '_' + ( suffix ++ );

} while ( usedNames.has( name ) );

object.name = name;
changed = true;

}

usedNames.add( object.name );

} );

if ( changed === false ) return;

// Point the affected tracks at their renamed targets.

for ( const { track, target, nodeName } of trackBindings ) {

if ( target.name !== nodeName ) {

track.name = target.name + track.name.slice( nodeName.length );

}

}

editor.signals.sceneGraphChanged.dispatch();

}

return container;

}
Expand Down
6 changes: 6 additions & 0 deletions editor/js/Strings.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ function Strings( config ) {
'prompt/file/failedToOpenProject': 'خطایی در باز کردن پروژه پیش آمده',
'prompt/file/export/noMeshSelected': 'هیچ Mesh ای انتخاب نکردید',
'prompt/file/export/noObjectSelected': 'هیچ آبجکتی انتخاب نکردید!',
'prompt/file/export/duplicateNames': 'Some objects share the same name. They will be renamed to ensure unique names. Are you sure?',
'prompt/script/remove': 'آیا اطمینان دارید؟',
'prompt/history/clear': 'هیستوری قبل و بعد (undo / redo) پاک خواهند شد آیا مطمئنید؟',
'prompt/history/preserve': 'The history will be preserved across sessions.\nThis can have an impact on performance when working with textures.',
Expand Down Expand Up @@ -456,6 +457,7 @@ function Strings( config ) {
'prompt/file/failedToOpenProject': 'Failed to open project!',
'prompt/file/export/noMeshSelected': 'No Mesh selected!',
'prompt/file/export/noObjectSelected': 'No Object selected!',
'prompt/file/export/duplicateNames': 'Some objects share the same name. They will be renamed to ensure unique names. Are you sure?',
'prompt/script/remove': 'Are you sure?',
'prompt/history/clear': 'The Undo/Redo History will be cleared. Are you sure?',
'prompt/history/preserve': 'The history will be preserved across sessions.\nThis can have an impact on performance when working with textures.',
Expand Down Expand Up @@ -905,6 +907,7 @@ function Strings( config ) {
'prompt/file/failedToOpenProject': 'Échec de l\'ouverture du projet !',
'prompt/file/export/noMeshSelected': 'Aucun maillage sélectionné !',
'prompt/file/export/noObjectSelected': 'Aucun objet sélectionné !',
'prompt/file/export/duplicateNames': 'Certains objets portent le même nom. Ils seront renommés afin de garantir des noms uniques. Êtes-vous sûr ?',
'prompt/script/remove': 'Es-tu sûr?',
'prompt/history/clear': 'L\'historique d\'annulation/rétablissement sera effacé Êtes-vous sûr ?',
'prompt/history/preserve': 'L\'histoire sera conservée entre les sessions.\nCela peut avoir un impact sur les performances lors de la manipulation des textures.',
Expand Down Expand Up @@ -1354,6 +1357,7 @@ function Strings( config ) {
'prompt/file/failedToOpenProject': '无法打开项目!',
'prompt/file/export/noMeshSelected': '未选择网格!',
'prompt/file/export/noObjectSelected': '未选择对象!',
'prompt/file/export/duplicateNames': '部分对象具有相同的名称。它们将被重命名以确保名称唯一。确定吗?',
'prompt/script/remove': '你确定吗?',
'prompt/history/clear': '撤销/重做历史记录将被清除。您确定吗?',
'prompt/history/preserve': '历史将在会话之间保留。\n这可能会影响在处理纹理时的性能。',
Expand Down Expand Up @@ -1803,6 +1807,7 @@ function Strings( config ) {
'prompt/file/failedToOpenProject': 'プロジェクトを開くことができませんでした!',
'prompt/file/export/noMeshSelected': 'メッシュが選択されていません!',
'prompt/file/export/noObjectSelected': 'オブジェクトが選択されていません!',
'prompt/file/export/duplicateNames': '一部のオブジェクトの名前が重複しています。名前を一意にするために変更します。よろしいですか?',
'prompt/script/remove': '本気ですか?',
'prompt/history/clear': '元に戻す/やり直しの履歴が消去されます。 本気ですか?',
'prompt/history/preserve': '履歴はセッションをまたいで保存されます。\nこれは、テクスチャを操作する際のパフォーマンスに影響を与える可能性があります。',
Expand Down Expand Up @@ -2251,6 +2256,7 @@ function Strings( config ) {
'prompt/file/failedToOpenProject': '프로젝트를 여는 데 실패했습니다!',
'prompt/file/export/noMeshSelected': '메시가 선택되지 않았습니다!',
'prompt/file/export/noObjectSelected': '객체가 선택되지 않았습니다!',
'prompt/file/export/duplicateNames': '일부 객체의 이름이 중복됩니다. 이름을 고유하게 만들기 위해 변경됩니다. 계속하시겠습니까?',
'prompt/script/remove': '삭제하시겠습니까?',
'prompt/history/clear': '되돌리기/다시하기 기록이 지워집니다. 진행하시겠습니까?',
'prompt/history/preserve': '기록은 세션을 통해 저장됩니다. 이는 텍스처를 조작할 때 성능에 영향을 미칠 수 있습니다.',
Expand Down
Binary file modified examples/screenshots/webgpu_postprocessing_motion_blur.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
22 changes: 9 additions & 13 deletions src/materials/nodes/NodeMaterial.js
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
import { Material } from '../Material.js';

import { hashArray, hashString } from '../../nodes/core/NodeUtils.js';
import { output, diffuseColor, emissive, varyingProperty } from '../../nodes/core/PropertyNode.js';
import { output, diffuseColor, emissive } from '../../nodes/core/PropertyNode.js';
import { materialAlphaTest, materialColor, materialOpacity, materialEmissive, materialNormal, materialLightMap, materialAO } from '../../nodes/accessors/MaterialNode.js';
import { modelViewProjection } from '../../nodes/accessors/ModelViewProjectionNode.js';
import { normalLocal } from '../../nodes/accessors/Normal.js';
import { instancedMesh } from '../../nodes/accessors/InstancedMeshNode.js';
import { batch } from '../../nodes/accessors/BatchNode.js';
import { instancedMesh, instanceColor } from '../../nodes/accessors/Instance.js';
import { batch, batchColor } from '../../nodes/accessors/Batch.js';
import { materialReference } from '../../nodes/accessors/MaterialReferenceNode.js';
import { positionLocal, positionView } from '../../nodes/accessors/Position.js';
import { skinning } from '../../nodes/accessors/SkinningNode.js';
import { morphReference } from '../../nodes/accessors/MorphNode.js';
import { skinning } from '../../nodes/accessors/Skinning.js';
import { morphReference } from '../../nodes/accessors/Morph.js';
import { fwidth, mix, smoothstep } from '../../nodes/math/MathNode.js';
import { float, vec3, vec4, bool } from '../../nodes/tsl/TSLBase.js';
import AONode from '../../nodes/lighting/AONode.js';
Expand Down Expand Up @@ -766,13 +766,13 @@ class NodeMaterial extends Material {

if ( geometry.morphAttributes.position || geometry.morphAttributes.normal || geometry.morphAttributes.color ) {

morphReference( object ).toStack();
morphReference( object );

}

if ( object.isSkinnedMesh === true ) {

skinning( object ).toStack();
skinning( object );

}

Expand All @@ -788,13 +788,13 @@ class NodeMaterial extends Material {

if ( object.isBatchedMesh ) {

batch( object ).toStack();
batch( object );

}

if ( ( object.isInstancedMesh && object.instanceMatrix && object.instanceMatrix.isInstancedBufferAttribute === true ) ) {

instancedMesh( object ).toStack();
instancedMesh( object );

}

Expand Down Expand Up @@ -844,16 +844,12 @@ class NodeMaterial extends Material {

if ( object.instanceColor ) {

const instanceColor = varyingProperty( 'vec3', 'vInstanceColor' );

colorNode = instanceColor.mul( colorNode );

}

if ( object.isBatchedMesh && object._colorsTexture ) {

const batchColor = varyingProperty( 'vec3', 'vBatchColor' );

colorNode = batchColor.mul( colorNode );

}
Expand Down
5 changes: 0 additions & 5 deletions src/nodes/Nodes.js
Original file line number Diff line number Diff line change
Expand Up @@ -43,24 +43,19 @@ import * as NodeUtils from './core/NodeUtils.js';
export { NodeUtils };

// accessors
export { default as BatchNode } from './accessors/BatchNode.js';
export { default as BufferAttributeNode } from './accessors/BufferAttributeNode.js';
export { default as BufferNode } from './accessors/BufferNode.js';
export { default as BuiltinNode } from './accessors/BuiltinNode.js';
export { default as ClippingNode } from './accessors/ClippingNode.js';
export { default as CubeTextureNode } from './accessors/CubeTextureNode.js';
export { default as InstanceNode } from './accessors/InstanceNode.js';
export { default as InstancedMeshNode } from './accessors/InstancedMeshNode.js';
export { default as MaterialNode } from './accessors/MaterialNode.js';
export { default as MaterialReferenceNode } from './accessors/MaterialReferenceNode.js';
export { default as ModelNode } from './accessors/ModelNode.js';
export { default as MorphNode } from './accessors/MorphNode.js';
export { default as Object3DNode } from './accessors/Object3DNode.js';
export { default as PointUVNode } from './accessors/PointUVNode.js';
export { default as ReferenceBaseNode } from './accessors/ReferenceBaseNode.js';
export { default as ReferenceNode } from './accessors/ReferenceNode.js';
export { default as RendererReferenceNode } from './accessors/RendererReferenceNode.js';
export { default as SkinningNode } from './accessors/SkinningNode.js';
export { default as StorageBufferNode } from './accessors/StorageBufferNode.js';
export { default as StorageTexture3DNode } from './accessors/StorageTexture3DNode.js';
export { default as StorageTextureNode } from './accessors/StorageTextureNode.js';
Expand Down
9 changes: 4 additions & 5 deletions src/nodes/TSL.js
Original file line number Diff line number Diff line change
Expand Up @@ -63,14 +63,13 @@ export * from './accessors/BuiltinNode.js';
export * from './accessors/Camera.js';
export * from './accessors/VertexColorNode.js';
export * from './accessors/CubeTextureNode.js';
export * from './accessors/InstanceNode.js';
export * from './accessors/InstancedMeshNode.js';
export * from './accessors/BatchNode.js';
export * from './accessors/Instance.js';
export * from './accessors/Batch.js';
export * from './accessors/MaterialNode.js';
export * from './accessors/MaterialProperties.js';
export * from './accessors/MaterialReferenceNode.js';
export * from './accessors/RendererReferenceNode.js';
export * from './accessors/MorphNode.js';
export * from './accessors/Morph.js';
export * from './accessors/TextureBicubic.js';
export * from './accessors/ModelNode.js';
export * from './accessors/ModelViewProjectionNode.js';
Expand All @@ -80,7 +79,7 @@ export * from './accessors/PointUVNode.js';
export * from './accessors/Position.js';
export * from './accessors/ReferenceNode.js';
export * from './accessors/ReflectVector.js';
export * from './accessors/SkinningNode.js';
export * from './accessors/Skinning.js';
export * from './accessors/SceneProperties.js';
export * from './accessors/StorageBufferNode.js';
export * from './accessors/StorageTexture3DNode.js';
Expand Down
Loading
Loading