Shaders with Typescript and React three fiber
Asked Answered
S

3

5

I'm trying to use shaders with React-three-fiber and Typescript. Shader file:

import { ShaderMaterial } from "three"
import { extend } from "react-three-fiber"

class CustomMaterial extends ShaderMaterial {
  constructor() {
    super({
      vertexShader: `...`,
      fragmentShader: `...`,
      uniforms: [...]
    })
  }
}

extend({ CustomMaterial })

and the component file:

<mesh
  key={el.name}
  material={el.material}
  receiveShadow
  castShadow
>
  <bufferGeometry attach="geometry" {...el.geometry} />
  <customMaterial attach="material" />
</mesh>

I'm getting error:

Property 'customMaterial' does not exist on type 'JSX.IntrinsicElements'.

Schuler answered 26/12, 2020 at 17:42 Comment(0)
D
7

Try:

declare global {
  namespace JSX {
    interface IntrinsicElements {
      customMaterial: ReactThreeFiber.Object3DNode<CustomMaterial, typeof CustomMaterial>
    }
  }
}

You might also need to stick in the following in your imports:

import { extend } from 'react-three-fiber'
...
extend ({ CustomMaterial })
Disport answered 27/12, 2020 at 5:0 Comment(2)
sorry for digging up an old thread, but im stuck on this same issue.. Where do I put this declare global ?Dram
Can you give an example ?Corum
C
0

Would just like to add that if you're trying to add something other than a custom material, you can use ReactThreeFiber.Object3DNode.

I was trying to get OrbitControls to work, and managed to do it with the following method:

import { extend } from '@react-three/fiber';
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls';

declare global {
    namespace JSX {
        interface Intrinsicelements {
            orbitControls: ReactThreeFiber.Node<OrbitControls, typeof OrbitControls>;
        }
    }
}

extend({ OrbitControls });
Cheri answered 15/1, 2022 at 22:18 Comment(0)
C
0

If you need to use a custom effect you're best off using the pmnd library for React Three Post Processing - https://github.com/pmndrs/react-postprocessing

You can extend their effect class for custom effects

This is from their docs:

import React, { forwardRef, useMemo } from 'react'
import { Uniform } from 'three'
import { Effect } from 'postprocessing'

const fragmentShader = `some_shader_code`

let _uParam

// Effect implementation
class MyCustomEffectImpl extends Effect {
  constructor({ param = 0.1 } = {}) {
    super('MyCustomEffect', fragmentShader, {
      uniforms: new Map([['param', new Uniform(param)]]),
    })

    _uParam = param
  }

  update(renderer, inputBuffer, deltaTime) {
    this.uniforms.get('param').value = _uParam
  }
}

// Effect component
export const MyCustomEffect = forwardRef(({ param }, ref) => {
  const effect = useMemo(() => new MyCustomEffectImpl(param), [param])
  return <primitive ref={ref} object={effect} dispose={null} />
})

hope this helps!!

Compensatory answered 9/10 at 8:34 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.