Skip to content

Issues and missing features on node type generics #2116

@shotamatsuda

Description

@shotamatsuda

The addition of node type generics in r183 is great. But it seems to have many breakages and need refinements, which appear to be already planned in #2049.

The purpose of this issue is to list the concrete issues and feature requests that are blocking me from migrating an existing codebase to r183 types as an example. I could work on most of them, but 2 and 3 would need your assistance because the underlying issues seem to be much broader.

  1. Chained methods on Node<unknown>

Basic chained methods like toConst(), toVar(), context() and swizzling are absent unless the node has a type other than unknown. This leads to many type breakages.

This is understandable, but given that most advanced nodes (e.g. compute nodes and those in the addon) don't have definite types right now, it would be more reasonable to include these methods on Node<unknown>.

  1. Function types on vectors

Most math functions should work with vectors component-wise, as well as integer types, but their types only accept float.

pow(vec3(), 1.5) // expected: Node<'vec3'>
sqrt(vec3()) // expected: Node<'vec3'>
fwidth(vec3()) // expected: Node<'vec3'>
greaterThan(vec3(), 0) // expected: Node<'bvec3'>
int(0).negate() // expected: Node<'int'>
ivec2().sign() // expected: Node<'ivec2'>
  1. Coerced types on arithmetic operations

Arithmetic operations like vec2 * ivec2 and ivec2 * vec2 are allowed at the TSL level, and their types are coerced to vec2 * vec2(ivec2) -> vec2 and ivec2 * ivec2(vec2) -> ivec2 respectively, but these are not supported in the current types and result in type errors instead.

vec2().mul(ivec2()) // expected: Node<'vec2'>
ivec2().mul(vec2()) // expected: Node<'ivec2'>
  1. Member types on StructNode

StructNode.get() always returns Node, so arithmetic operations require type casting.

It would be ideal to add generics to StructNode and resolve member types accordingly.

const S = struct({
  a: 'vec3',
  b: 'float'
})
const s = S(vec3(), float())
const a = s.get('a') // expected: Node<'vec3'>, actual: Node
const b = s.get('b') // expected: Node<'float'>, actual: Node
  1. ivecN, uvecN, bvecN functions with VectorN instances

ivecN, uvecN, and bvecN functions should also accept VectorN instances, just like vecN functions do.

ivec2(new Vector2()) // expected: Node<'ivec2'>
  1. Generics on compute nodes

Types for most compute shader nodes are missing. This would be largely alleviated if 1 is addressed.

globalId.xy // expected: Node<'ivec2'>

declare const storage: StorageBufferNode<'int'>
atomicAdd(storage.element(0), 1) // expected: Node<'int'>
  1. Refinement on UniformNode inference

UniformNode now takes two type parameters, but the second one can be trivially inferred from the first.

const node: UniformNode<'vec3'> // UniformNode<'vec3', Vector3>
  1. Array functions with struct

Array functions like instancedArray and attributeArray can take StructTypeNode. But this would require reworking the type of StorageBufferNode, especially if we will support generics on StructNode mentioned in 4.

const S = struct({ ... })
instancedArray(1, S) // expected: StorageBufferNode<StructNode>
  1. TextureNode with DepthTexture always samples float

A quick workaround would be to overload PassNode.getTextureNode('depth') to return TextureNode<'float'>, because this is the most common way users access such nodes.

const passNode = pass(scene, camera)
const depthNode = passNode.getTextureNode('depth') // expected: TextureNode<'float'>

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions