Страницы

Поиск по вопросам

воскресенье, 26 января 2020 г.

3D эффект параллакса для фотографии (Depthy)

#javascript #алгоритм #canvas #webgl


Когда-то копаясь в проектах WebGL находил Depthy

Исходник на github

Возникло желание попрактиковаться с реализацией такого эффекта, после чего сразу
покопался в исходниках, где нашел основной класс для этого. Конечно разбираться в непрокомментированном
коде нет охоты (там же и PIXI, о котором я слышу впервые), поэтому решил сразу спросить
здесь, может растолкуете сам принцип и этапы, но и я по ходу изучения может смогу добавить
информации.

В данный момент "под рукой" есть JS+Canvas, думаю для реализации этого будет достаточно

Пока мысль лишь о том, чтобы каждый пиксель изображения смещать по заданному оффсету(в
данном случае это позиция курсора относительно центра) полагаясь на значение того же
пикселя на карте глубины. Может тогда возникнут разрывы пикселей и эффект Nearest фильтрации,
о чем я не могу пока что лишь предположить, но и это по ходу дела решится?!

Вот что получилось на данный момент чистым JS+Canvas

this.render=function(ctx,offsetX,offsetY) {


            for (var i = 0, l = output.width * output.height * 4; i < l; i += 4) {
                if(i<0 || i>l)continue;


                var depthK = (255-depthData[i/4])/5000;



                var offset=i+Math.round((Math.floor(offsetY*depthK)*output.width+Math.floor(offsetX*depthK)))*4;

                output.data[i] = mapData[offset];
                output.data[i + 1] = mapData[offset+1];
                output.data[i + 2] = mapData[offset+2];
            }



            ctx.putImageData(output,0,0);
        };


И это на WebGL. Быстрее и визуально приятнее. Весь код идентичен Hello World'овским,
за исключением фрагментного шейдера, куда я передаю две текстуры, одна из которых накладывается
на примитивы, а другая служит коэффициентом смещения для каждого пикселя по карте глубины

precision mediump float;
    uniform sampler2D map;
    uniform sampler2D depth;
    uniform vec2 offset;
    varying vec2 uv;


  void main(void) {

    vec2 texCoord = (uv+offset*(1.0-texture2D(depth,uv).z));

    gl_FragColor = vec4(texture2D(map,texCoord).xyz, 1.0);
  }

    


Ответы

Ответ 1



Вот вам галерея фильтров pixi. Поиграйтесь с displacement — это именно то, что вам нужно. А как захотите повторить — вот вам код для этого. Я сам с этой библиотекой не сильно знаком, но полагаю, если вы начнете со странички "basics" и дочитаете до фильтров, все станет понятно. Моя реализация: http://jsfiddle.net/ycj88zhs/2/ var image, depthMap, displacementMap; image = load( 'http://depthy.me/samples/hut-image.jpg', function () { depthMap = load( 'http://i.imgur.com/C4ZJY9m.jpg', function () { var renderer = PIXI.autoDetectRenderer( image.canvas.width, image.canvas.height); document.body.appendChild(renderer.view); var stage = new PIXI.Container(); stage.interactive = true; var container = new PIXI.Container(); stage.addChild(container); var displacementSprite = new PIXI.Sprite( PIXI.Texture.fromCanvas(depthMap.canvas)); displacementSprite.width = image.canvas.width; displacementSprite.height = image.canvas.height; stage.addChild(displacementSprite); var displacementFilter = new PIXI.filters. DisplacementFilter(displacementSprite); container.filters = [displacementFilter]; displacementFilter.scale.x = 10; displacementFilter.scale.y = 10; var bg = new PIXI.Sprite( PIXI.Texture.fromCanvas(image.canvas)); container.addChild(bg); stage.on('mousemove', onPointerMove) .on('touchmove', onPointerMove); renderer.render(stage); function onPointerMove(eventData) { var mouseOffsetX = eventData.data.global.x / image.canvas.width; var mouseOffsetY = eventData.data.global.y / image.canvas.height; displacementFilter.scale.x = mouseOffsetX * 20; displacementFilter.scale.y = mouseOffsetY * 20; renderer.render(stage); } }) }) function load(path, callback) { var canvas = document.createElement("canvas"); var ctx = canvas.getContext("2d"); var img = document.createElement('img'); img.crossOrigin = "Anonymous"; img.onload = function () { canvas.width = img.width; canvas.height = img.height; ctx.drawImage(img, 0, 0); callback(canvas, ctx, img); }; img.src = path; return { context: ctx, image: img, canvas: canvas }; }

Комментариев нет:

Отправить комментарий