Here's an example based on the second live example from https://threejsfundamentals.org/threejs/lessons/threejs-shadertoy.html:
html, body {
height: 100%;
margin: 0;
}
#c {
width: 100%;
height: 100%;
display: block;
}
<canvas id="c"></canvas>
<script type="module">
// Three.js - Shadertoy Basic
// from https://threejsfundamentals.org/threejs/threejs-shadertoy-basic.html
import * as THREE from 'https://unpkg.com/three@0.122.0/build/three.module.js';
function main() {
const canvas = document.querySelector('#c');
const renderer = new THREE.WebGLRenderer({canvas});
renderer.autoClearColor = false;
const camera = new THREE.PerspectiveCamera(
45, 16/9, 0.01, 1000
);
camera.position.z = 5
const scene = new THREE.Scene();
const plane = new THREE.PlaneBufferGeometry(2, 2);
const fragmentShader = `
#include <common>
uniform vec3 iResolution;
uniform float iTime;
// https://www.shadertoy.com/view/MtXSWj
float alternate(float p, float d){;
return sign(fract(p*d*.5)*2.-1.);
}
vec3 rainbow(float t){
return sin(t+vec3(0,.33,.66)*6.28)*.5+.5;
}
vec3 TwinDragon(vec2 p){
float time = fract(iTime*0.05)*20.;
//scaling
p = (p*2.-iResolution.xy)/iResolution.y*1.5;
//----------the fractal stuff---- ---THIS IS ANIMATIONS----(so remove them if you want)
p.y += alternate(p.x, 256. )/512. * clamp(time-16.,0.,2.)/2.;
p.x -= alternate(p.y, 128. )/256. * clamp(time-14.,0.,2.)/2.;
p.y += alternate(p.x, 64. )/128. * clamp(time-12.,0.,2.)/2.;
p.x -= alternate(p.y, 32. )/ 64. * clamp(time-10.,0.,2.)/2.;
p.y += alternate(p.x, 16. )/ 32. * clamp(time- 8.,0.,2.)/2.;
p.x -= alternate(p.y, 8. )/ 16. * clamp(time- 6.,0.,2.)/2.;
p.y += alternate(p.x, 4. )/ 8. * clamp(time- 4.,0.,2.)/2.;
p.x -= alternate(p.y, 2. )/ 4. * clamp(time- 2.,0.,2.)/2.;
// prettifying
vec2 block = ceil(p+.5); //index for blocks from which the fractal is shifted
vec3 color = rainbow(block.x*4.+block.y); //rainbow palette using block index as t
float dis = length(fract(p+.5)*2.-1.);//distance to middle of block
color *= .5+dis*.7; //using distance within block for some more pretty.
return color;
}
void mainImage( out vec4 fragColor, in vec2 fragCoord ){
vec2 d = vec2(.5,0);
//some antialiasing
vec3 col = (
TwinDragon(fragCoord+d.xy)+
TwinDragon(fragCoord-d.xy)+
TwinDragon(fragCoord+d.yx)+
TwinDragon(fragCoord-d.yx)
)*.25;
fragColor = vec4(col,1.);
}
void main() {
mainImage(gl_FragColor, gl_FragCoord.xy);
}
`;
const uniforms = {
iTime: { value: 0 },
iResolution: { value: new THREE.Vector3() },
};
const material = new THREE.ShaderMaterial({
fragmentShader,
uniforms,
side: THREE.DoubleSide
});
const mesh = new THREE.Mesh(plane, material)
scene.add(mesh);
function resizeRendererToDisplaySize(renderer) {
const canvas = renderer.domElement;
const width = canvas.clientWidth;
const height = canvas.clientHeight;
const needResize = canvas.width !== width || canvas.height !== height;
if (needResize) {
renderer.setSize(width, height, false);
}
return needResize;
}
function render(time) {
time *= 0.001; // convert to seconds
resizeRendererToDisplaySize(renderer);
const canvas = renderer.domElement;
uniforms.iResolution.value.set(canvas.width, canvas.height, 1);
uniforms.iTime.value = time;
mesh.rotation.y += 0.01
renderer.render(scene, camera);
requestAnimationFrame(render);
}
requestAnimationFrame(render);
}
main();
</script>
But as you see, when I change to PerspectiveCamera, and rotate the plane, the texture does not transform with the object.
What's the simplest way to modify the example to make the shader transform with the plane, so that the graphic appears to be on the surface of the plane instead of the plane appearing to be like a mask?