skip to Main Content

I started to use ThreeJS a few months ago and that lead me to webgl.
I watched a bunch of courses on youtube but most of them are oriented to 3d compositions.

So far I got a basic understanding of how this works but I´m still suck at some stuff.

Here is the thing.

I’m trying to understand how to get the data, meaning pixel position and values, from my displacement texture so I can switch the values between my images and make a transition.

I was following this example here but I’m using webpack and three JS and my porpouse here is not to copy but to understand how this works and I think here is missing information or I just can’t understand.

Anyway, I couldn’t find much information about this on the web but as far as I could get is that my images are converted to textures in my code so I should have the values of every pixel of my images and convert those values to UV coordinates and switch the values between my images to get the effect I want.

Here is a link to my repo.

So far I have this.

Here is how I load the images and

import * as THREE from 'three';
import { imgTexture1, imgTexture2, imgTexture3 } from './imgLoaderManager.js';

import vertexShader from './glsl/vertex.glsl';
import fragmentShader from './glsl/fragment.glsl';

//
const texturesArr = [imgTexture1, imgTexture2, imgTexture3];



const planeGeometry = new THREE.PlaneBufferGeometry(3, 3);

const planeMaterial = new THREE.ShaderMaterial({
  vertexShader: vertexShader,
  fragmentShader: fragmentShader,
  side: THREE.DoubleSide,
});
planeMaterial.uniforms.uTime = { value: 0 };
planeMaterial.uniforms.uTexture1 = { value: imgTexture1 };
planeMaterial.uniforms.uTexture2 = { value: imgTexture2 };
planeMaterial.uniforms.uTexture3 = { value: imgTexture3 };
planeMaterial.uniforms.uTexture = {
  value: new THREE.TextureLoader().load(texturesArr),
};

console.log(planeMaterial);
console.log(planeGeometry.attributes);
console.log(imgTexture1);
console.log(imgTexture2);
console.log(imgTexture3);

export const plane = new THREE.Mesh(planeGeometry, planeMaterial);

Here is my Fragment and vertex Code

varying vec2 vUv;
varying vec3 vPosition;
uniform sampler2D uTexture1;
uniform sampler2D uTexture2;
uniform sampler2D uTexture3;

void main() {

    vec3 img1 = texture2D(uTexture1, vUv).xyz;
    vec3 img2 = texture2D(uTexture2, vUv).xyz;
    vec3 img3 = texture2D(uTexture3, vUv).xyz;

    gl_FragColor = vec4(img1 * img2 * img3, 1);
    //gl_FragColor = vec4(vPosition, 1);

}
//////////////////////////////////////////////

varying vec2 vUv;

varying vec3 vPosition;

void main() {
    vPosition = position;
    vUv = uv;

    gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);

}

2

Answers


  1. Chosen as BEST ANSWER

    I found a solution to this. If anyone here is trying to understand how this works.

    void main(){
    
    ///This is the vec4 of the displacement image
    vec4 dispImg = texture2D(uTexture3, vUv.yx);
    
    /// This vec2 is the formula you have to use to capture the values of the 
    ///displacement image to distort the second image.
    ///iProgress is a uniform value between 0 and 10 that you  create in your shader 
    ///material.
    vec2 displacedUv = vec2(vUv.x, vUv.y + iProgress * dispImg.r );
    
    vec4 img1 = texture2D(uTexture1, vUv);
    
    ///Replace the vUv by the displacedUv created
    vec4 img2 = texture2D(uTexture2, displacedUv);
    
    
    gl_FragColor = img2;
    }
    

  2. I don’t really understand what effect you would like to achieve/understand… If it’s the one in the example you provided, you can do it using the mix function and interpolate the values. Instead of colors, you can use your textures.

    You also have coordinates and pixel values ​​printed.

    <script type="importmap">
      {
        "imports": {
          "three": "https://unpkg.com/[email protected]/build/three.module.js",
          "three/addons/": "https://unpkg.com/[email protected]/examples/jsm/"
        }
      }
    </script>
    
    
    <canvas class="webglHH"> </canvas>
    
    <script type="module">
    import * as THREE from "three";
    import GUI from 'https://cdn.jsdelivr.net/npm/[email protected]/+esm';
    const scene = new THREE.Scene();
    
    const sizes = {
      width: window.innerWidth,
      height: window.innerHeight,
    };
    
    const canvas = document.querySelector("canvas.webglHH");
    
    const camera = new THREE.PerspectiveCamera(
      75,
      window.innerWidth / window.innerHeight,
      0.1,
      1000
    );
    camera.position.z = 3;
    
    const renderer = new THREE.WebGLRenderer({
      canvas: canvas,
      antialias: true,
    });
    renderer.setSize(sizes.width, sizes.height);
    renderer.render(scene, camera);
    
    const vertexShader = `
    varying vec2 vUv;
    void main() {
        vUv = uv;
        gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
    }
    `;
    
    const fragmentShader = `
    varying vec2 vUv;
    uniform float iProgress;
    
    void main() {
        vec3 color1 = vec3(0.556, 0.216, 0.757);
        vec3 color2 = vec3(1.0, 0.941, 0.133);
    
        // Interpolate between two colors based on iProgress / or if you want textures.
        vec3 mixedColor = mix(color1, color2, iProgress);
        gl_FragColor = vec4(mixedColor, 1);
    }
    `;
    
    const material = new THREE.ShaderMaterial({
      uniforms: {
        iProgress: { value: 0.0 },
      },
      vertexShader,
      fragmentShader,
    });
    
    const geometry = new THREE.PlaneGeometry(3, 3);
    const plane = new THREE.Mesh(geometry, material);
    scene.add(plane);
    
    const gui = new GUI()
    gui.add(material.uniforms.iProgress, 'value', 0.0, 1.0).name('Progress');
    
    function animate() {
      requestAnimationFrame(animate);
      renderer.render(scene, camera);
    }
    animate();
    canvas.addEventListener('mousemove', (event) => {
      const mouseX = (event.clientX / sizes.width) * 2 - 1;
      const mouseY = -(event.clientY / sizes.height) * 2 + 1;
      const raycaster = new THREE.Raycaster();
      raycaster.setFromCamera({ x: mouseX, y: mouseY }, camera);
      const intersects = raycaster.intersectObject(plane);
      if (intersects.length > 0) {
        const pixelX = Math.floor(intersects[0].uv.x * sizes.width);
        const pixelY = Math.floor((1 - intersects[0].uv.y) * sizes.height);
        console.log(`Pixel Position: (${pixelX}, ${pixelY})`);
        console.log('Color Values:', intersects[0].object.material.uniforms.iProgress.value);
      }
    });
    function resize() {
      sizes.width = window.innerWidth;
      sizes.height = window.innerHeight;
      camera.aspect = sizes.width / sizes.height;
      camera.updateProjectionMatrix();
      renderer.setSize(sizes.width, sizes.height);
    }
    window.addEventListener('resize', resize);
    
    
    </script>
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search