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 :)