Skip to content

Commit

Permalink
Merge branch 'webgpu'
Browse files Browse the repository at this point in the history
# Conflicts:
#	src/nodes/NodeVFX.ts
  • Loading branch information
Alchemist0823 committed Apr 30, 2024
2 parents 148a1d6 + 8699616 commit e56d6c2
Show file tree
Hide file tree
Showing 15 changed files with 880 additions and 188 deletions.
9 changes: 5 additions & 4 deletions examples/nodeBasedVFXDemo.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import {BatchedParticleRenderer, Node, NodeGraph, NodeTypes, NodeVFX, RenderMode, Wire} from 'three.quarks';
import {Demo} from './demo.js';
import {AdditiveBlending, MeshBasicMaterial, NormalBlending, TextureLoader, Vector3, Vector4} from 'three';
import {NodeValueType} from "./js/three.quarks.esm.js";

export class NodeBasedVFXDemo extends Demo {
name = 'Node Based VFX (Experimental)';
Expand All @@ -25,7 +26,7 @@ export class NodeBasedVFXDemo extends Demo {
emissionGraph.addWire(new Wire(repeater, 0, emit, 0));

const updateGraph = new NodeGraph('test');
const age = new Node(NodeTypes['particleProperty'], 0, {property: 'age'});
const age = new Node(NodeTypes['particleProperty'], 0, {property: 'age', type: NodeValueType.Number});
const time = new Node(NodeTypes['time']);
const add = new Node(NodeTypes['add'], 0);
add.inputs[1] = {getValue: () => 1};
Expand All @@ -38,10 +39,10 @@ export class NodeBasedVFXDemo extends Demo {
pos2.inputs[1] = {getValue: () => 1};
pos2.inputs[2] = {getValue: () => 1};

const life = new Node(NodeTypes['particleProperty'], 0, {property: 'life'});
const life = new Node(NodeTypes['particleProperty'], 0, {property: 'life', type: NodeValueType.Number});
life.inputs[0] = {getValue: () => 5};
const ppos = new Node(NodeTypes['particleProperty'], 0, {property: 'position'});
const pvel = new Node(NodeTypes['particleProperty'], 0, {property: 'velocity'});
const ppos = new Node(NodeTypes['particleProperty'], 0, {property: 'position', type: NodeValueType.Vec3});
const pvel = new Node(NodeTypes['particleProperty'], 0, {property: 'velocity', type: NodeValueType.Vec3});

updateGraph.addNode(age);
updateGraph.addNode(time);
Expand Down
2 changes: 1 addition & 1 deletion src/behaviors/NodeGraphBehavior.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import {Behavior} from "./Behavior";
import {Particle} from "../Particle";
import { NodeGraph } from "../nodes/NodeGraph";
import {Interpreter} from "../nodes/Interpreter";
import {ExecutionContext} from "../nodes/NodeType";
import {ExecutionContext} from "../nodes/NodeDef";

export class NodeGraphBehavior implements Behavior {

Expand Down
50 changes: 36 additions & 14 deletions src/nodes/BaseCompiler.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import {NodeGraph} from './NodeGraph';
import {ConstInput, Node, Wire} from './Node';
import {ExecutionContext} from './NodeType';
import {Adapter, ConstInput, Node, Wire} from './Node';
import {ExecutionContext} from './NodeDef';

export abstract class BaseCompiler {
static Instance: BaseCompiler;
Expand All @@ -10,6 +10,7 @@ export abstract class BaseCompiler {
}

visited: Set<string> = new Set<string>();
debug: boolean = false;

protected buildExecutionOrder(graph: NodeGraph, context: ExecutionContext): void {
graph.nodesInOrder.length = 0;
Expand All @@ -22,24 +23,43 @@ export abstract class BaseCompiler {
}
graph.compiled = true;
}

private _traverseWire(wire: Wire, graph: NodeGraph, context: ExecutionContext) {

}

private _traverse(node: Node, graph: NodeGraph, context: ExecutionContext) {
this.visited.add(node.id);
const inputValues = [];
for (let i = 0; i < node.inputs.length; i++) {
if (node.inputs[i] instanceof Wire) {
const inputNode = (node.inputs[i] as Wire).input;
//if (inputNode) {
if (!this.visited.has(inputNode.id)) {
this._traverse(inputNode, graph, context);
const input = (node.inputs[i] as Wire).input;
//if (input) {
if (input instanceof Node) {
if (!this.visited.has(input.id)) {
this._traverse(input, graph, context);
}
} else if (input instanceof Adapter) {
if (!input.isInput) {
this._traverse(input.node, graph, context);
}
}
} else if (node.inputs[i] instanceof Adapter) {
const input = node.inputs[i] as Adapter;
for (let j = 0; j < input.inputs.length; j++) {
const wireOrNot = input.inputs[j];
if (wireOrNot !== undefined) {
if (wireOrNot.input instanceof Node) {
if (!this.visited.has(wireOrNot.input.id)) {
this._traverse(wireOrNot.input, graph, context);
}
} else {
if (!this.visited.has(wireOrNot.input.node.id)) {
this._traverse(wireOrNot.input.node, graph, context);
}
}
}
}
//inputValues.push(inputNode.outputValues[(node.inputs[i] as Wire).inputIndex]);
/*} else {
throw new Error(`Node ${node.id} has not inputs`);
}*/
} else if (node.inputs[i] !== undefined) {
//inputValues.push((node.inputs[i] as ConstInput).getValue(context));
} else {
//inputValues.push(undefined);
}
}
// calculation
Expand All @@ -48,4 +68,6 @@ export abstract class BaseCompiler {
}

abstract run(graph: NodeGraph, context: ExecutionContext): void;

abstract build(graph: NodeGraph, context: ExecutionContext): string;
}
38 changes: 33 additions & 5 deletions src/nodes/Interpreter.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
import {NodeGraph} from './NodeGraph';
import {ConstInput, Node, Wire} from './Node';
import {ExecutionContext} from './NodeType';
import { BaseCompiler } from "./BaseCompiler";
import {Adapter, ConstInput, Node, Wire} from './Node';
import {ExecutionContext} from './NodeDef';
import {BaseCompiler} from './BaseCompiler';
import {context} from 'three/examples/jsm/nodes/shadernode/ShaderNodeBaseElements';
import {genDefaultForNodeValueType} from './NodeValueType';

export class Interpreter extends BaseCompiler {

constructor() {
super();
}
Expand Down Expand Up @@ -36,15 +37,38 @@ export class Interpreter extends BaseCompiler {
for (let i = 0; i < nodes.length; i++) {
const inputValues = [];
const node = nodes[i];
if (this.debug) {
console.log('Node:', node);
}
for (let j = 0; j < node.inputs.length; j++) {
if (node.inputs[j] instanceof Wire) {
inputValues.push((node.inputs[j] as Wire).input.outputValues[(node.inputs[j] as Wire).inputIndex]);
if ((node.inputs[j] as Wire).input instanceof Node) {
inputValues.push(
((node.inputs[j] as Wire).input as Node).outputValues[(node.inputs[j] as Wire).inputIndex]
);
} // TODO: handle adapter
} else if (node.inputs[j] instanceof Adapter) {
// TODO: handle adapter
//inputValues.push((node.inputs[j] as Adapter).input.outputValues[(node.inputs[j] as Wire).inputIndex]);
} else if (node.inputs[j] !== undefined) {
inputValues.push((node.inputs[j] as ConstInput).getValue(context));
} else {
inputValues.push(undefined);
}
}
if (node.outputValues.length === 0) {
const signatureIndex = node.signatureIndex < 0 ? 0 : node.signatureIndex;
for (let i = 0; i < node.definition.nodeTypeSignatures[signatureIndex].outputTypes.length; i++) {
node.outputValues.push(
genDefaultForNodeValueType(
node.definition.nodeTypeSignatures[signatureIndex].outputTypes[i]
)
);
if (node.outputValues[i] === undefined) {
node.outputValues[i] = genDefaultForNodeValueType(node.data.type);
}
}
}
node.func(context, inputValues, node.outputValues);
}
}
Expand All @@ -55,4 +79,8 @@ export class Interpreter extends BaseCompiler {
}
this.executeCompiledGraph(graph, context);
}

build(graph: NodeGraph, context: ExecutionContext): string {
return '';
}
}
81 changes: 67 additions & 14 deletions src/nodes/Node.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
import {Vector2} from 'three';
import {genDefaultForNodeValueType, NodeValueType} from './NodeValueType';
import {ExecutionContext, NodeType} from './NodeType';
import {ExecutionContext, NodeDef} from './NodeDef';

export type NodeData = {[key: string]: any};
export class Node {
id: string;
inputs: (Wire | ConstInput | undefined)[] = [];
inputs: (Wire | ConstInput | Adapter | undefined)[] = [];
outputs: Wire[][] = [];
type: NodeType;
definition: NodeDef;
signatureIndex: number = -1;
data: NodeData;

Expand All @@ -17,34 +17,33 @@ export class Node {
// execution
outputValues: any[] = [];

constructor(type: NodeType, signatureIndex: number = -1, data: NodeData = {}) {
constructor(definition: NodeDef, signatureIndex: number = -1, data: NodeData = {}) {
this.id = '' + Math.round(Math.random() * 100000); //TODO use real random
this.type = type;
this.definition = definition;
this.signatureIndex = signatureIndex;
this.data = data;
const realIndex = signatureIndex === -1 ? 0 : signatureIndex;
for (let i = 0; i < type.nodeTypeSignatures[realIndex].inputTypes.length; i++) {
for (let i = 0; i < definition.nodeTypeSignatures[realIndex].inputTypes.length; i++) {
this.inputs.push(undefined);
}
for (let i = 0; i < type.nodeTypeSignatures[realIndex].outputTypes.length; i++) {
for (let i = 0; i < definition.nodeTypeSignatures[realIndex].outputTypes.length; i++) {
this.outputs.push([]);
this.outputValues.push(genDefaultForNodeValueType(type.nodeTypeSignatures[realIndex].outputTypes[i]));
}
}

get inputTypes(): NodeValueType[] {
const signatureIndex = this.signatureIndex === -1 ? 0 : this.signatureIndex;
return this.type.nodeTypeSignatures[signatureIndex].inputTypes;
return this.definition.nodeTypeSignatures[signatureIndex].inputTypes;
}

get outputTypes(): NodeValueType[] {
const signatureIndex = this.signatureIndex === -1 ? 0 : this.signatureIndex;
return this.type.nodeTypeSignatures[signatureIndex].outputTypes;
return this.definition.nodeTypeSignatures[signatureIndex].outputTypes;
}

func(context: ExecutionContext, inputs: any[], outputs: any[]) {
const signatureIndex = this.signatureIndex === -1 ? 0 : this.signatureIndex;
this.type.nodeTypeSignatures[signatureIndex].func(context, this.data, inputs, outputs);
this.definition.nodeTypeSignatures[signatureIndex].func(context, this.data, inputs, outputs);
}
}

Expand All @@ -53,12 +52,12 @@ export interface ConstInput {
}

export class Wire {
input: Node;
input: Node | Adapter;
inputIndex: number;
output: Node;
output: Node | Adapter;
outputIndex: number;

constructor(input: Node, inputIndex: number, output: Node, outputIndex: number) {
constructor(input: Node | Adapter, inputIndex: number, output: Node | Adapter, outputIndex: number) {
this.input = input;
this.inputIndex = inputIndex;
this.input.outputs[inputIndex].push(this);
Expand All @@ -67,3 +66,57 @@ export class Wire {
this.output.inputs[outputIndex] = this;
}
}

export class Adapter {
node: Node;
isInput: boolean;
paramIndex: number;
type: NodeValueType;
inputs: (Wire | undefined) [];
outputs: Wire [][];

constructor(type: NodeValueType, isInput:boolean, node: Node, paramIndex: number) {
this.type = type;
this.node = node;
this.isInput = isInput;
this.paramIndex = paramIndex;
if (isInput) {
switch (type) {
case NodeValueType.Vec2:
this.inputs = [undefined, undefined];
this.outputs =[];
break;
case NodeValueType.Vec3:
this.inputs = [undefined, undefined, undefined];
this.outputs =[];
break;
case NodeValueType.Vec4:
this.inputs = [undefined, undefined, undefined, undefined];
this.outputs =[];
break;
default:
this.inputs = [undefined];
this.outputs =[];
break;
}
} else {
switch (type) {
case NodeValueType.Vec2:
this.inputs = [];
this.outputs = [[], []];
break;
case NodeValueType.Vec3:
this.inputs = [];
this.outputs = [[], [], []];
break;
case NodeValueType.Vec4:
this.inputs = [];
this.outputs = [[], [], [], []];
break;
default:
this.inputs = [];
this.outputs = [[]];
}
}
}
}
21 changes: 15 additions & 6 deletions src/nodes/NodeType.ts → src/nodes/NodeDef.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,12 +22,21 @@ export interface NodeTypeSignature {
func: NodeExecFunction;
}

export class NodeType {
export enum NodeType {
Variable,
Expression,
Storage,
Function,
}

export class NodeDef {
name: string;
type: NodeType;
nodeTypeSignatures: NodeTypeSignature[] = [];

constructor(name: string) {
constructor(name: string, type: NodeType) {
this.name = name;
this.type = type;
}

addSignature(inputTypes: NodeValueType[], outputTypes: NodeValueType[], func: NodeExecFunction) {
Expand All @@ -39,24 +48,24 @@ export class NodeType {
}
}

export class GraphNodeType extends NodeType {
export class GraphNodeType extends NodeDef {
nodeGraph: NodeGraph;

constructor(nodeGraph: NodeGraph) {
const inputTypes = [];
for (let i = 0; i < nodeGraph.inputNodes.length; i++) {
if (nodeGraph.inputNodes[i].type.name === 'input') {
if (nodeGraph.inputNodes[i].definition.name === 'input') {
inputTypes.push(nodeGraph.inputNodes[i].data.type);
}
}
const outputTypes = [];
for (let i = 0; i < nodeGraph.outputNodes.length; i++) {
if (nodeGraph.outputNodes[i].type.name === 'output') {
if (nodeGraph.outputNodes[i].definition.name === 'output') {
outputTypes.push(nodeGraph.outputNodes[i].data.type);
}
}

super(nodeGraph.name);
super(nodeGraph.name, NodeType.Expression);
this.addSignature(inputTypes, outputTypes, (context: ExecutionContext, data, inputs, outputs) => {
context.inputs = inputs;
context.outputs = outputs;
Expand Down
Loading

0 comments on commit e56d6c2

Please sign in to comment.