[SOLVED] I want a sliding effect on images loaded as textures when a button is clicked

I have loaded images using TextureLoader() from an array of images using a plane geometry. created two child objects for the original plane geometry for backward and forward clicking events. when right button is clicked next texture image is loaded. I want to have a slider effect when next texture is loading.

    domEvents.addEventListener(mesh11, 'click', function(event) {
                loader.load(arr[textureToShow],
                    function(tex) {
                        console.log("right:" + arr[textureToShow]);
                        textureToShow++;


                        if (textureToShow > arr.length - 1) {
                            textureToShow = 0;
                        }
                        material.map = tex;
                        console.log("after: " + textureToShow);
                        render();

                    });
            }, false)
            domEvents.addEventListener(mesh12, 'click', function(event) {
                loader.load(arr[textureToShow], function(tex) {
                    console.log("left:" + arr[textureToShow]);
                    textureToShow--;


                    if (textureToShow == -1) {
                        textureToShow = 2;
                    }
                    material.map = tex;
                    console.log("after: " + textureToShow);
                    render();
                });
            }, false)

I tried animations but it works on actual mesh but not on textures. Any help is appreciated and also please look at the logic for right and left click, they work but they do not coordinate.

If you can formulate your problem as a JSFiddle that should work, but doesn’t, that will make it much easier for others to help you. Now the question seems very unclear to me.

A geometry has no children. A mesh may have children, though. Are the children also meshes with their own geometries?

What worked on mesh, but not on textures? How did you try?

Note that loader.load(texture_path, function(tex) { /*Do something with the texture.*/}) spawns an asynchronous operation. This means the callback (function(tex)) will not run until after the file is loaded and the execution thread is free.

I’m sorry, I was not clear with the question. Here is the thing. I’m updating my code on codepen, will update the link here.

Actually, it is a mesh on which I’m loading 3 different images as textures. Two child object are created to a mesh. When those buttons are clicked a new texture appears. I want to animate the texture transition with the slider effect.
Thanks again.

1 Like

You will make it easier for yourself by preloading all the textures, or at least the nearest ones. Check out THREE.LoadingManager. You could even make the “previous” and “next” buttons invisible until the required texture is loaded.

How to do the texture transition? I think maybe the easiest will be to create an extra plane that you slide in as the other slides out. Every time you click one of the buttons, the then unused plane is moved to the side you want to slide in from and mapped with the new texture, and then both planes are slided.

For some reason, I’m not able to load my code on codepen.

Here is my code

var camera, scene, renderer, control, orbit, cube;
        var back = false;
        var meshes = new Array();
        var meshl = new Array();
        var meshr = new Array();

        init();
        render();

        function init() {
            console.log("check");
            container = document.createElement('div');
            document.body.appendChild(container);
            renderer = new THREE.WebGLRenderer({
                antialias: true
            });
            renderer.setPixelRatio(window.devicePixelRatio);
            renderer.setSize(window.innerWidth, window.innerHeight);
            renderer.setClearColor(0xf0f0f0);
            container.appendChild(renderer.domElement);

            camera = new THREE.PerspectiveCamera(50, window.innerWidth / window.innerHeight, 1, 3000);
            camera.position.set(100, 100, 500);
            camera.lookAt(0, 20, 0);

            scene = new THREE.Scene();
            scene.add(new THREE.GridHelper(2000, 10));

            var light = new THREE.DirectionalLight(0xffffff, 2);
            light.position.set(1, 1, 1);
            scene.add(light);

            orbit = new THREE.OrbitControls(camera, renderer.domElement);
            orbit.update();
            orbit.addEventListener('change', render);

            control = new THREE.TransformControls(camera, renderer.domElement);
            control.addEventListener('change', render);

            control.addEventListener('dragging-changed', function(event) {

                orbit.enabled = !event.value;

            });

            // instantiate a texture loader
            var loader = new THREE.TextureLoader();
            loader.crossOrigin = '';



            // The textures to use
            var arr = [
                'images/slider0.jpg',
                'images/slider1.jpg',
                'images/slider2.jpg'
            ];
            var textureToShow = 0;

            // var texture = loadTexture('https://s3-us-west-2.amazonaws.com/s.cdpn.io/259155/MarbleSurface.jpg');

            var material = new THREE.MeshBasicMaterial();
            var geometry = new THREE.PlaneGeometry(200, 200, 200);
            cube = new THREE.Mesh(geometry, material);


            loader.load(arr[textureToShow], function(tex) {
                material.map = tex;
                textureToShow++;
                scene.add(cube);
                render();
            });
            var texture1 = new THREE.TextureLoader().load('images/right-arrow.png', render);
            texture1.anisotropy = renderer.capabilities.getMaxAnisotropy();
            var material1 = new THREE.MeshLambertMaterial({
                map: texture1,
                color: 0x000000,
            });

            var mesh11 = new THREE.Mesh(new THREE.PlaneGeometry(20, 40, 0), material1);
            mesh11.position.x = 90;
            cube.add(mesh11);
            var mesh12 = new THREE.Mesh(new THREE.BoxGeometry(20, 40, 0), new THREE.MeshBasicMaterial({
                color: 0xaa00ff
            }));
            mesh12.position.x = -90;
            cube.add(mesh12);
            meshr.push(mesh11);
            meshl.push(mesh12);

            var domEvents = new THREEx.DomEvents(camera, renderer.domElement);

            domEvents.addEventListener(mesh11, 'click', function(event) {
                loader.load(arr[textureToShow],
                    function(tex) {
                        console.log("right:" + arr[textureToShow]);
                        textureToShow++;


                        if (textureToShow > arr.length - 1) {
                            textureToShow = 0;
                        }
                        material.map = tex;
                        console.log("after: " + textureToShow);
                        render();

                    });
            }, false)
            domEvents.addEventListener(mesh12, 'click', function(event) {
                loader.load(arr[textureToShow], function(tex) {
                    console.log("left:" + arr[textureToShow]);
                    textureToShow--;


                    if (textureToShow == -1) {
                        textureToShow = 2;
                    }
                    tex.dispose();
                    material.map = tex;
                    console.log("after: " + textureToShow);
                    render();
                });
            }, false)

            control.attach(cube);
            scene.add(control);

            window.addEventListener('resize', onWindowResize, false);
        }

        function onWindowResize() {

            camera.aspect = window.innerWidth / window.innerHeight;
            camera.updateProjectionMatrix();

            renderer.setSize(window.innerWidth, window.innerHeight);
            render();

        }

        function render() {
            requestAnimationFrame(render);


            renderer.render(scene, camera);
        }

I will try the loading manager and also by adding a new plane.

Also, could you please check my code and also back and forward buttons logic. When a back button is clicked and forward is clicked they don’t synchronise.

I guess codepen will fail because it does not access your image files.

Preloading with LoadingManager will be something like:

const textures = [];
const manager = new THREE.LoadingManager();
manager.onLoad(function() {
    init();
    animate();
});
const loader = new THREE.TextureLoader(manager);
var arr = [
                'images/slider0.jpg',
                'images/slider1.jpg',
                'images/slider2.jpg'
            ];
for (let i = 0; i < arr.length; i++) {
    loader.load(arr[i], function(tex) {
        textures[i] = tex;
});
}

Then in init and animate and the click handlers you never need to load a texture.

Hey,

Thanks for actively answering.

I was somehow able to make it work by adding the code to codepen, here is the link https://codepen.io/saiviru/pen/NWWNeoy

When I’m adding loadermanager to my code it says manager.onload is not a function. Do I need to add any dependency to run loader manager?

I wrote it from the back of my head, and did one of the usual mistakes…

manager.onLoad(function() {
    init();
    animate();
});

should have been

manager.onLoad = function() {
    init();
    animate();
};

https://threejs.org/docs/#api/en/loaders/managers/LoadingManager

With this setup, you will not call init or animate before all textures are loaded. It would be possible to allow some functionality before textures are loaded, but this is the easiest solution. This way you can count on having the textures available, and will never use TextureLoader again, in the event handlers or elsewhere.

Hello,

I don’t know for some reason, there is no good documentation for loading manager. I’m not able to integrate your code with my code. https://codepen.io/saiviru/pen/NWWNeoy

What is the difference from the previous version? You certainly haven’t added a manager.

I didn’t add the code in codepen, but in my local server. I have added it now could you make necessary changes? https://codepen.io/saiviru/pen/NWWNeoy.
Also please help me with the slider, I have commented the code for extra plane.

No. It is too messy. But you must move the manager and loader out of init and make sure to not call init unconditionally, but only in onLoad. You would use the contiguous code segment I provided earlier in the beginning (maybe with a few changes like crossOrigin=""; and render instead of animate).

Eventually, textures will contain all your textures, and the click handler will basically do:

material.map = textures[someIndex];

Only after making this basic texture switching work fine, I will recommend you to try making a nice animation.

If I’m adding your code at the start it won’t go into init() function. I have added some comments if it makes you look at the code better.

https://codepen.io/eliashasle/pen/gOOMxab?editors=1111

Yeah, I disabled the LoadingManager, as it did not show the behavior I wanted. TextureLoader.load returns a Texture object, which is empty until the image is loaded.

This demo is not perfect, because it seems to not show an image initially. But it is responsive, and the code is much cleaner. I added cube directly to the scene, and removed the TransformControls from the camera. (Why would you have them there?)

1 Like

Thanks a ton. This is great.

But the main concern is to add a slider effect to the textures. This was the hardest part of all.

Is there a possibility to add slider animation to texture. I’ve been searching for this all time. I just need a basic image transition effect.

I told you how above. I think you will have to try yourself.

I’m trying my best on this. I’ll ask you if I’m stuck anywhere.
Thanks for all the help.

1 Like