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'.

3 Answers 3

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 })
Sign up to request clarification or add additional context in comments.

2 Comments

sorry for digging up an old thread, but im stuck on this same issue.. Where do I put this declare global ?
Can you give an example ?
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 });

Comments

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!!

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.