2

Having issues loading glsl shaders in a Next.js project. More specifically, when attempting to load the glslify function 'snoise3', I am prompted with the following error message:

WARNING: 0:64: 'glslify' : unrecognized pragma ERROR: 0:73: 'snoise3' : no matching overloaded function found

I've seem similar issues around the internet but can't seem to track a solution that works in my project.

Here's the CodeSandbox I am modeling off of: https://codesandbox.io/s/r3f-wavey-image-shader-j4uwl?file=/src/App.js

For reference, here's my three.js object code (including glsl code):

import * as THREE from "three";
import React, { useRef, Suspense } from "react";
import { Canvas, extend, useFrame, useLoader } from "@react-three/fiber";
import { shaderMaterial } from "@react-three/drei";

const glslify = require("glslify");

const WaveShaderMaterial = shaderMaterial(
  // Uniform
  {
    uTime: 0,
    uColor: new THREE.Color(0.0, 0.0, 0.0),
    uTexture: new THREE.Texture(),
  },
  // Vertex Shader
  glslify`precision mediump float;
 
  varying vec2 vUv;
  varying float vWave;

  uniform float uTime;

  #pragma glslify: snoise3 = require(glsl-noise/simplex/3d.glsl);

  void main() {
    vUv = uv;

    vec3 pos = position;
    float noiseFreq = 2.0;
    float noiseAmp = 0.4;
    vec3 noisePos = vec3(pos.x * noiseFreq + uTime, pos.y, pos.z);
    pos.z += snoise3(noisePos) * noiseAmp;
    vWave = pos.z;

    gl_Position = projectionMatrix * modelViewMatrix * vec4(pos, 1.0);  
  }`,
  // Fragment Shader
  glslify`precision mediump float;

  uniform vec3 uColor;
  uniform float uTime;
  uniform sampler2D uTexture;

  varying vec2 vUv;
  varying float vWave;

  void main() {
    float wave = vWave * 0.2;
    vec3 texture = texture2D(uTexture, vUv + wave).rgb;
    gl_FragColor = vec4(texture, 1.0); 
  }`
);

extend({ WaveShaderMaterial });

const Wave = () => {
  const ref = useRef();
  useFrame(({ clock }) => (ref.current.uTime = clock.getElapsedTime()));

  const [image] = useLoader(THREE.TextureLoader, [
    "https://i.imgur.com/Fc5Rwr6.png",
  ]);

  return (
    <mesh>
      <planeBufferGeometry args={[0.5, 0.5, 16, 16]} />
      <waveShaderMaterial
        wireframe
        uColor={"orange"}
        ref={ref}
        uTexture={image}
        GLSLVersion={THREE.GLSL3}
      />
    </mesh>
  );
};

const GridWaveObject = () => {
  return (
    <Canvas camera={{ fov: 12, position: [1, 3, 5] }}>
      <Suspense fallback={null}>
        <Wave />
      </Suspense>
    </Canvas>
  );
};

export default GridWaveObject;

and also my next.config.js:

/** @type {import('next').NextConfig} */
const webpack = require("webpack");

const nextConfig = {
  reactStrictMode: true,
  webpack(config) {
    // Perform customizations to webpack config
    config.module.rules.push({
      // shader import support
      test: /\.glsl$/,
      use: [
        {
          loader: "ify-loader",
          options: {
            name: "dist/[path][name].[ext]",
          },
        },
        "webpack-glsl-loader",
      ],
    });

    return config;
  },
};

module.exports = nextConfig;

I originally tried just using the babel configuration, but this failed pretty quick because I'm using next/font. I've also tried using all different types of loaders (glsl-loader, ify-loader, webpack-glsl-loader, and more), extracting the glsl code to their own files and importing, as well as all different types of next configs. I'm stumped here as I believe I've tried everything I can.

If anyone has experience using shaders with @react-three/fiber or @react-three/drei with Next.js, I'd appreciate any solution that can help me move forward :)

John Smith
  • 21
  • 5

0 Answers0