Shadertoy to Three.js ShaderMaterial
Shadertoy's mainImage is not a GLSL entry point. After moving it into Three.js, add main and update iTime and iResolution from JavaScript. First verify a full-screen plane, then change the coordinate source for a model. This separates entry-point failures from UV mistakes.
Fix the problem and environment
Shadertoy's mainImage is not a GLSL entry point. After moving it into Three.js, add main and update iTime and iResolution from JavaScript. First verify a full-screen plane, then change the coordinate source for a model. This separates entry-point failures from UV mistakes.
The module below is for a browser project with three installed. It uses an original sine-color example rather than a third-party artwork. The drawing-buffer size includes pixel ratio; iResolution must describe that same buffer rather than the CSS size.
The controlling code
import * as THREE from 'three';
const renderer = new THREE.WebGLRenderer();
document.body.append(renderer.domElement);
const scene = new THREE.Scene();
const camera = new THREE.OrthographicCamera(-1, 1, 1, -1, 0, 1);
const uniforms = { iTime: { value: 0 }, iResolution: { value: new THREE.Vector3(1, 1, 1) } };
const material = new THREE.ShaderMaterial({
uniforms,
vertexShader: `void main(){gl_Position=vec4(position.xy,0.0,1.0);}`,
fragmentShader: `precision highp float;
uniform float iTime; uniform vec3 iResolution;
void mainImage(out vec4 color, in vec2 fragCoord){
vec2 uv=fragCoord/iResolution.xy;
color=vec4(0.5+0.5*sin(iTime+uv.xyx*6.0),1.0);
}
void main(){mainImage(gl_FragColor,gl_FragCoord.xy);}`
});
const mesh = new THREE.Mesh(new THREE.PlaneGeometry(2, 2), material);
scene.add(mesh);
function resize(){
renderer.setPixelRatio(Math.min(window.devicePixelRatio,2));
renderer.setSize(window.innerWidth,window.innerHeight);
const size=renderer.getDrawingBufferSize(new THREE.Vector2());
uniforms.iResolution.value.set(size.x,size.y,1);
}
window.addEventListener('resize',resize);resize();
renderer.setAnimationLoop(ms=>{uniforms.iTime.value=ms*0.001;renderer.render(scene,camera);});
// On teardown: stop the loop, remove resize, dispose geometry/material/renderer.
Verify in order
Verify animated full-screen color first. Then pass vUv=uv from the vertex shader and call mainImage with vUv*iResolution.xy. For a mesh, use a perspective camera and the normal projection/model-view transform. The full-screen gl_Position deliberately ignores model transforms and must not be reused unchanged.
Scope and common mistakes
A shader using Buffer A/B, cube maps or special textures needs all those resources. Copying only the Image pass is incomplete; check the artwork license before reusing its source.