@babylonjs/smart-filters 0.3.2-alpha → 0.3.4-alpha
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/blocks/inputBlock.d.ts +19 -0
- package/dist/blocks/inputBlock.d.ts.map +1 -1
- package/dist/blocks/inputBlock.deserializer.d.ts +1 -3
- package/dist/blocks/inputBlock.deserializer.d.ts.map +1 -1
- package/dist/blocks/inputBlock.deserializer.js +14 -13
- package/dist/blocks/inputBlock.deserializer.js.map +1 -1
- package/dist/blocks/inputBlock.js.map +1 -1
- package/dist/blocks/inputBlock.serialization.types.d.ts +13 -0
- package/dist/blocks/inputBlock.serialization.types.d.ts.map +1 -1
- package/dist/blocks/inputBlock.serializer.d.ts.map +1 -1
- package/dist/blocks/inputBlock.serializer.js +12 -4
- package/dist/blocks/inputBlock.serializer.js.map +1 -1
- package/dist/blocks/outputBlock.d.ts +7 -0
- package/dist/blocks/outputBlock.d.ts.map +1 -1
- package/dist/blocks/outputBlock.js +7 -4
- package/dist/blocks/outputBlock.js.map +1 -1
- package/dist/blocks/shaderBlock.d.ts.map +1 -1
- package/dist/blocks/shaderBlock.js +5 -8
- package/dist/blocks/shaderBlock.js.map +1 -1
- package/dist/runtime/renderTargetGenerator.d.ts +3 -2
- package/dist/runtime/renderTargetGenerator.d.ts.map +1 -1
- package/dist/runtime/renderTargetGenerator.js +25 -14
- package/dist/runtime/renderTargetGenerator.js.map +1 -1
- package/dist/serialization/smartFilterDeserializer.d.ts.map +1 -1
- package/dist/serialization/smartFilterDeserializer.js +12 -5
- package/dist/serialization/smartFilterDeserializer.js.map +1 -1
- package/dist/serialization/smartFilterSerializer.js +4 -4
- package/dist/serialization/smartFilterSerializer.js.map +1 -1
- package/dist/serialization/v1/serialization.types.d.ts +4 -4
- package/dist/serialization/v1/serialization.types.d.ts.map +1 -1
- package/dist/smartFilter.d.ts +4 -1
- package/dist/smartFilter.d.ts.map +1 -1
- package/dist/smartFilter.js +7 -7
- package/dist/smartFilter.js.map +1 -1
- package/dist/utils/buildTools/buildShaders.d.ts +8 -0
- package/dist/utils/buildTools/buildShaders.d.ts.map +1 -0
- package/dist/utils/buildTools/buildShaders.js +12 -0
- package/dist/utils/buildTools/buildShaders.js.map +1 -0
- package/dist/utils/buildTools/shaderConverter.d.ts +12 -1
- package/dist/utils/buildTools/shaderConverter.d.ts.map +1 -1
- package/dist/utils/buildTools/shaderConverter.js +4 -8
- package/dist/utils/buildTools/shaderConverter.js.map +1 -1
- package/dist/utils/buildTools/watchShaders.d.ts +8 -0
- package/dist/utils/buildTools/watchShaders.d.ts.map +1 -0
- package/dist/utils/buildTools/watchShaders.js +36 -0
- package/dist/utils/buildTools/watchShaders.js.map +1 -0
- package/dist/utils/renderTargetUtils.d.ts +24 -0
- package/dist/utils/renderTargetUtils.d.ts.map +1 -0
- package/dist/utils/renderTargetUtils.js +38 -0
- package/dist/utils/renderTargetUtils.js.map +1 -0
- package/package.json +5 -3
- package/src/blocks/inputBlock.deserializer.ts +20 -21
- package/src/blocks/inputBlock.serialization.types.ts +16 -0
- package/src/blocks/inputBlock.serializer.ts +10 -1
- package/src/blocks/inputBlock.ts +25 -1
- package/src/blocks/outputBlock.ts +10 -6
- package/src/blocks/shaderBlock.ts +11 -10
- package/src/runtime/renderTargetGenerator.ts +31 -14
- package/src/serialization/smartFilterDeserializer.ts +17 -6
- package/src/serialization/smartFilterSerializer.ts +4 -4
- package/src/serialization/v1/serialization.types.ts +4 -4
- package/src/smartFilter.ts +12 -9
- package/src/utils/buildTools/buildShaders.ts +13 -0
- package/src/utils/buildTools/shaderConverter.ts +4 -9
- package/src/utils/buildTools/watchShaders.ts +40 -0
- package/src/utils/renderTargetUtils.ts +56 -0
|
@@ -3,7 +3,9 @@ import { ConnectionPointType } from "../connection/connectionPointType.js";
|
|
|
3
3
|
import { BaseBlock } from "./baseBlock.js";
|
|
4
4
|
import { CopyBlock } from "./copyBlock.js";
|
|
5
5
|
import { ShaderRuntime } from "../runtime/shaderRuntime.js";
|
|
6
|
-
import {
|
|
6
|
+
import type { Nullable } from "@babylonjs/core/types";
|
|
7
|
+
import type { ThinRenderTargetTexture } from "@babylonjs/core/Materials/Textures/thinRenderTargetTexture";
|
|
8
|
+
import { registerFinalRenderCommand } from "../utils/renderTargetUtils.js";
|
|
7
9
|
|
|
8
10
|
/**
|
|
9
11
|
* The output block of a smart filter.
|
|
@@ -23,6 +25,12 @@ export class OutputBlock extends BaseBlock {
|
|
|
23
25
|
*/
|
|
24
26
|
public readonly input = this._registerInput("input", ConnectionPointType.Texture);
|
|
25
27
|
|
|
28
|
+
/**
|
|
29
|
+
* If supplied, the Smart Filter will render into this texture. Otherwise, it renders
|
|
30
|
+
* into the the canvas or WebGL context the ThinEngine is using for rendering.
|
|
31
|
+
*/
|
|
32
|
+
public renderTargetTexture: Nullable<ThinRenderTargetTexture> = null;
|
|
33
|
+
|
|
26
34
|
private _copyBlock: CopyBlock | null;
|
|
27
35
|
|
|
28
36
|
/**
|
|
@@ -86,11 +94,7 @@ export class OutputBlock extends BaseBlock {
|
|
|
86
94
|
initializationData.initializationPromises.push(shaderBlockRuntime.onReadyAsync);
|
|
87
95
|
runtime.registerResource(shaderBlockRuntime);
|
|
88
96
|
|
|
89
|
-
runtime
|
|
90
|
-
createCommand(`${this.getClassName()}.renderToCanvas`, this, () => {
|
|
91
|
-
shaderBlockRuntime.renderToCanvas();
|
|
92
|
-
})
|
|
93
|
-
);
|
|
97
|
+
registerFinalRenderCommand(this.renderTargetTexture, runtime, this, shaderBlockRuntime);
|
|
94
98
|
|
|
95
99
|
super.generateCommandsAndGatherInitPromises(initializationData, finalOutput);
|
|
96
100
|
}
|
|
@@ -10,6 +10,7 @@ import { ConnectionPointType } from "../connection/connectionPointType.js";
|
|
|
10
10
|
import { createCommand } from "../command/command.js";
|
|
11
11
|
import { DisableableBlock } from "./disableableBlock.js";
|
|
12
12
|
import { undecorateSymbol } from "../utils/shaderCodeUtils.js";
|
|
13
|
+
import { getRenderTarget, registerFinalRenderCommand } from "../utils/renderTargetUtils.js";
|
|
13
14
|
|
|
14
15
|
/**
|
|
15
16
|
* This is the base class for all shader blocks.
|
|
@@ -121,21 +122,21 @@ export abstract class ShaderBlock extends DisableableBlock {
|
|
|
121
122
|
runtime.registerResource(shaderBlockRuntime);
|
|
122
123
|
|
|
123
124
|
if (finalOutput) {
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
125
|
+
registerFinalRenderCommand(
|
|
126
|
+
initializationData.outputBlock.renderTargetTexture,
|
|
127
|
+
runtime,
|
|
128
|
+
this,
|
|
129
|
+
shaderBlockRuntime
|
|
128
130
|
);
|
|
129
131
|
} else {
|
|
130
|
-
const
|
|
131
|
-
this.output.runtimeData
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
}
|
|
132
|
+
const renderTarget = getRenderTarget(
|
|
133
|
+
this.output.runtimeData?.value as ThinRenderTargetTexture,
|
|
134
|
+
this.getClassName()
|
|
135
|
+
);
|
|
135
136
|
|
|
136
137
|
runtime.registerCommand(
|
|
137
138
|
createCommand(`${this.getClassName()}.render`, this, () => {
|
|
138
|
-
shaderBlockRuntime.renderToTexture(
|
|
139
|
+
shaderBlockRuntime.renderToTexture(renderTarget);
|
|
139
140
|
})
|
|
140
141
|
);
|
|
141
142
|
}
|
|
@@ -51,11 +51,11 @@ export class RenderTargetGenerator {
|
|
|
51
51
|
|
|
52
52
|
/**
|
|
53
53
|
* Sets the output textures for the ShaderBlocks of the smart filter.
|
|
54
|
-
* @param
|
|
54
|
+
* @param smartFilter - The smart filter to generate the render targets for.
|
|
55
55
|
* @param initializationData - The initialization data to use.
|
|
56
56
|
*/
|
|
57
|
-
public setOutputTextures(
|
|
58
|
-
|
|
57
|
+
public setOutputTextures(smartFilter: SmartFilter, initializationData: InitializationData) {
|
|
58
|
+
smartFilter.output.ownerBlock.visit(
|
|
59
59
|
initializationData,
|
|
60
60
|
(block: BaseBlock, initializationData: InitializationData) => {
|
|
61
61
|
if (!(block instanceof ShaderBlock)) {
|
|
@@ -66,8 +66,8 @@ export class RenderTargetGenerator {
|
|
|
66
66
|
|
|
67
67
|
// We assign a texture to the output of the block only if this is not the last block in the chain,
|
|
68
68
|
// i.e. not the block connected to the smart output block (in which case the output of the block is to the canvas and not a texture).
|
|
69
|
-
if (!block.output.endpoints.some((cp) => cp.ownerBlock ===
|
|
70
|
-
refCountedTexture = this._getTexture(initializationData.runtime, block.textureRatio);
|
|
69
|
+
if (!block.output.endpoints.some((cp) => cp.ownerBlock === smartFilter.output.ownerBlock)) {
|
|
70
|
+
refCountedTexture = this._getTexture(initializationData.runtime, block.textureRatio, smartFilter);
|
|
71
71
|
|
|
72
72
|
if (!block.output.runtimeData) {
|
|
73
73
|
const runtimeOutput = createStrongRef(refCountedTexture.texture);
|
|
@@ -122,11 +122,15 @@ export class RenderTargetGenerator {
|
|
|
122
122
|
return null;
|
|
123
123
|
}
|
|
124
124
|
|
|
125
|
-
private _getTexture(
|
|
125
|
+
private _getTexture(
|
|
126
|
+
runtime: InternalSmartFilterRuntime,
|
|
127
|
+
ratio: number,
|
|
128
|
+
smartFilter: SmartFilter
|
|
129
|
+
): RefCountedTexture {
|
|
126
130
|
if (!this._optimize) {
|
|
127
131
|
this._numTargetsCreated++;
|
|
128
132
|
return {
|
|
129
|
-
texture: this._createTexture(runtime, ratio),
|
|
133
|
+
texture: this._createTexture(runtime, smartFilter, ratio),
|
|
130
134
|
refCount: 0,
|
|
131
135
|
};
|
|
132
136
|
}
|
|
@@ -140,7 +144,7 @@ export class RenderTargetGenerator {
|
|
|
140
144
|
let refCountedTexture = this._findAvailableTexture(ratio);
|
|
141
145
|
if (!refCountedTexture) {
|
|
142
146
|
refCountedTexture = {
|
|
143
|
-
texture: this._createTexture(runtime, ratio),
|
|
147
|
+
texture: this._createTexture(runtime, smartFilter, ratio),
|
|
144
148
|
refCount: 0,
|
|
145
149
|
};
|
|
146
150
|
refCountedTextures.add(refCountedTexture);
|
|
@@ -173,10 +177,15 @@ export class RenderTargetGenerator {
|
|
|
173
177
|
/**
|
|
174
178
|
* Creates an offscreen texture to hold on the result of the block rendering.
|
|
175
179
|
* @param runtime - The current runtime we create the texture for
|
|
180
|
+
* @param smartFilter - The smart filter the texture is created for
|
|
176
181
|
* @param ratio - The ratio of the texture to create compared to the final output
|
|
177
182
|
* @returns The render target texture
|
|
178
183
|
*/
|
|
179
|
-
private _createTexture(
|
|
184
|
+
private _createTexture(
|
|
185
|
+
runtime: InternalSmartFilterRuntime,
|
|
186
|
+
smartFilter: SmartFilter,
|
|
187
|
+
ratio: number
|
|
188
|
+
): ThinRenderTargetTexture {
|
|
180
189
|
const engine = runtime.engine;
|
|
181
190
|
|
|
182
191
|
// We are only rendering full screen post process without depth or stencil information
|
|
@@ -187,12 +196,20 @@ export class RenderTargetGenerator {
|
|
|
187
196
|
samplingMode: 2, // Babylon Constants.TEXTURE_LINEAR_LINEAR,
|
|
188
197
|
};
|
|
189
198
|
|
|
190
|
-
//
|
|
191
|
-
|
|
192
|
-
|
|
199
|
+
// Get the smartFilter output size - either from the output block's renderTargetTexture or the engine's render size
|
|
200
|
+
let outputWidth: number;
|
|
201
|
+
let outputHeight: number;
|
|
202
|
+
const renderTargetTextureSize = smartFilter.outputBlock.renderTargetTexture?.getSize();
|
|
203
|
+
if (renderTargetTextureSize) {
|
|
204
|
+
outputWidth = renderTargetTextureSize.width;
|
|
205
|
+
outputHeight = renderTargetTextureSize.height;
|
|
206
|
+
} else {
|
|
207
|
+
outputWidth = engine.getRenderWidth(true);
|
|
208
|
+
outputHeight = engine.getRenderHeight(true);
|
|
209
|
+
}
|
|
193
210
|
const size = {
|
|
194
|
-
width: Math.floor(
|
|
195
|
-
height: Math.floor(
|
|
211
|
+
width: Math.floor(outputWidth * ratio),
|
|
212
|
+
height: Math.floor(outputHeight * ratio),
|
|
196
213
|
};
|
|
197
214
|
|
|
198
215
|
// Creates frame buffers for effects
|
|
@@ -31,8 +31,8 @@ export class SmartFilterDeserializer {
|
|
|
31
31
|
// Add in the core block deserializers - they are not delay loaded, so they are wrapped in Promise.resolve()
|
|
32
32
|
this._blockDeserializersV1.set(
|
|
33
33
|
InputBlock.ClassName,
|
|
34
|
-
(smartFilter: SmartFilter, serializedBlock: ISerializedBlockV1
|
|
35
|
-
Promise.resolve(inputBlockDeserializer(smartFilter, serializedBlock
|
|
34
|
+
(smartFilter: SmartFilter, serializedBlock: ISerializedBlockV1) =>
|
|
35
|
+
Promise.resolve(inputBlockDeserializer(smartFilter, serializedBlock))
|
|
36
36
|
);
|
|
37
37
|
|
|
38
38
|
this._blockDeserializersV1.set(OutputBlock.ClassName, (smartFilter: SmartFilter) =>
|
|
@@ -59,7 +59,10 @@ export class SmartFilterDeserializer {
|
|
|
59
59
|
serializedSmartFilter: SerializedSmartFilterV1
|
|
60
60
|
): Promise<SmartFilter> {
|
|
61
61
|
const smartFilter = new SmartFilter(serializedSmartFilter.name);
|
|
62
|
-
const
|
|
62
|
+
const blockIdMap = new Map<number, BaseBlock>();
|
|
63
|
+
|
|
64
|
+
// Only needed for smart filters saved before we started using uniqueIds for the maps, didn't warrant new version
|
|
65
|
+
const blockNameMap = new Map<string, BaseBlock>();
|
|
63
66
|
|
|
64
67
|
// Deserialize the SmartFilter level data
|
|
65
68
|
smartFilter.comments = serializedSmartFilter.comments;
|
|
@@ -85,7 +88,8 @@ export class SmartFilterDeserializer {
|
|
|
85
88
|
UniqueIdGenerator.EnsureIdsGreaterThan(newBlock.uniqueId);
|
|
86
89
|
|
|
87
90
|
// Save in the map
|
|
88
|
-
|
|
91
|
+
blockIdMap.set(newBlock.uniqueId, newBlock);
|
|
92
|
+
blockNameMap.set(newBlock.name, newBlock);
|
|
89
93
|
})
|
|
90
94
|
);
|
|
91
95
|
});
|
|
@@ -94,7 +98,11 @@ export class SmartFilterDeserializer {
|
|
|
94
98
|
// Deserialize the connections
|
|
95
99
|
serializedSmartFilter.connections.forEach((connection: ISerializedConnectionV1) => {
|
|
96
100
|
// Find the source block and its connection point's connectTo function
|
|
97
|
-
const sourceBlock =
|
|
101
|
+
const sourceBlock =
|
|
102
|
+
typeof connection.outputBlock === "string"
|
|
103
|
+
? blockNameMap.get(connection.outputBlock)
|
|
104
|
+
: blockIdMap.get(connection.outputBlock);
|
|
105
|
+
|
|
98
106
|
if (!sourceBlock) {
|
|
99
107
|
throw new Error(`Source block ${connection.outputBlock} not found`);
|
|
100
108
|
}
|
|
@@ -107,7 +115,10 @@ export class SmartFilterDeserializer {
|
|
|
107
115
|
const sourceConnectToFunction = sourceConnectionPoint.connectTo.bind(sourceConnectionPoint);
|
|
108
116
|
|
|
109
117
|
// Find the target block and its connection point
|
|
110
|
-
const targetBlock =
|
|
118
|
+
const targetBlock =
|
|
119
|
+
typeof connection.inputBlock === "string"
|
|
120
|
+
? blockNameMap.get(connection.inputBlock)
|
|
121
|
+
: blockIdMap.get(connection.inputBlock);
|
|
111
122
|
if (!targetBlock) {
|
|
112
123
|
throw new Error(`Target block ${connection.inputBlock} not found`);
|
|
113
124
|
}
|
|
@@ -72,9 +72,9 @@ export class SmartFilterSerializer {
|
|
|
72
72
|
const connectedTo = input.connectedTo;
|
|
73
73
|
if (connectedTo) {
|
|
74
74
|
const newConnection: ISerializedConnectionV1 = {
|
|
75
|
-
inputBlock: block.
|
|
75
|
+
inputBlock: block.uniqueId,
|
|
76
76
|
inputConnectionPoint: input.name,
|
|
77
|
-
outputBlock: connectedTo.ownerBlock.
|
|
77
|
+
outputBlock: connectedTo.ownerBlock.uniqueId,
|
|
78
78
|
outputConnectionPoint: connectedTo.name,
|
|
79
79
|
};
|
|
80
80
|
if (!connections.find((other) => serializedConnectionPointsEqual(newConnection, other))) {
|
|
@@ -87,9 +87,9 @@ export class SmartFilterSerializer {
|
|
|
87
87
|
block.outputs.forEach((output: ConnectionPoint) => {
|
|
88
88
|
output.endpoints.forEach((input: ConnectionPoint) => {
|
|
89
89
|
const newConnection: ISerializedConnectionV1 = {
|
|
90
|
-
inputBlock: input.ownerBlock.
|
|
90
|
+
inputBlock: input.ownerBlock.uniqueId,
|
|
91
91
|
inputConnectionPoint: input.name,
|
|
92
|
-
outputBlock: block.
|
|
92
|
+
outputBlock: block.uniqueId,
|
|
93
93
|
outputConnectionPoint: output.name,
|
|
94
94
|
};
|
|
95
95
|
if (!connections.find((other) => serializedConnectionPointsEqual(newConnection, other))) {
|
|
@@ -57,14 +57,14 @@ export interface ISerializedBlockV1 {
|
|
|
57
57
|
* V1 Serialized Connection
|
|
58
58
|
*/
|
|
59
59
|
export interface ISerializedConnectionV1 {
|
|
60
|
-
/** The
|
|
61
|
-
outputBlock:
|
|
60
|
+
/** The uniqueId of the block that the connection is to */
|
|
61
|
+
outputBlock: number;
|
|
62
62
|
|
|
63
63
|
/** The name of the connectionPoint on the outputBlock */
|
|
64
64
|
outputConnectionPoint: string;
|
|
65
65
|
|
|
66
|
-
/** The
|
|
67
|
-
inputBlock:
|
|
66
|
+
/** The uniqueId of the block that the connection is from */
|
|
67
|
+
inputBlock: number;
|
|
68
68
|
|
|
69
69
|
/** The name of the connectionPoint on the inputBlock */
|
|
70
70
|
inputConnectionPoint: string;
|
package/src/smartFilter.ts
CHANGED
|
@@ -55,6 +55,11 @@ export class SmartFilter {
|
|
|
55
55
|
*/
|
|
56
56
|
public readonly output: ConnectionPoint<ConnectionPointType.Texture>;
|
|
57
57
|
|
|
58
|
+
/**
|
|
59
|
+
* The output block of the smart filter.
|
|
60
|
+
*/
|
|
61
|
+
public readonly outputBlock: OutputBlock;
|
|
62
|
+
|
|
58
63
|
/**
|
|
59
64
|
* User defined comments to describe the current smart filter.
|
|
60
65
|
*/
|
|
@@ -66,8 +71,6 @@ export class SmartFilter {
|
|
|
66
71
|
public editorData: Nullable<IEditorData> = null;
|
|
67
72
|
|
|
68
73
|
private readonly _attachedBlocks: Array<BaseBlock>;
|
|
69
|
-
private readonly _outputBlock: OutputBlock;
|
|
70
|
-
|
|
71
74
|
/**
|
|
72
75
|
* Creates a new instance of a @see SmartFilter.
|
|
73
76
|
* @param name - The friendly name of the smart filter
|
|
@@ -76,8 +79,8 @@ export class SmartFilter {
|
|
|
76
79
|
this.name = name;
|
|
77
80
|
|
|
78
81
|
this._attachedBlocks = new Array<BaseBlock>();
|
|
79
|
-
this.
|
|
80
|
-
this.output = this.
|
|
82
|
+
this.outputBlock = new OutputBlock(this);
|
|
83
|
+
this.output = this.outputBlock.input;
|
|
81
84
|
}
|
|
82
85
|
|
|
83
86
|
/**
|
|
@@ -136,7 +139,7 @@ export class SmartFilter {
|
|
|
136
139
|
}
|
|
137
140
|
|
|
138
141
|
private _generateCommandsAndGatherInitPromises(initializationData: InitializationData): void {
|
|
139
|
-
const outputBlock = this.
|
|
142
|
+
const outputBlock = this.outputBlock;
|
|
140
143
|
|
|
141
144
|
outputBlock.visit(initializationData, (block: BaseBlock, initializationData: InitializationData) => {
|
|
142
145
|
// If the block is the output block,
|
|
@@ -173,17 +176,17 @@ export class SmartFilter {
|
|
|
173
176
|
|
|
174
177
|
const initializationData: InitializationData = {
|
|
175
178
|
runtime,
|
|
176
|
-
outputBlock: this.
|
|
179
|
+
outputBlock: this.outputBlock,
|
|
177
180
|
initializationPromises: [],
|
|
178
181
|
};
|
|
179
182
|
|
|
180
183
|
this._workWithAggregateFreeGraph(() => {
|
|
181
|
-
this.
|
|
184
|
+
this.outputBlock.prepareForRuntime();
|
|
182
185
|
|
|
183
186
|
renderTargetGenerator = renderTargetGenerator ?? new RenderTargetGenerator(false);
|
|
184
187
|
renderTargetGenerator.setOutputTextures(this, initializationData);
|
|
185
188
|
|
|
186
|
-
this.
|
|
189
|
+
this.outputBlock.propagateRuntimeData();
|
|
187
190
|
|
|
188
191
|
this._generateCommandsAndGatherInitPromises(initializationData);
|
|
189
192
|
});
|
|
@@ -210,7 +213,7 @@ export class SmartFilter {
|
|
|
210
213
|
const mergedAggregateBlocks: AggregateBlock[] = [];
|
|
211
214
|
|
|
212
215
|
// Merge all aggregate blocks
|
|
213
|
-
this.
|
|
216
|
+
this.outputBlock.visit({}, (block: BaseBlock, _extraData: Object) => {
|
|
214
217
|
if (block instanceof AggregateBlock) {
|
|
215
218
|
block._mergeIntoSmartFilter(mergedAggregateBlocks);
|
|
216
219
|
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Builds all .glsl files under <shaderPath>.
|
|
3
|
+
* @param shaderPath - The path to the shaders to watch
|
|
4
|
+
* @param importPath - The path to import the converted shaders
|
|
5
|
+
* @example node buildShaders.js <shaderPath> <importPath>
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { convertShaders } from "./shaderConverter.js";
|
|
9
|
+
|
|
10
|
+
const externalArguments = process.argv.slice(2);
|
|
11
|
+
if (externalArguments.length >= 2 && externalArguments[0] && externalArguments[1]) {
|
|
12
|
+
convertShaders(externalArguments[0], externalArguments[1]);
|
|
13
|
+
}
|
|
@@ -63,7 +63,7 @@ const GetFunctionNamesRegEx = /\S*\w+\s+(\w+)\s*\(/g;
|
|
|
63
63
|
* @param fragmentShaderPath - The path to the fragment file for the shader
|
|
64
64
|
* @param importPath - The path to import the ShaderProgram type from
|
|
65
65
|
*/
|
|
66
|
-
function convertShader(fragmentShaderPath: string, importPath: string): void {
|
|
66
|
+
export function convertShader(fragmentShaderPath: string, importPath: string): void {
|
|
67
67
|
console.log(`Processing fragment shader: ${fragmentShaderPath}`);
|
|
68
68
|
|
|
69
69
|
// See if there is a corresponding vertex shader
|
|
@@ -182,8 +182,8 @@ function processFragmentShaderV1(fragmentShader: string): FragmentShaderInfo {
|
|
|
182
182
|
const symbolsToDecorate = [...uniforms, ...consts, ...functionNames];
|
|
183
183
|
let fragmentShaderWithRenamedSymbols = fragmentShader;
|
|
184
184
|
for (const symbol of symbolsToDecorate) {
|
|
185
|
-
const regex = new RegExp(`(
|
|
186
|
-
fragmentShaderWithRenamedSymbols = fragmentShaderWithRenamedSymbols.replace(regex,
|
|
185
|
+
const regex = new RegExp(`(?<=\\W+)${symbol}(?=\\W+)`, "gs");
|
|
186
|
+
fragmentShaderWithRenamedSymbols = fragmentShaderWithRenamedSymbols.replace(regex, `_${symbol}_`);
|
|
187
187
|
}
|
|
188
188
|
console.log(`${symbolsToDecorate.length} symbol(s) renamed`);
|
|
189
189
|
const uniformNames = uniforms.map((uniform) => `${uniform}: "${uniform}",`);
|
|
@@ -376,7 +376,7 @@ function removeFunctionBodies(input: string): string {
|
|
|
376
376
|
* @param shaderPath - The path to the .glsl files to convert.
|
|
377
377
|
* @param importPath - The path to import the ShaderProgram type from.
|
|
378
378
|
*/
|
|
379
|
-
function convertShaders(shaderPath: string, importPath: string) {
|
|
379
|
+
export function convertShaders(shaderPath: string, importPath: string) {
|
|
380
380
|
// Get all files in the path
|
|
381
381
|
const allFiles = fs.readdirSync(shaderPath, { withFileTypes: true, recursive: true });
|
|
382
382
|
|
|
@@ -391,9 +391,4 @@ function convertShaders(shaderPath: string, importPath: string) {
|
|
|
391
391
|
}
|
|
392
392
|
}
|
|
393
393
|
|
|
394
|
-
const externalArguments = process.argv.slice(2);
|
|
395
|
-
if (externalArguments.length >= 2 && externalArguments[0] && externalArguments[1]) {
|
|
396
|
-
convertShaders(externalArguments[0], externalArguments[1]);
|
|
397
|
-
}
|
|
398
|
-
|
|
399
394
|
// TODO: simple copy from shader file to .ts, get it to build (including import trick)
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/* eslint-disable no-console */
|
|
2
|
+
/**
|
|
3
|
+
* Watches all .glsl files under <shaderPath> and rebuilds them when changed.
|
|
4
|
+
* @param shaderPath - The path to the shaders to watch
|
|
5
|
+
* @param importPath - The path to import the converted shaders
|
|
6
|
+
* @example node watchShaders.js <shaderPath> <importPath>
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import { convertShader } from "./shaderConverter.js";
|
|
10
|
+
import { watch } from "chokidar";
|
|
11
|
+
import { extname } from "path";
|
|
12
|
+
|
|
13
|
+
const externalArguments = process.argv.slice(2);
|
|
14
|
+
if (externalArguments.length >= 2 && externalArguments[0] && externalArguments[1]) {
|
|
15
|
+
const shaderPath = externalArguments[0];
|
|
16
|
+
const importPath = externalArguments[1];
|
|
17
|
+
|
|
18
|
+
watch(shaderPath).on("all", (event, file) => {
|
|
19
|
+
// Only process file changes and added files
|
|
20
|
+
if (event !== "change" && event !== "add") {
|
|
21
|
+
return;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
// Only process .glsl files
|
|
25
|
+
if (extname(file) !== ".glsl") {
|
|
26
|
+
return;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
// Wrap in try-catch to prevent the watcher from crashing
|
|
30
|
+
// if the new shader changes are invalid
|
|
31
|
+
try {
|
|
32
|
+
convertShader(file, importPath);
|
|
33
|
+
console.log(`Successfully updated shader ${file}`);
|
|
34
|
+
} catch (error) {
|
|
35
|
+
console.error(`Failed to convert shader ${file}: ${error}`);
|
|
36
|
+
}
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
console.log(`Watching for shader changes in ${shaderPath}`);
|
|
40
|
+
}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import type { RenderTargetWrapper } from "@babylonjs/core/Engines/renderTargetWrapper";
|
|
2
|
+
import type { ThinRenderTargetTexture } from "@babylonjs/core/Materials/Textures/thinRenderTargetTexture";
|
|
3
|
+
import type { Nullable } from "@babylonjs/core/types";
|
|
4
|
+
import { createCommand } from "../command/command.js";
|
|
5
|
+
import type { BaseBlock } from "../blocks/baseBlock";
|
|
6
|
+
import type { ShaderRuntime } from "../runtime/shaderRuntime";
|
|
7
|
+
import type { InternalSmartFilterRuntime } from "../runtime/smartFilterRuntime";
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Tries to get a renderTarget from a renderTargetTexture, throws an error if it fails.
|
|
11
|
+
* @param renderTargetTexture - The renderTargetTexture to get the renderTarget from.
|
|
12
|
+
* @param callerName - The name of the component calling this one, used for a more descriptive error message.
|
|
13
|
+
* @returns - The renderTarget or throws an Error if it fails.
|
|
14
|
+
*/
|
|
15
|
+
export function getRenderTarget(
|
|
16
|
+
renderTargetTexture: Nullable<ThinRenderTargetTexture>,
|
|
17
|
+
callerName: string
|
|
18
|
+
): RenderTargetWrapper {
|
|
19
|
+
const renderTarget = renderTargetTexture?.renderTarget;
|
|
20
|
+
if (!renderTarget) {
|
|
21
|
+
throw new Error(`${callerName} could not get a renderTarget it needed.`);
|
|
22
|
+
}
|
|
23
|
+
return renderTarget;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Registers the final command of the command queue - the one that draws to either the canvas or
|
|
28
|
+
* renderTargetTexture.
|
|
29
|
+
* @param renderTargetTexture - If non-null, the render target texture to render to, otherwise the command will
|
|
30
|
+
* render to the canvas.
|
|
31
|
+
* @param runtime - The smart filter runtime to use.
|
|
32
|
+
* @param commandOwner - The owner of the command.
|
|
33
|
+
* @param shaderBlockRuntime - The shader block runtime to use.
|
|
34
|
+
*/
|
|
35
|
+
export function registerFinalRenderCommand(
|
|
36
|
+
renderTargetTexture: Nullable<ThinRenderTargetTexture>,
|
|
37
|
+
runtime: InternalSmartFilterRuntime,
|
|
38
|
+
commandOwner: BaseBlock,
|
|
39
|
+
shaderBlockRuntime: ShaderRuntime
|
|
40
|
+
): void {
|
|
41
|
+
const commandOwnerClassName = commandOwner.getClassName();
|
|
42
|
+
if (renderTargetTexture) {
|
|
43
|
+
const renderTarget = getRenderTarget(renderTargetTexture, commandOwnerClassName);
|
|
44
|
+
runtime.registerCommand(
|
|
45
|
+
createCommand(`${commandOwnerClassName}.renderToFinalTexture`, commandOwner, () => {
|
|
46
|
+
shaderBlockRuntime.renderToTexture(renderTarget);
|
|
47
|
+
})
|
|
48
|
+
);
|
|
49
|
+
} else {
|
|
50
|
+
runtime.registerCommand(
|
|
51
|
+
createCommand(`${commandOwnerClassName}.renderToCanvas`, commandOwner, () => {
|
|
52
|
+
shaderBlockRuntime.renderToCanvas();
|
|
53
|
+
})
|
|
54
|
+
);
|
|
55
|
+
}
|
|
56
|
+
}
|