Страницы

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

вторник, 19 марта 2019 г.

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

Когда-то копаясь в проектах 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); }


Ответ

Вот вам галерея фильтров 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 }; }

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

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