From b250b31546f85e3a4ad46220a9c32bba0b0cc5b9 Mon Sep 17 00:00:00 2001 From: ycw Date: Mon, 27 May 2024 10:03:09 -0500 Subject: [PATCH 01/16] uses angle for some geometry params (#28497) --- editor/js/Sidebar.Geometry.CircleGeometry.js | 4 ++-- editor/js/Sidebar.Geometry.RingGeometry.js | 4 ++-- editor/js/Sidebar.Geometry.TorusGeometry.js | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/editor/js/Sidebar.Geometry.CircleGeometry.js b/editor/js/Sidebar.Geometry.CircleGeometry.js index c8537f8d044947..a68316ba8a58e6 100644 --- a/editor/js/Sidebar.Geometry.CircleGeometry.js +++ b/editor/js/Sidebar.Geometry.CircleGeometry.js @@ -36,7 +36,7 @@ function GeometryParametersPanel( editor, object ) { // thetaStart const thetaStartRow = new UIRow(); - const thetaStart = new UINumber( parameters.thetaStart * THREE.MathUtils.RAD2DEG ).setStep( 10 ).onChange( update ); + const thetaStart = new UINumber( parameters.thetaStart * THREE.MathUtils.RAD2DEG ).setUnit( '°' ).setStep( 10 ).onChange( update ); thetaStartRow.add( new UIText( strings.getKey( 'sidebar/geometry/circle_geometry/thetastart' ) ).setClass( 'Label' ) ); thetaStartRow.add( thetaStart ); @@ -46,7 +46,7 @@ function GeometryParametersPanel( editor, object ) { // thetaLength const thetaLengthRow = new UIRow(); - const thetaLength = new UINumber( parameters.thetaLength * THREE.MathUtils.RAD2DEG ).setStep( 10 ).onChange( update ); + const thetaLength = new UINumber( parameters.thetaLength * THREE.MathUtils.RAD2DEG ).setUnit( '°' ).setStep( 10 ).onChange( update ); thetaLengthRow.add( new UIText( strings.getKey( 'sidebar/geometry/circle_geometry/thetalength' ) ).setClass( 'Label' ) ); thetaLengthRow.add( thetaLength ); diff --git a/editor/js/Sidebar.Geometry.RingGeometry.js b/editor/js/Sidebar.Geometry.RingGeometry.js index 73d5dbf63b6582..33b83e098ae665 100644 --- a/editor/js/Sidebar.Geometry.RingGeometry.js +++ b/editor/js/Sidebar.Geometry.RingGeometry.js @@ -56,7 +56,7 @@ function GeometryParametersPanel( editor, object ) { // thetaStart const thetaStartRow = new UIRow(); - const thetaStart = new UINumber( parameters.thetaStart * THREE.MathUtils.RAD2DEG ).setStep( 10 ).onChange( update ); + const thetaStart = new UINumber( parameters.thetaStart * THREE.MathUtils.RAD2DEG ).setUnit( '°' ).setStep( 10 ).onChange( update ); thetaStartRow.add( new UIText( strings.getKey( 'sidebar/geometry/ring_geometry/thetastart' ) ).setClass( 'Label' ) ); thetaStartRow.add( thetaStart ); @@ -66,7 +66,7 @@ function GeometryParametersPanel( editor, object ) { // thetaLength const thetaLengthRow = new UIRow(); - const thetaLength = new UINumber( parameters.thetaLength * THREE.MathUtils.RAD2DEG ).setStep( 10 ).onChange( update ); + const thetaLength = new UINumber( parameters.thetaLength * THREE.MathUtils.RAD2DEG ).setUnit( '°' ).setStep( 10 ).onChange( update ); thetaLengthRow.add( new UIText( strings.getKey( 'sidebar/geometry/ring_geometry/thetalength' ) ).setClass( 'Label' ) ); thetaLengthRow.add( thetaLength ); diff --git a/editor/js/Sidebar.Geometry.TorusGeometry.js b/editor/js/Sidebar.Geometry.TorusGeometry.js index ce96c00815ccf4..9a5eef26008019 100644 --- a/editor/js/Sidebar.Geometry.TorusGeometry.js +++ b/editor/js/Sidebar.Geometry.TorusGeometry.js @@ -56,7 +56,7 @@ function GeometryParametersPanel( editor, object ) { // arc const arcRow = new UIRow(); - const arc = new UINumber( parameters.arc * THREE.MathUtils.RAD2DEG ).setStep( 10 ).onChange( update ); + const arc = new UINumber( parameters.arc * THREE.MathUtils.RAD2DEG ).setUnit( '°' ).setStep( 10 ).onChange( update ); arcRow.add( new UIText( strings.getKey( 'sidebar/geometry/torus_geometry/arc' ) ).setClass( 'Label' ) ); arcRow.add( arc ); From d29a6ac4ac809c9255405333c55a70fa6dcfec08 Mon Sep 17 00:00:00 2001 From: Nathan Bierema Date: Mon, 27 May 2024 14:26:27 -0400 Subject: [PATCH 02/16] WebGPURenderer: Uniform - Clean up. (#28500) --- examples/jsm/renderers/common/Uniform.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/jsm/renderers/common/Uniform.js b/examples/jsm/renderers/common/Uniform.js index 4386d3e755e025..23bcf5ad382cfb 100644 --- a/examples/jsm/renderers/common/Uniform.js +++ b/examples/jsm/renderers/common/Uniform.js @@ -2,7 +2,7 @@ import { Color, Matrix3, Matrix4, Vector2, Vector3, Vector4 } from 'three'; class Uniform { - constructor( name, value = null ) { + constructor( name, value ) { this.name = name; this.value = value; From 23e68107bc64c6ee0dd39fc2d6839b4df94f8738 Mon Sep 17 00:00:00 2001 From: sunag Date: Mon, 27 May 2024 15:26:54 -0300 Subject: [PATCH 03/16] TSL: Fix Math/Operators fail generate cache with same node (#28502) --- examples/jsm/nodes/core/Node.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/examples/jsm/nodes/core/Node.js b/examples/jsm/nodes/core/Node.js index 79ad31a86324f4..bc1db917790b10 100644 --- a/examples/jsm/nodes/core/Node.js +++ b/examples/jsm/nodes/core/Node.js @@ -199,9 +199,11 @@ class Node extends EventDispatcher { const nodeProperties = builder.getNodeProperties( this ); + let index = 0; + for ( const childNode of this.getChildren() ) { - nodeProperties[ '_node' + childNode.id ] = childNode; + nodeProperties[ 'node' + index ++ ] = childNode; } From 7a3cd9870f2274a552a87f1f257145fb8880199d Mon Sep 17 00:00:00 2001 From: Nathan Bierema Date: Mon, 27 May 2024 14:33:44 -0400 Subject: [PATCH 04/16] WebGPURenderer: Pipelines - Clean up. (#28495) * WebGPURenderer: Pipelines - Clean up. * Update Attributes --- examples/jsm/renderers/common/Attributes.js | 2 ++ examples/jsm/renderers/common/Pipelines.js | 4 ++-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/examples/jsm/renderers/common/Attributes.js b/examples/jsm/renderers/common/Attributes.js index afb3467cf66ed5..b1330ba66be168 100644 --- a/examples/jsm/renderers/common/Attributes.js +++ b/examples/jsm/renderers/common/Attributes.js @@ -22,6 +22,8 @@ class Attributes extends DataMap { } + return attributeData; + } update( attribute, type ) { diff --git a/examples/jsm/renderers/common/Pipelines.js b/examples/jsm/renderers/common/Pipelines.js index afb176f1b7ee93..4cae37d1260006 100644 --- a/examples/jsm/renderers/common/Pipelines.js +++ b/examples/jsm/renderers/common/Pipelines.js @@ -67,7 +67,7 @@ class Pipelines extends DataMap { if ( pipeline === undefined ) { - if ( previousPipeline && previousPipeline.usedTimes === 0 ) this._releasePipeline( computeNode ); + if ( previousPipeline && previousPipeline.usedTimes === 0 ) this._releasePipeline( previousPipeline ); pipeline = this._getComputePipeline( computeNode, stageCompute, cacheKey, bindings ); @@ -205,7 +205,7 @@ class Pipelines extends DataMap { } - super.delete( object ); + return super.delete( object ); } From 0a03ca667a09da70fe94a69f68635cd0f94a304b Mon Sep 17 00:00:00 2001 From: sunag Date: Mon, 27 May 2024 15:36:37 -0300 Subject: [PATCH 05/16] TSL: Introduce `.toGlobal` (#28503) --- examples/jsm/nodes/core/Node.js | 4 +++- examples/jsm/nodes/shadernode/ShaderNode.js | 10 ++++++++++ 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/examples/jsm/nodes/core/Node.js b/examples/jsm/nodes/core/Node.js index bc1db917790b10..007186bef09f20 100644 --- a/examples/jsm/nodes/core/Node.js +++ b/examples/jsm/nodes/core/Node.js @@ -25,6 +25,8 @@ class Node extends EventDispatcher { this._cacheKey = null; this._cacheKeyVersion = 0; + this.global = false; + this.isNode = true; Object.defineProperty( this, 'id', { value: _nodeId ++ } ); @@ -98,7 +100,7 @@ class Node extends EventDispatcher { isGlobal( /*builder*/ ) { - return false; + return this.global; } diff --git a/examples/jsm/nodes/shadernode/ShaderNode.js b/examples/jsm/nodes/shadernode/ShaderNode.js index 6daedb977d5c0b..39054ee312bac9 100644 --- a/examples/jsm/nodes/shadernode/ShaderNode.js +++ b/examples/jsm/nodes/shadernode/ShaderNode.js @@ -531,6 +531,16 @@ addNodeClass( 'ShaderNode', ShaderNode ); // +addNodeElement( 'toGlobal', ( node ) => { + + node.global = true; + + return node; + +} ); + +// + export const setCurrentStack = ( stack ) => { if ( currentStack === stack ) { From b609f8a0d73af65ce843381e305e80806fc2ff45 Mon Sep 17 00:00:00 2001 From: sunag Date: Mon, 27 May 2024 16:16:31 -0300 Subject: [PATCH 06/16] TSL: `VaryingNode` - Fix twice flow node (#28504) --- examples/jsm/nodes/core/VaryingNode.js | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/examples/jsm/nodes/core/VaryingNode.js b/examples/jsm/nodes/core/VaryingNode.js index ceac05cf35b73b..2bcff5398d8534 100644 --- a/examples/jsm/nodes/core/VaryingNode.js +++ b/examples/jsm/nodes/core/VaryingNode.js @@ -66,13 +66,20 @@ class VaryingNode extends Node { generate( builder ) { - const type = this.getNodeType( builder ); + const properties = builder.getNodeProperties( this ); const varying = this.setupVarying( builder ); - const propertyName = builder.getPropertyName( varying, NodeShaderStage.VERTEX ); + if ( properties.propertyName === undefined ) { + + const type = this.getNodeType( builder ); + const propertyName = builder.getPropertyName( varying, NodeShaderStage.VERTEX ); + + // force node run in vertex stage + builder.flowNodeFromShaderStage( NodeShaderStage.VERTEX, this.node, type, propertyName ); + + properties.propertyName = propertyName; - // force node run in vertex stage - builder.flowNodeFromShaderStage( NodeShaderStage.VERTEX, this.node, type, propertyName ); + } return builder.getPropertyName( varying ); From a3c4bc086bfc6d78228aab7fcb1062b4628005fe Mon Sep 17 00:00:00 2001 From: aardgoose Date: Mon, 27 May 2024 20:38:51 +0100 Subject: [PATCH 07/16] WebGPURenderer: Avoid object creation in PassNode.updateBefore (#28505) Co-authored-by: aardgoose --- examples/jsm/nodes/display/PassNode.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/examples/jsm/nodes/display/PassNode.js b/examples/jsm/nodes/display/PassNode.js index cd9e440a4d1422..acfdd502651ab0 100644 --- a/examples/jsm/nodes/display/PassNode.js +++ b/examples/jsm/nodes/display/PassNode.js @@ -7,6 +7,8 @@ import { uniform } from '../core/UniformNode.js'; import { viewZToOrthographicDepth, perspectiveDepthToViewZ } from './ViewportDepthNode.js'; import { RenderTarget, Vector2, HalfFloatType, DepthTexture, NoToneMapping/*, FloatType*/ } from 'three'; +const _size = new Vector2(); + class PassTextureNode extends TextureNode { constructor( passNode, texture ) { @@ -135,7 +137,7 @@ class PassNode extends TempNode { this._pixelRatio = renderer.getPixelRatio(); - const size = renderer.getSize( new Vector2() ); + const size = renderer.getSize( _size ); this.setSize( size.width, size.height ); From 722c7c7916d33f18e5dc237c7bdb4c6654795865 Mon Sep 17 00:00:00 2001 From: Nathan Bierema Date: Mon, 27 May 2024 17:03:43 -0400 Subject: [PATCH 08/16] TSL: NodeBuilder - Cleanup (#28506) --- examples/jsm/nodes/core/NodeBuilder.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/jsm/nodes/core/NodeBuilder.js b/examples/jsm/nodes/core/NodeBuilder.js index a496c6d6152c0c..1cefadab15d8e3 100644 --- a/examples/jsm/nodes/core/NodeBuilder.js +++ b/examples/jsm/nodes/core/NodeBuilder.js @@ -80,7 +80,7 @@ class NodeBuilder { this.computeShader = null; this.flowNodes = { vertex: [], fragment: [], compute: [] }; - this.flowCode = { vertex: '', fragment: '', compute: [] }; + this.flowCode = { vertex: '', fragment: '', compute: '' }; this.uniforms = { vertex: [], fragment: [], compute: [], index: 0 }; this.structs = { vertex: [], fragment: [], compute: [], index: 0 }; this.bindings = { vertex: [], fragment: [], compute: [] }; From 7a3cdca330e4e55fd4b1b3482cf02cbdc34275a7 Mon Sep 17 00:00:00 2001 From: Nathan Bierema Date: Mon, 27 May 2024 21:18:26 -0400 Subject: [PATCH 09/16] TSL: NodeBuilder - Cleanup (#28508) --- examples/jsm/nodes/core/NodeBuilder.js | 6 ------ 1 file changed, 6 deletions(-) diff --git a/examples/jsm/nodes/core/NodeBuilder.js b/examples/jsm/nodes/core/NodeBuilder.js index 1cefadab15d8e3..3a5ef6c36ddbd0 100644 --- a/examples/jsm/nodes/core/NodeBuilder.js +++ b/examples/jsm/nodes/core/NodeBuilder.js @@ -415,12 +415,6 @@ class NodeBuilder { } - generateMethod( method ) { - - return method; - - } - hasGeometryAttribute( name ) { return this.geometry && this.geometry.getAttribute( name ) !== undefined; From 4c6d0c47a7062620a840d0c30c4e5da939659bd0 Mon Sep 17 00:00:00 2001 From: sunag Date: Mon, 27 May 2024 22:18:54 -0300 Subject: [PATCH 10/16] WebGPURenderer: `MeshPhysicalNodeMaterial` - Fix `clearcoatRoughness` (#28507) * MeshPhysicalNodeMaterial: Fix clearcoatRoughness * update screenshot --- .../nodes/functions/PhysicalLightingModel.js | 2 +- .../materials/MeshPhysicalNodeMaterial.js | 3 ++- examples/screenshots/webgpu_clearcoat.jpg | Bin 31412 -> 30184 bytes examples/webgpu_clearcoat.html | 9 --------- 4 files changed, 3 insertions(+), 11 deletions(-) diff --git a/examples/jsm/nodes/functions/PhysicalLightingModel.js b/examples/jsm/nodes/functions/PhysicalLightingModel.js index 3a4d332b527707..ecfc0085bc7901 100644 --- a/examples/jsm/nodes/functions/PhysicalLightingModel.js +++ b/examples/jsm/nodes/functions/PhysicalLightingModel.js @@ -331,7 +331,7 @@ const IBLSheenBRDF = tslFn( ( { normal, viewDir, roughness } ) => { } ); const clearcoatF0 = vec3( 0.04 ); -const clearcoatF90 = vec3( 1 ); +const clearcoatF90 = float( 1 ); // diff --git a/examples/jsm/nodes/materials/MeshPhysicalNodeMaterial.js b/examples/jsm/nodes/materials/MeshPhysicalNodeMaterial.js index 91495702d2fc48..e42b658b5f9642 100644 --- a/examples/jsm/nodes/materials/MeshPhysicalNodeMaterial.js +++ b/examples/jsm/nodes/materials/MeshPhysicalNodeMaterial.js @@ -3,6 +3,7 @@ import { transformedClearcoatNormalView } from '../accessors/NormalNode.js'; import { clearcoat, clearcoatRoughness, sheen, sheenRoughness, iridescence, iridescenceIOR, iridescenceThickness, specularColor, specularF90, diffuseColor, metalness, roughness, anisotropy, alphaT, anisotropyT, anisotropyB, ior, transmission, thickness, attenuationDistance, attenuationColor, dispersion } from '../core/PropertyNode.js'; import { materialClearcoat, materialClearcoatRoughness, materialClearcoatNormal, materialSheen, materialSheenRoughness, materialIridescence, materialIridescenceIOR, materialIridescenceThickness, materialSpecularIntensity, materialSpecularColor, materialAnisotropy, materialIOR, materialTransmission, materialThickness, materialAttenuationDistance, materialAttenuationColor, materialDispersion } from '../accessors/MaterialNode.js'; import { float, vec2, vec3, If } from '../shadernode/ShaderNode.js'; +import getRoughness from '../functions/material/getRoughness.js'; import { TBNViewMatrix } from '../accessors/AccessorsUtils.js'; import PhysicalLightingModel from '../functions/PhysicalLightingModel.js'; import MeshStandardNodeMaterial from './MeshStandardNodeMaterial.js'; @@ -112,7 +113,7 @@ class MeshPhysicalNodeMaterial extends MeshStandardNodeMaterial { const clearcoatRoughnessNode = this.clearcoatRoughnessNode ? float( this.clearcoatRoughnessNode ) : materialClearcoatRoughness; clearcoat.assign( clearcoatNode ); - clearcoatRoughness.assign( clearcoatRoughnessNode ); + clearcoatRoughness.assign( getRoughness( { roughness: clearcoatRoughnessNode } ) ); } diff --git a/examples/screenshots/webgpu_clearcoat.jpg b/examples/screenshots/webgpu_clearcoat.jpg index 19bd4024d71182c834dd435b5cb5defdc0905b14..7dfb0d565f2ea0b0029e3e686ca83819813c1c58 100644 GIT binary patch delta 29818 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 SbD~=vrP1Mjf}Hj Date: Mon, 27 May 2024 23:28:42 -0300 Subject: [PATCH 11/16] TSL: Analyze lights and auto generate cache (#28509) * analyze lights, auto generate cache * new cache for new function generator --- examples/jsm/nodes/core/ContextNode.js | 6 ++++++ examples/jsm/nodes/core/NodeBuilder.js | 7 +++++++ examples/jsm/nodes/lighting/LightsNode.js | 17 +++++++++++++++++ 3 files changed, 30 insertions(+) diff --git a/examples/jsm/nodes/core/ContextNode.js b/examples/jsm/nodes/core/ContextNode.js index b776b9644d2861..d2873507d6bbc9 100644 --- a/examples/jsm/nodes/core/ContextNode.js +++ b/examples/jsm/nodes/core/ContextNode.js @@ -20,6 +20,12 @@ class ContextNode extends Node { } + analyze( builder ) { + + this.node.build( builder ); + + } + setup( builder ) { const previousContext = builder.getContext(); diff --git a/examples/jsm/nodes/core/NodeBuilder.js b/examples/jsm/nodes/core/NodeBuilder.js index 3a5ef6c36ddbd0..08aedc074008b7 100644 --- a/examples/jsm/nodes/core/NodeBuilder.js +++ b/examples/jsm/nodes/core/NodeBuilder.js @@ -911,7 +911,9 @@ class NodeBuilder { const previousFlow = this.flow; const previousVars = this.vars; + const previousCache = this.cache; const previousBuildStage = this.buildStage; + const previousStack = this.stack; const flow = { code: '' @@ -919,6 +921,8 @@ class NodeBuilder { this.flow = flow; this.vars = {}; + this.cache = new NodeCache(); + this.stack = stack(); for ( const buildStage of defaultBuildStages ) { @@ -932,6 +936,9 @@ class NodeBuilder { this.flow = previousFlow; this.vars = previousVars; + this.cache = previousCache; + this.stack = previousStack; + this.setBuildStage( previousBuildStage ); return flow; diff --git a/examples/jsm/nodes/lighting/LightsNode.js b/examples/jsm/nodes/lighting/LightsNode.js index d8f88251317987..57b058967e8526 100644 --- a/examples/jsm/nodes/lighting/LightsNode.js +++ b/examples/jsm/nodes/lighting/LightsNode.js @@ -53,6 +53,18 @@ class LightsNode extends Node { } + analyze( builder ) { + + const properties = builder.getDataFromNode( this ); + + for ( const node of properties.nodes ) { + + node.build( builder ); + + } + + } + setup( builder ) { const context = builder.context; @@ -70,6 +82,11 @@ class LightsNode extends Node { // + const properties = builder.getDataFromNode( this ); + properties.nodes = stack.nodes; + + // + lightingModel.start( context, stack, builder ); // lights From 66e1aa2abfb1b6b7c8c047691130a0ab19fee311 Mon Sep 17 00:00:00 2001 From: sunag Date: Mon, 27 May 2024 23:29:27 -0300 Subject: [PATCH 12/16] TSL: PositionNode/ReflectVectorNode - Move to TSL approach (#28510) * PositionNode: Move to TSL approach * ReflectVectorNode: Move to TSL approach --- examples/jsm/nodes/Nodes.js | 4 +- examples/jsm/nodes/accessors/PositionNode.js | 106 +----------------- .../jsm/nodes/accessors/ReflectVectorNode.js | 33 +----- 3 files changed, 10 insertions(+), 133 deletions(-) diff --git a/examples/jsm/nodes/Nodes.js b/examples/jsm/nodes/Nodes.js index bac1a3e9c4aea8..3407cd071e3295 100644 --- a/examples/jsm/nodes/Nodes.js +++ b/examples/jsm/nodes/Nodes.js @@ -95,9 +95,9 @@ export { default as ModelViewProjectionNode, modelViewProjection } from './acces export * from './accessors/NormalNode.js'; export { default as Object3DNode, objectDirection, objectViewMatrix, objectNormalMatrix, objectWorldMatrix, objectPosition, objectScale, objectViewPosition } from './accessors/Object3DNode.js'; export { default as PointUVNode, pointUV } from './accessors/PointUVNode.js'; -export { default as PositionNode, positionGeometry, positionLocal, positionWorld, positionWorldDirection, positionView, positionViewDirection } from './accessors/PositionNode.js'; +export * from './accessors/PositionNode.js'; export { default as ReferenceNode, reference, referenceBuffer } from './accessors/ReferenceNode.js'; -export { default as ReflectVectorNode, reflectVector } from './accessors/ReflectVectorNode.js'; +export * from './accessors/ReflectVectorNode.js'; export { default as SkinningNode, skinning } from './accessors/SkinningNode.js'; export { default as SceneNode, backgroundBlurriness, backgroundIntensity } from './accessors/SceneNode.js'; export { default as StorageBufferNode, storage, storageObject } from './accessors/StorageBufferNode.js'; diff --git a/examples/jsm/nodes/accessors/PositionNode.js b/examples/jsm/nodes/accessors/PositionNode.js index 89dc162e2fd4ad..f77d84563b01af 100644 --- a/examples/jsm/nodes/accessors/PositionNode.js +++ b/examples/jsm/nodes/accessors/PositionNode.js @@ -1,104 +1,10 @@ -import Node, { addNodeClass } from '../core/Node.js'; import { attribute } from '../core/AttributeNode.js'; import { varying } from '../core/VaryingNode.js'; -import { normalize } from '../math/MathNode.js'; import { modelWorldMatrix, modelViewMatrix } from './ModelNode.js'; -import { nodeImmutable } from '../shadernode/ShaderNode.js'; -class PositionNode extends Node { - - constructor( scope = PositionNode.LOCAL ) { - - super( 'vec3' ); - - this.scope = scope; - - } - - isGlobal() { - - return true; - - } - - getHash( /*builder*/ ) { - - return `position-${this.scope}`; - - } - - generate( builder ) { - - const scope = this.scope; - - let outputNode = null; - - if ( scope === PositionNode.GEOMETRY ) { - - outputNode = attribute( 'position', 'vec3' ); - - } else if ( scope === PositionNode.LOCAL ) { - - outputNode = varying( positionGeometry ); - - } else if ( scope === PositionNode.WORLD ) { - - const vertexPositionNode = modelWorldMatrix.mul( positionLocal ); - outputNode = varying( vertexPositionNode ); - - } else if ( scope === PositionNode.VIEW ) { - - const vertexPositionNode = modelViewMatrix.mul( positionLocal ); - outputNode = varying( vertexPositionNode ); - - } else if ( scope === PositionNode.VIEW_DIRECTION ) { - - const vertexPositionNode = positionView.negate(); - outputNode = normalize( varying( vertexPositionNode ) ); - - } else if ( scope === PositionNode.WORLD_DIRECTION ) { - - const vertexPositionNode = positionLocal.transformDirection( modelWorldMatrix ); - outputNode = normalize( varying( vertexPositionNode ) ); - - } - - return outputNode.build( builder, this.getNodeType( builder ) ); - - } - - serialize( data ) { - - super.serialize( data ); - - data.scope = this.scope; - - } - - deserialize( data ) { - - super.deserialize( data ); - - this.scope = data.scope; - - } - -} - -PositionNode.GEOMETRY = 'geometry'; -PositionNode.LOCAL = 'local'; -PositionNode.WORLD = 'world'; -PositionNode.WORLD_DIRECTION = 'worldDirection'; -PositionNode.VIEW = 'view'; -PositionNode.VIEW_DIRECTION = 'viewDirection'; - -export default PositionNode; - -export const positionGeometry = nodeImmutable( PositionNode, PositionNode.GEOMETRY ); -export const positionLocal = nodeImmutable( PositionNode, PositionNode.LOCAL ).temp( 'Position' ); -export const positionWorld = nodeImmutable( PositionNode, PositionNode.WORLD ); -export const positionWorldDirection = nodeImmutable( PositionNode, PositionNode.WORLD_DIRECTION ); -export const positionView = nodeImmutable( PositionNode, PositionNode.VIEW ); -export const positionViewDirection = nodeImmutable( PositionNode, PositionNode.VIEW_DIRECTION ); - -addNodeClass( 'PositionNode', PositionNode ); +export const positionGeometry = /*#__PURE__*/ attribute( 'position', 'vec3' ); +export const positionLocal = /*#__PURE__*/ positionGeometry.toVar( 'positionLocal' ); +export const positionWorld = /*#__PURE__*/ varying( modelWorldMatrix.mul( positionLocal ).xyz, 'v_positionWorld' ); +export const positionWorldDirection = /*#__PURE__*/ varying( positionLocal.transformDirection( modelWorldMatrix ), 'v_positionWorldDirection' ).normalize().toVar( 'positionWorldDirection' ); +export const positionView = /*#__PURE__*/ varying( modelViewMatrix.mul( positionLocal ).xyz, 'v_positionView' ); +export const positionViewDirection = /*#__PURE__*/ varying( positionView.negate(), 'v_positionViewDirection' ).normalize().toVar( 'positionViewDirection' ); diff --git a/examples/jsm/nodes/accessors/ReflectVectorNode.js b/examples/jsm/nodes/accessors/ReflectVectorNode.js index b552b268e91704..ced16b3993b5c1 100644 --- a/examples/jsm/nodes/accessors/ReflectVectorNode.js +++ b/examples/jsm/nodes/accessors/ReflectVectorNode.js @@ -1,35 +1,6 @@ -import Node, { addNodeClass } from '../core/Node.js'; import { cameraViewMatrix } from './CameraNode.js'; import { transformedNormalView } from './NormalNode.js'; import { positionViewDirection } from './PositionNode.js'; -import { nodeImmutable } from '../shadernode/ShaderNode.js'; -class ReflectVectorNode extends Node { - - constructor() { - - super( 'vec3' ); - - } - - getHash( /*builder*/ ) { - - return 'reflectVector'; - - } - - setup() { - - const reflectView = positionViewDirection.negate().reflect( transformedNormalView ); - - return reflectView.transformDirection( cameraViewMatrix ); - - } - -} - -export default ReflectVectorNode; - -export const reflectVector = nodeImmutable( ReflectVectorNode ); - -addNodeClass( 'ReflectVectorNode', ReflectVectorNode ); +export const reflectView = /*#__PURE__*/ positionViewDirection.negate().reflect( transformedNormalView ); +export const reflectVector = /*#__PURE__*/ reflectView.transformDirection( cameraViewMatrix ).toVar( 'reflectVector' ); From e811420109551a424fb7d351ac95b7336c93dcf9 Mon Sep 17 00:00:00 2001 From: sunag Date: Tue, 28 May 2024 00:05:46 -0300 Subject: [PATCH 13/16] TSL: UVNode - Move to TSL approach (#28511) * Normal/Tangent/Bitangent revisions * UVNode: Move to TSL approach * fix type --- examples/jsm/nodes/Nodes.js | 2 +- examples/jsm/nodes/accessors/BitangentNode.js | 12 ++--- examples/jsm/nodes/accessors/NormalNode.js | 8 ++-- examples/jsm/nodes/accessors/TangentNode.js | 8 ++-- examples/jsm/nodes/accessors/UVNode.js | 48 +------------------ 5 files changed, 17 insertions(+), 61 deletions(-) diff --git a/examples/jsm/nodes/Nodes.js b/examples/jsm/nodes/Nodes.js index 3407cd071e3295..bdee9f3f6b045e 100644 --- a/examples/jsm/nodes/Nodes.js +++ b/examples/jsm/nodes/Nodes.js @@ -105,7 +105,7 @@ export * from './accessors/TangentNode.js'; export { default as TextureNode, texture, textureLoad, /*textureLevel,*/ sampler } from './accessors/TextureNode.js'; export { default as TextureStoreNode, textureStore } from './accessors/TextureStoreNode.js'; export { default as Texture3DNode, texture3D } from './accessors/Texture3DNode.js'; -export { default as UVNode, uv } from './accessors/UVNode.js'; +export * from './accessors/UVNode.js'; export { default as UserDataNode, userData } from './accessors/UserDataNode.js'; // display diff --git a/examples/jsm/nodes/accessors/BitangentNode.js b/examples/jsm/nodes/accessors/BitangentNode.js index 03f10bdc77dfe4..877b9efe73c89e 100644 --- a/examples/jsm/nodes/accessors/BitangentNode.js +++ b/examples/jsm/nodes/accessors/BitangentNode.js @@ -5,9 +5,9 @@ import { tangentGeometry, tangentLocal, tangentView, tangentWorld, transformedTa const getBitangent = ( crossNormalTangent ) => crossNormalTangent.mul( tangentGeometry.w ).xyz; -export const bitangentGeometry = varying( getBitangent( normalGeometry.cross( tangentGeometry ) ) ).normalize(); -export const bitangentLocal = varying( getBitangent( normalLocal.cross( tangentLocal ) ) ).normalize(); -export const bitangentView = varying( getBitangent( normalView.cross( tangentView ) ) ).normalize(); -export const bitangentWorld = varying( getBitangent( normalWorld.cross( tangentWorld ) ) ).normalize(); -export const transformedBitangentView = getBitangent( transformedNormalView.cross( transformedTangentView ) ).normalize(); -export const transformedBitangentWorld = transformedBitangentView.transformDirection( cameraViewMatrix ).normalize(); +export const bitangentGeometry = /*#__PURE__*/ varying( getBitangent( normalGeometry.cross( tangentGeometry ) ), 'v_bitangentGeometry' ).normalize().toVar( 'bitangentGeometry' ); +export const bitangentLocal = /*#__PURE__*/ varying( getBitangent( normalLocal.cross( tangentLocal ) ), 'v_bitangentLocal' ).normalize().toVar( 'bitangentLocal' ); +export const bitangentView = /*#__PURE__*/ varying( getBitangent( normalView.cross( tangentView ) ), 'v_bitangentView' ).normalize().toVar( 'bitangentView' ); +export const bitangentWorld = /*#__PURE__*/ varying( getBitangent( normalWorld.cross( tangentWorld ) ), 'v_bitangentWorld' ).normalize().toVar( 'bitangentWorld' ); +export const transformedBitangentView = /*#__PURE__*/ getBitangent( transformedNormalView.cross( transformedTangentView ) ).normalize().toVar( 'transformedBitangentView' ); +export const transformedBitangentWorld = /*#__PURE__*/ transformedBitangentView.transformDirection( cameraViewMatrix ).normalize().toVar( 'transformedBitangentWorld' ); diff --git a/examples/jsm/nodes/accessors/NormalNode.js b/examples/jsm/nodes/accessors/NormalNode.js index 2f1c3ca14217dd..a9c99ff27d1973 100644 --- a/examples/jsm/nodes/accessors/NormalNode.js +++ b/examples/jsm/nodes/accessors/NormalNode.js @@ -6,9 +6,9 @@ import { modelNormalMatrix } from './ModelNode.js'; import { vec3 } from '../shadernode/ShaderNode.js'; export const normalGeometry = /*#__PURE__*/ attribute( 'normal', 'vec3', vec3( 0, 1, 0 ) ); -export const normalLocal = /*#__PURE__*/ varying( normalGeometry ).toVar( 'normalLocal' ); -export const normalView = /*#__PURE__*/ varying( modelNormalMatrix.mul( normalLocal ), 'normalView' ).normalize(); -export const normalWorld = /*#__PURE__*/ varying( normalView.transformDirection( cameraViewMatrix ), 'normalWorld' ).normalize(); +export const normalLocal = /*#__PURE__*/ normalGeometry.toVar( 'normalLocal' ); +export const normalView = /*#__PURE__*/ varying( modelNormalMatrix.mul( normalLocal ), 'v_normalView' ).normalize().toVar( 'normalView' ); +export const normalWorld = /*#__PURE__*/ varying( normalView.transformDirection( cameraViewMatrix ), 'v_normalWorld' ).normalize().toVar( 'transformedNormalWorld' ); export const transformedNormalView = /*#__PURE__*/ property( 'vec3', 'transformedNormalView' ); -export const transformedNormalWorld = /*#__PURE__*/ transformedNormalView.transformDirection( cameraViewMatrix ).normalize(); +export const transformedNormalWorld = /*#__PURE__*/ transformedNormalView.transformDirection( cameraViewMatrix ).normalize().toVar( 'transformedNormalWorld' ); export const transformedClearcoatNormalView = /*#__PURE__*/ property( 'vec3', 'transformedClearcoatNormalView' ); diff --git a/examples/jsm/nodes/accessors/TangentNode.js b/examples/jsm/nodes/accessors/TangentNode.js index e8f85e69a3e813..f2e5726d258b89 100644 --- a/examples/jsm/nodes/accessors/TangentNode.js +++ b/examples/jsm/nodes/accessors/TangentNode.js @@ -16,8 +16,8 @@ export const tangentGeometry = /*#__PURE__*/ tslFn( ( stack, builder ) => { } )(); -export const tangentLocal = /*#__PURE__*/ varying( tangentGeometry.xyz, 'tangentLocal' ); -export const tangentView = /*#__PURE__*/ varying( modelViewMatrix.mul( vec4( tangentLocal, 0 ) ).xyz, 'tangentView' ).normalize(); -export const tangentWorld = /*#__PURE__*/ varying( tangentView.transformDirection( cameraViewMatrix ), 'tangentWorld' ).normalize(); +export const tangentLocal = /*#__PURE__*/ tangentGeometry.xyz.toVar( 'tangentLocal' ); +export const tangentView = /*#__PURE__*/ varying( modelViewMatrix.mul( vec4( tangentLocal, 0 ) ).xyz, 'v_tangentView' ).normalize().toVar( 'tangentView' ); +export const tangentWorld = /*#__PURE__*/ varying( tangentView.transformDirection( cameraViewMatrix ), 'v_tangentWorld' ).normalize().toVar( 'tangentWorld' ); export const transformedTangentView = /*#__PURE__*/ tangentView.toVar( 'transformedTangentView' ); -export const transformedTangentWorld = /*#__PURE__*/ transformedTangentView.transformDirection( cameraViewMatrix ).normalize(); +export const transformedTangentWorld = /*#__PURE__*/ transformedTangentView.transformDirection( cameraViewMatrix ).normalize().toVar( 'transformedTangentWorld' ); diff --git a/examples/jsm/nodes/accessors/UVNode.js b/examples/jsm/nodes/accessors/UVNode.js index 473545eb081582..4789a74bc36d67 100644 --- a/examples/jsm/nodes/accessors/UVNode.js +++ b/examples/jsm/nodes/accessors/UVNode.js @@ -1,47 +1,3 @@ -import { addNodeClass } from '../core/Node.js'; -import AttributeNode from '../core/AttributeNode.js'; -import { nodeObject } from '../shadernode/ShaderNode.js'; +import { attribute } from '../core/AttributeNode.js'; -class UVNode extends AttributeNode { - - constructor( index = 0 ) { - - super( null, 'vec2' ); - - this.isUVNode = true; - - this.index = index; - - } - - getAttributeName( /*builder*/ ) { - - const index = this.index; - - return 'uv' + ( index > 0 ? index : '' ); - - } - - serialize( data ) { - - super.serialize( data ); - - data.index = this.index; - - } - - deserialize( data ) { - - super.deserialize( data ); - - this.index = data.index; - - } - -} - -export default UVNode; - -export const uv = ( ...params ) => nodeObject( new UVNode( ...params ) ); - -addNodeClass( 'UVNode', UVNode ); +export const uv = ( index ) => attribute( 'uv' + ( index > 0 ? index : '' ), 'vec2' ); From c104489e1fc201cdde6ff066dd0dfbcd34d4a9b9 Mon Sep 17 00:00:00 2001 From: ycw Date: Tue, 28 May 2024 00:30:41 -0500 Subject: [PATCH 14/16] Editor: Ensures that video dimensions are divisible by 2 (requirement of libx264) (#28498) * div2 * div2 2 * Update Sidebar.Project.Video.js --------- Co-authored-by: mrdoob --- editor/js/Sidebar.Project.Video.js | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/editor/js/Sidebar.Project.Video.js b/editor/js/Sidebar.Project.Video.js index 3fae5fdb2a8488..37262771daa393 100644 --- a/editor/js/Sidebar.Project.Video.js +++ b/editor/js/Sidebar.Project.Video.js @@ -16,17 +16,25 @@ function SidebarProjectVideo( editor ) { // Resolution + function toDiv2() { + + // Make sure dimensions are divisible by 2 (requirement of libx264) + + this.setValue( 2 * Math.floor( this.getValue() / 2 ) ); + + } + const resolutionRow = new UIRow(); container.add( resolutionRow ); resolutionRow.add( new UIText( strings.getKey( 'sidebar/project/resolution' ) ).setClass( 'Label' ) ); - const videoWidth = new UIInteger( 1024 ).setTextAlign( 'center' ).setWidth( '28px' ); + const videoWidth = new UIInteger( 1024 ).setTextAlign( 'center' ).setWidth( '28px' ).setStep( 2 ).onChange( toDiv2 ); resolutionRow.add( videoWidth ); resolutionRow.add( new UIText( '×' ).setTextAlign( 'center' ).setFontSize( '12px' ).setWidth( '12px' ) ); - const videoHeight = new UIInteger( 1024 ).setTextAlign( 'center' ).setWidth( '28px' ); + const videoHeight = new UIInteger( 1024 ).setTextAlign( 'center' ).setWidth( '28px' ).setStep( 2 ).onChange( toDiv2 ); resolutionRow.add( videoHeight ); const videoFPS = new UIInteger( 30 ).setTextAlign( 'center' ).setWidth( '20px' ); From 9d6f51c7f0614210a1e1cd04a62c395ca965dcd4 Mon Sep 17 00:00:00 2001 From: "Mr.doob" Date: Tue, 28 May 2024 14:47:44 +0900 Subject: [PATCH 15/16] Editor: Use jsdelivr ffmpeg. --- editor/index.html | 2 +- editor/js/libs/ffmpeg.min.js | 2 -- editor/sw.js | 1 - 3 files changed, 1 insertion(+), 4 deletions(-) delete mode 100644 editor/js/libs/ffmpeg.min.js diff --git a/editor/index.html b/editor/index.html index cbbae21ea2dc2e..df86a2f54506b3 100644 --- a/editor/index.html +++ b/editor/index.html @@ -23,7 +23,7 @@ - + diff --git a/editor/js/libs/ffmpeg.min.js b/editor/js/libs/ffmpeg.min.js deleted file mode 100644 index 1c8795e1174ca3..00000000000000 --- a/editor/js/libs/ffmpeg.min.js +++ /dev/null @@ -1,2 +0,0 @@ -!function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t():"function"==typeof define&&define.amd?define([],t):"object"==typeof exports?exports.FFmpeg=t():e.FFmpeg=t()}(self,(function(){return e={497:(e,t,r)=>{r(72);var n=r(306).devDependencies;e.exports={corePath:"https://unpkg.com/@ffmpeg/core@".concat(n["@ffmpeg/core"].substring(1),"/dist/ffmpeg-core.js")}},663:(e,t,r)=>{function n(e,t,r,n,o,i,a){try{var c=e[i](a),s=c.value}catch(e){return void r(e)}c.done?t(s):Promise.resolve(s).then(n,o)}var o=r(72),i=function(e){return new Promise((function(t,r){var n=new FileReader;n.onload=function(){t(n.result)},n.onerror=function(e){var t=e.target.error.code;r(Error("File could not be read! Code=".concat(t)))},n.readAsArrayBuffer(e)}))};e.exports=function(){var e,t=(e=regeneratorRuntime.mark((function e(t){var r,n;return regeneratorRuntime.wrap((function(e){for(;;)switch(e.prev=e.next){case 0:if(r=t,void 0!==t){e.next=3;break}return e.abrupt("return",new Uint8Array);case 3:if("string"!=typeof t){e.next=16;break}if(!/data:_data\/([a-zA-Z]*);base64,([^"]*)/.test(t)){e.next=8;break}r=atob(t.split(",")[1]).split("").map((function(e){return e.charCodeAt(0)})),e.next=14;break;case 8:return e.next=10,fetch(o(t));case 10:return n=e.sent,e.next=13,n.arrayBuffer();case 13:r=e.sent;case 14:e.next=20;break;case 16:if(!(t instanceof File||t instanceof Blob)){e.next=20;break}return e.next=19,i(t);case 19:r=e.sent;case 20:return e.abrupt("return",new Uint8Array(r));case 21:case"end":return e.stop()}}),e)})),function(){var t=this,r=arguments;return new Promise((function(o,i){var a=e.apply(t,r);function c(e){n(a,o,i,c,s,"next",e)}function s(e){n(a,o,i,c,s,"throw",e)}c(void 0)}))});return function(e){return t.apply(this,arguments)}}()},452:(e,t,r)=>{function n(e,t,r,n,o,i,a){try{var c=e[i](a),s=c.value}catch(e){return void r(e)}c.done?t(s):Promise.resolve(s).then(n,o)}function o(e){return function(){var t=this,r=arguments;return new Promise((function(o,i){var a=e.apply(t,r);function c(e){n(a,o,i,c,s,"next",e)}function s(e){n(a,o,i,c,s,"throw",e)}c(void 0)}))}}var i=r(72),a=r(185).log,c=function(){var e=o(regeneratorRuntime.mark((function e(t,r){var n,o,i;return regeneratorRuntime.wrap((function(e){for(;;)switch(e.prev=e.next){case 0:return a("info","fetch ".concat(t)),e.next=3,fetch(t);case 3:return e.next=5,e.sent.arrayBuffer();case 5:return n=e.sent,a("info","".concat(t," file size = ").concat(n.byteLength," bytes")),o=new Blob([n],{type:r}),i=URL.createObjectURL(o),a("info","".concat(t," blob URL = ").concat(i)),e.abrupt("return",i);case 11:case"end":return e.stop()}}),e)})));return function(t,r){return e.apply(this,arguments)}}();e.exports=function(){var e=o(regeneratorRuntime.mark((function e(t){var r,n,o,s,u;return regeneratorRuntime.wrap((function(e){for(;;)switch(e.prev=e.next){case 0:if("string"==typeof(r=t.corePath)){e.next=3;break}throw Error("corePath should be a string!");case 3:return n=i(r),e.next=6,c(n,"application/javascript");case 6:return o=e.sent,e.next=9,c(n.replace("ffmpeg-core.js","ffmpeg-core.wasm"),"application/wasm");case 9:return s=e.sent,e.next=12,c(n.replace("ffmpeg-core.js","ffmpeg-core.worker.js"),"application/javascript");case 12:if(u=e.sent,"undefined"!=typeof createFFmpegCore){e.next=15;break}return e.abrupt("return",new Promise((function(e){var t=document.createElement("script");t.src=o,t.type="text/javascript",t.addEventListener("load",(function r(){t.removeEventListener("load",r),a("info","ffmpeg-core.js script loaded"),e({createFFmpegCore,corePath:o,wasmPath:s,workerPath:u})})),document.getElementsByTagName("head")[0].appendChild(t)})));case 15:return a("info","ffmpeg-core.js script is loaded already"),e.abrupt("return",Promise.resolve({createFFmpegCore,corePath:o,wasmPath:s,workerPath:u}));case 17:case"end":return e.stop()}}),e)})));return function(t){return e.apply(this,arguments)}}()},698:(e,t,r)=>{var n=r(497),o=r(452),i=r(663);e.exports={defaultOptions:n,getCreateFFmpegCore:o,fetchFile:i}},500:e=>{e.exports={defaultArgs:["./ffmpeg","-nostdin","-y"],baseOptions:{log:!1,logger:function(){},progress:function(){},corePath:""}}},906:(e,t,r)=>{function n(e){return function(e){if(Array.isArray(e))return o(e)}(e)||function(e){if("undefined"!=typeof Symbol&&Symbol.iterator in Object(e))return Array.from(e)}(e)||function(e,t){if(e){if("string"==typeof e)return o(e,t);var r=Object.prototype.toString.call(e).slice(8,-1);return"Object"===r&&e.constructor&&(r=e.constructor.name),"Map"===r||"Set"===r?Array.from(e):"Arguments"===r||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(r)?o(e,t):void 0}}(e)||function(){throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}()}function o(e,t){(null==t||t>e.length)&&(t=e.length);for(var r=0,n=new Array(t);r=0||(o[r]=e[r]);return o}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(o[r]=e[r])}return o}var l=r(500),p=l.defaultArgs,h=l.baseOptions,m=r(185),g=m.setLogging,d=m.setCustomLogger,y=m.log,v=r(583),b=r(319),w=r(698),x=w.defaultOptions,j=w.getCreateFFmpegCore,E=r(306).version,O=Error("ffmpeg.wasm is not ready, make sure you have completed load().");e.exports=function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{},t=s(s(s({},h),x),e),r=t.log,o=t.logger,i=t.progress,c=f(t,["log","logger","progress"]),u=null,l=null,m=null,w=!1,F=i,L=function(e){"FFMPEG_END"===e&&null!==m&&(m(),m=null,w=!1)},P=function(e){var t=e.type,r=e.message;y(t,r),v(r,F),L(r)},k=function(){var e=a(regeneratorRuntime.mark((function e(){var t,r,n,o,i;return regeneratorRuntime.wrap((function(e){for(;;)switch(e.prev=e.next){case 0:if(y("info","load ffmpeg-core"),null!==u){e.next=17;break}return y("info","loading ffmpeg-core"),e.next=5,j(c);case 5:return t=e.sent,r=t.createFFmpegCore,n=t.corePath,o=t.workerPath,i=t.wasmPath,e.next=12,r({mainScriptUrlOrBlob:n,printErr:function(e){return P({type:"fferr",message:e})},print:function(e){return P({type:"ffout",message:e})},locateFile:function(e,t){if("undefined"!=typeof window){if(void 0!==i&&e.endsWith("ffmpeg-core.wasm"))return i;if(void 0!==o&&e.endsWith("ffmpeg-core.worker.js"))return o}return t+e}});case 12:u=e.sent,l=u.cwrap("proxy_main","number",["number","number"]),y("info","ffmpeg-core loaded"),e.next=18;break;case 17:throw Error("ffmpeg.wasm was loaded, you should not load it again, use ffmpeg.isLoaded() to check next time.");case 18:case"end":return e.stop()}}),e)})));return function(){return e.apply(this,arguments)}}(),S=function(){return null!==u},A=function(){for(var e=arguments.length,t=new Array(e),r=0;r1?t-1:0),n=1;n")})).join(" "))),null===u)throw O;var o=null;try{var i;o=(i=u.FS)[e].apply(i,r)}catch(t){throw"readdir"===e?Error("ffmpeg.FS('readdir', '".concat(r[0],"') error. Check if the path exists, ex: ffmpeg.FS('readdir', '/')")):"readFile"===e?Error("ffmpeg.FS('readFile', '".concat(r[0],"') error. Check if the path exists")):Error("Oops, something went wrong in FS operation.")}return o},C=function(){if(null===u)throw O;w=!1,u.exit(1),u=null,l=null,m=null},R=function(e){F=e},T=function(e){d(e)};return g(r),d(o),y("info","use ffmpeg.wasm v".concat(E)),{setProgress:R,setLogger:T,setLogging:g,load:k,isLoaded:S,run:A,exit:C,FS:_}}},352:(e,t,r)=>{r(666);var n=r(906),o=r(698).fetchFile;e.exports={createFFmpeg:n,fetchFile:o}},185:e=>{var t=!1,r=function(){};e.exports={logging:t,setLogging:function(e){t=e},setCustomLogger:function(e){r=e},log:function(e,n){r({type:e,message:n}),t&&console.log("[".concat(e,"] ").concat(n))}}},319:e=>{e.exports=function(e,t){var r=e._malloc(t.length*Uint32Array.BYTES_PER_ELEMENT);return t.forEach((function(t,n){var o=e._malloc(t.length+1);e.writeAsciiToMemory(t,o),e.setValue(r+Uint32Array.BYTES_PER_ELEMENT*n,o,"i32")})),[t.length,r]}},583:e=>{function t(e,t){(null==t||t>e.length)&&(t=e.length);for(var r=0,n=new Array(t);ra)&&(r=a)}else if(e.startsWith("frame")||e.startsWith("size")){var c=e.split("time=")[1].split(" ")[0],s=o(c);t({ratio:n=s/r,time:s})}else e.startsWith("video:")&&(t({ratio:1}),r=0)}},666:e=>{var t=function(e){"use strict";var t,r=Object.prototype,n=r.hasOwnProperty,o="function"==typeof Symbol?Symbol:{},i=o.iterator||"@@iterator",a=o.asyncIterator||"@@asyncIterator",c=o.toStringTag||"@@toStringTag";function s(e,t,r){return Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}),e[t]}try{s({},"")}catch(e){s=function(e,t,r){return e[t]=r}}function u(e,t,r,n){var o=t&&t.prototype instanceof d?t:d,i=Object.create(o.prototype),a=new k(n||[]);return i._invoke=function(e,t,r){var n=l;return function(o,i){if(n===h)throw new Error("Generator is already running");if(n===m){if("throw"===o)throw i;return A()}for(r.method=o,r.arg=i;;){var a=r.delegate;if(a){var c=F(a,r);if(c){if(c===g)continue;return c}}if("next"===r.method)r.sent=r._sent=r.arg;else if("throw"===r.method){if(n===l)throw n=m,r.arg;r.dispatchException(r.arg)}else"return"===r.method&&r.abrupt("return",r.arg);n=h;var s=f(e,t,r);if("normal"===s.type){if(n=r.done?m:p,s.arg===g)continue;return{value:s.arg,done:r.done}}"throw"===s.type&&(n=m,r.method="throw",r.arg=s.arg)}}}(e,r,a),i}function f(e,t,r){try{return{type:"normal",arg:e.call(t,r)}}catch(e){return{type:"throw",arg:e}}}e.wrap=u;var l="suspendedStart",p="suspendedYield",h="executing",m="completed",g={};function d(){}function y(){}function v(){}var b={};b[i]=function(){return this};var w=Object.getPrototypeOf,x=w&&w(w(S([])));x&&x!==r&&n.call(x,i)&&(b=x);var j=v.prototype=d.prototype=Object.create(b);function E(e){["next","throw","return"].forEach((function(t){s(e,t,(function(e){return this._invoke(t,e)}))}))}function O(e,t){function r(o,i,a,c){var s=f(e[o],e,i);if("throw"!==s.type){var u=s.arg,l=u.value;return l&&"object"==typeof l&&n.call(l,"__await")?t.resolve(l.__await).then((function(e){r("next",e,a,c)}),(function(e){r("throw",e,a,c)})):t.resolve(l).then((function(e){u.value=e,a(u)}),(function(e){return r("throw",e,a,c)}))}c(s.arg)}var o;this._invoke=function(e,n){function i(){return new t((function(t,o){r(e,n,t,o)}))}return o=o?o.then(i,i):i()}}function F(e,r){var n=e.iterator[r.method];if(n===t){if(r.delegate=null,"throw"===r.method){if(e.iterator.return&&(r.method="return",r.arg=t,F(e,r),"throw"===r.method))return g;r.method="throw",r.arg=new TypeError("The iterator does not provide a 'throw' method")}return g}var o=f(n,e.iterator,r.arg);if("throw"===o.type)return r.method="throw",r.arg=o.arg,r.delegate=null,g;var i=o.arg;return i?i.done?(r[e.resultName]=i.value,r.next=e.nextLoc,"return"!==r.method&&(r.method="next",r.arg=t),r.delegate=null,g):i:(r.method="throw",r.arg=new TypeError("iterator result is not an object"),r.delegate=null,g)}function L(e){var t={tryLoc:e[0]};1 in e&&(t.catchLoc=e[1]),2 in e&&(t.finallyLoc=e[2],t.afterLoc=e[3]),this.tryEntries.push(t)}function P(e){var t=e.completion||{};t.type="normal",delete t.arg,e.completion=t}function k(e){this.tryEntries=[{tryLoc:"root"}],e.forEach(L,this),this.reset(!0)}function S(e){if(e){var r=e[i];if(r)return r.call(e);if("function"==typeof e.next)return e;if(!isNaN(e.length)){var o=-1,a=function r(){for(;++o=0;--i){var a=this.tryEntries[i],c=a.completion;if("root"===a.tryLoc)return o("end");if(a.tryLoc<=this.prev){var s=n.call(a,"catchLoc"),u=n.call(a,"finallyLoc");if(s&&u){if(this.prev=0;--r){var o=this.tryEntries[r];if(o.tryLoc<=this.prev&&n.call(o,"finallyLoc")&&this.prev=0;--t){var r=this.tryEntries[t];if(r.finallyLoc===e)return this.complete(r.completion,r.afterLoc),P(r),g}},catch:function(e){for(var t=this.tryEntries.length-1;t>=0;--t){var r=this.tryEntries[t];if(r.tryLoc===e){var n=r.completion;if("throw"===n.type){var o=n.arg;P(r)}return o}}throw new Error("illegal catch attempt")},delegateYield:function(e,r,n){return this.delegate={iterator:S(e),resultName:r,nextLoc:n},"next"===this.method&&(this.arg=t),g}},e}(e.exports);try{regeneratorRuntime=t}catch(e){Function("r","regeneratorRuntime = r")(t)}},72:function(e,t,r){var n,o;void 0===(o="function"==typeof(n=function(){return function(){var e=arguments.length;if(0===e)throw new Error("resolveUrl requires at least one argument; got none.");var t=document.createElement("base");if(t.href=arguments[0],1===e)return t.href;var r=document.getElementsByTagName("head")[0];r.insertBefore(t,r.firstChild);for(var n,o=document.createElement("a"),i=1;i{"use strict";e.exports=JSON.parse('{"name":"@ffmpeg/ffmpeg","version":"0.10.1","description":"FFmpeg WebAssembly version","main":"src/index.js","types":"src/index.d.ts","directories":{"example":"examples"},"scripts":{"start":"node scripts/server.js","build":"rimraf dist && webpack --config scripts/webpack.config.prod.js","prepublishOnly":"npm run build","lint":"eslint src","wait":"rimraf dist && wait-on http://localhost:3000/dist/ffmpeg.dev.js","test":"npm-run-all -p -r start test:all","test:all":"npm-run-all wait test:browser:ffmpeg test:node:all","test:node":"node --experimental-wasm-threads --experimental-wasm-bulk-memory node_modules/.bin/_mocha --exit --bail --require ./scripts/test-helper.js","test:node:all":"npm run test:node -- ./tests/*.test.js","test:browser":"mocha-headless-chrome -a allow-file-access-from-files -a incognito -a no-sandbox -a disable-setuid-sandbox -a disable-logging -t 300000","test:browser:ffmpeg":"npm run test:browser -- -f ./tests/ffmpeg.test.html"},"browser":{"./src/node/index.js":"./src/browser/index.js"},"repository":{"type":"git","url":"git+https://github.com/ffmpegwasm/ffmpeg.wasm.git"},"keywords":["ffmpeg","WebAssembly","video"],"author":"Jerome Wu ","license":"MIT","bugs":{"url":"https://github.com/ffmpegwasm/ffmpeg.wasm/issues"},"engines":{"node":">=12.16.1"},"homepage":"https://github.com/ffmpegwasm/ffmpeg.wasm#readme","dependencies":{"is-url":"^1.2.4","node-fetch":"^2.6.1","regenerator-runtime":"^0.13.7","resolve-url":"^0.2.1"},"devDependencies":{"@babel/core":"^7.12.3","@babel/preset-env":"^7.12.1","@ffmpeg/core":"^0.10.0","@types/emscripten":"^1.39.4","babel-loader":"^8.1.0","chai":"^4.2.0","cors":"^2.8.5","eslint":"^7.12.1","eslint-config-airbnb-base":"^14.1.0","eslint-plugin-import":"^2.22.1","express":"^4.17.1","mocha":"^8.2.1","mocha-headless-chrome":"^2.0.3","npm-run-all":"^4.1.5","wait-on":"^5.3.0","webpack":"^5.3.2","webpack-cli":"^4.1.0","webpack-dev-middleware":"^4.0.0"}}')}},t={},function r(n){if(t[n])return t[n].exports;var o=t[n]={exports:{}};return e[n].call(o.exports,o,o.exports,r),o.exports}(352);var e,t})); -//# sourceMappingURL=ffmpeg.min.js.map \ No newline at end of file diff --git a/editor/sw.js b/editor/sw.js index 7553e8287e58da..3cec06c472b139 100644 --- a/editor/sw.js +++ b/editor/sw.js @@ -91,7 +91,6 @@ const assets = [ './js/libs/codemirror/mode/glsl.js', './js/libs/esprima.js', - './js/libs/ffmpeg.min.js', './js/libs/jsonlint.js', './js/libs/codemirror/addon/dialog.css', From 936402ce754a79cf379e5ae1910618212463116e Mon Sep 17 00:00:00 2001 From: "Mr.doob" Date: Tue, 28 May 2024 15:33:08 +0900 Subject: [PATCH 16/16] Editor: Updated ffmpeg to 0.11.6 0.12.* seems to have issues on localhost (DOMException: Failed to construct 'Worker') --- editor/index.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/editor/index.html b/editor/index.html index df86a2f54506b3..29775ed72887a9 100644 --- a/editor/index.html +++ b/editor/index.html @@ -23,7 +23,7 @@ - +