簡體   English   中英

使用單個平面圖像的假視差效果

[英]Fake parallax effect using a single flat image

我試圖在JavaScript中實現'假'視差效果。 描述我的意思真的很難,但我想嘗試一下:

當我將鼠標懸停在頁面上時,我希望頁面上的內容可以移動。 后面的東西應該比前面的東西少 - 通常的視差效果 - 除了我想使用平面圖像這樣做。 現在,通常你必須在圖像編輯器中剪掉東西並替換現在缺少的部分背景等等。 但我認為我曾經以某種“偽造”的方式看到過這種情況:略微伸展和壓縮背景。

不幸的是,我無法找到這種效果的例子,但我很確定它與置換貼圖有關

這種東西有圖書館嗎? 或者至少有人知道我可以翻譯成JavaScript的另一種語言的例子嗎?

不確定你在問什么。 但是我用spritely快速做了一個視差場景。 它確實涉及多個圖像層,但它們可以很容易地制作。 http://www.spritely.net/

還有其他一些像這樣的視差解決方案。 這種方法涉及重復相同的圖像以創建深度。 http://www.stevefenton.co.uk/cmsfiles/assets/File/imageparallax.html

乍一看, Phrogz 鏈接看起來並不相關(之前我也進行了自己的研究時也點了相同的鏈接),但是當我深入研究它時,它正是我所尋找的。

不幸的是,它真的很慢,所以它並不適合我想要的那種動畫,特別是對於屏幕填充圖像。 通過進行一些微優化,我得到了更快的速度,但最終這種情況對於今天的JavaScript來說似乎過於激烈。

無論如何,這就是我最終的結果。 也許它可以幫助某人,或者有人想出如何加速它以便以30或60 fps的速度使用它(工人?)。 代碼並不漂亮,因為我只是搞砸了一下。 用它作為起點。

HTML:

<!DOCTYPE html>
<html>
    <head>
        <meta charset="utf-8" />
        <title></title>
        <script src="displacement.js"></script>
    </head>
    <body>
        <script>
            (function() {
                'use strict';
                var source, map, target;
                var sourceCtx, mapCtx, targetCtx;
                var loaded = false;
                var x = 0, y = 0;
                var filter;

                function render() {
                    filter = new filters.DisplacementMap(
                            source,
                            map,
                            target,
                            new filters.Point(0, 0),
                            x,
                            y,
                            filters.ColorChannel.RED,
                            filters.ColorChannel.RED);
                    filter.draw();
                }

                (function init() {
                    var img = new Image();

                    function prepareCanvases() {
                        // Create canvases and add them to the document
                        source = document.createElement('canvas');
                        map = document.createElement('canvas');
                        target = document.createElement('canvas');
                        [target, source, map].forEach(function(canvas) {
                            canvas.setAttribute('width', img.width);
                            canvas.setAttribute('height', img.height);
                            document.body.appendChild(canvas);
                        });

                        // Get contexts
                        sourceCtx = source.getContext('2d');
                        mapCtx = map.getContext('2d');
                        targetCtx = target.getContext('2d');
                    }

                    // Load source image
                    (function loadImage() {
                        img.onload = function() {
                            prepareCanvases();
                            sourceCtx.drawImage(img, 0, 0);
                            img.onload = function() {
                                mapCtx.drawImage(img, 0, 0);
                                addEventListeners();
                                loaded = true;
                            };
                            // Put your displacement map here
                            img.src = 'jn-map-small.jpg';
                        };
                        // Put your image here
                        img.src = 'jn-edit-small.jpg';
                    }());

                    // Event listener
                    function addEventListeners() {
                        target.onmousemove = function(e) {
                            x = ((-e.offsetX / source.width) * 10) + 5;
                            y = ((-e.offsetY / source.height) * 10) + 5;
                            render();
                        };
                    }
                }());
            }());
        </script>
    </body>
</html>

displacement.js:

/**
 * Based on Romuald Quantin's code
 * @see http://www.soundstep.com/blog/2012/04/25/javascript-displacement-mapping/
 */
var filters = {} || filters;
(function() {

    filters.ColorChannel = {
        RED: 0,
        GREEN: 1,
        BLUE: 2,
        ALPHA: 3
    };

    filters.Point = function(x, y) {
        this.x = x || 0;
        this.y = y || 0;
    };

    filters.DisplacementMap = function(source, map, target, point, scaleX, scaleY, channelX, channelY) {
        this.source = source;
        this.map = map;
        this.target = target;
        this.sourceCtx = this.source.getContext("2d");
        this.mapCtx = this.map.getContext("2d");
        this.targetCtx = this.target.getContext("2d");
        this.point = point || new filters.Point();
        this.scaleX = scaleX || 0;
        this.scaleY = scaleY || 0;
        this.channelX = channelX || filters.ColorChannel.RED;
        this.channelY = channelY || filters.ColorChannel.RED;
        if (this.channelX !== 0 && this.channelX !== 1 && this.channelX !== 2 && this.channelX !== 3)
            this.channelX = filters.ColorChannel.RED;
        if (this.channelY !== 0 && this.channelY !== 1 && this.channelY !== 2 && this.channelY !== 3)
            this.channelY = filters.ColorChannel.RED;
    };

    var p = filters.DisplacementMap.prototype;

    p.draw = function() {
        var sourceData = this.sourceCtx.getImageData(0, 0, this.source.width, this.source.height);
        var mapData = this.mapCtx.getImageData(0, 0, this.map.width, this.map.height);
        var targetDataX = this.sourceCtx.getImageData(0, 0, this.source.width, this.source.height);
        var targetDataY = this.sourceCtx.getImageData(0, 0, this.source.width, this.source.height);
        var pixelsLength = mapData.data.length / 4;
        var colorValue,
                alphaValue,
                ratio,
                ratioWithAlpha,
                pixelShift,
                sourcePosition,
                targetPosition,
                x,
                y;
        var i = 0;
        var map = this.map;
        var point = this.point;
        var channelX = this.channelX;
        var channelY = this.channelY;
        var scaleX = this.scaleX;
        var scaleY = this.scaleY;
        var source = this.source;
        var target = this.target;
        while (i < pixelsLength) {
            x = ((i % map.width) + point.x) | 0;
            y = (((i / map.width) | 0) + point.y) | 0;
//            alphaValue = mapData.data[i * 4 + filters.ColorChannel.ALPHA];
//            ratioWithAlpha = ratio * (alphaValue / 0xFF);
            targetDataX.data = this.setPixels(targetDataX.data, (target.width * y) + x + ((((mapData.data[i * 4 + channelX]) / 0xFF * 2) - 1) * scaleX | 0), sourceData.data, (source.width * y) + x);
            i++;
        }
        i = 0;
        while (i < pixelsLength) {
            x = ((i % map.width) + point.x) | 0;
            y = (((i / map.width) | 0) + point.y) | 0;
//            alphaValue = mapData.data[i * 4 + filters.ColorChannel.ALPHA];
//            ratioWithAlpha = ratio * (alphaValue / 0xFF);
            targetDataY.data = this.setPixels(targetDataY.data, (target.width * (y + ((((mapData.data[i * 4 + channelY]) / 0xFF * 2) - 1) * scaleY | 0))) + x, targetDataX.data, (source.width * y) + x);
            i++;
        }
        this.targetCtx.putImageData(targetDataY, 0, 0);
    };

    p.setPixels = function(target, pos, source, i) {
        i = i * 4;
        pos = pos * 4;
        target[i] = source[pos];
        target[i + 1] = source[pos + 1];
        target[i + 2] = source[pos + 2];
        target[i + 3] = source[pos + 3];
        return target;
    };

})();

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM