Проблема с шейдером ShaderToy, преобразованным в PixiJS v4 - PullRequest
0 голосов
/ 18 октября 2018

Я пытаюсь преобразовать самый базовый шейдер ShaderToy (https://www.shadertoy.com/new) для использования с PixiJS v4.5.5. Я получаю совершенно неподвижный фон:

enter image description here

Предполагается, что фон перемещается и смешивается между цветами, как в примере с ShaderToy. Я не получаю никаких ошибок в консоли.

Мой код:

let width = window.innerWidth;
let height = window.innerHeight;

let app = new PIXI.Application(width, height);
document.body.appendChild(app.view);

let shaderFrag = `
    precision mediump float;

    uniform vec3 iResolution; // viewport resolution (in pixels)
    uniform float iTime; // shader playback time (in seconds)

    void main() {

        // Normalized pixel coordinates (from 0 to 1)
        vec2 uv = gl_FragCoord.xy/iResolution.xy;

        // Time varying pixel color
        vec3 col = 0.5 + 0.5*cos(iTime+uv.xyx+vec3(0,2,4));

        // Output to screen
        gl_FragColor = vec4(col,1.0);

    }
`;

let container = new PIXI.Container();
container.filterArea = app.screen;
app.stage.addChild(container);

let filter = new PIXI.Filter(null, shaderFrag);
filter.uniforms.iResolution = [width, height, 1.0];
filter.uniforms.iTime = 1.0;
container.filters = [filter];

// Animate the filter
app.ticker.add(function(delta) {
    filter.uniforms.iTime += 0.1;
});

В чем здесь проблема?

PS: точно такой же код шейдера отлично работает с Three.js.

1 Ответ

0 голосов
/ 18 октября 2018

Вы столкнулись с ошибкой в ​​ PixiJS .

См. Комментарии в шейдере могут закомментировать строки кода # 5048

Я отладилкод и выяснил, что PixiJs (версия 4.8.2) анализирует файл фрагмента шейдера, чтобы найти униформу.

См. исходный код, который я скопировал из библиотеки:

function extractUniformsFromString(string)
{
    const maskRegex = new RegExp('^(projectionMatrix|uSampler|filterArea|filterClamp)$');

    const uniforms = {};
    let nameSplit;

    // clean the lines a little - remove extra spaces / tabs etc
    // then split along ';'
    const lines = string.replace(/\s+/g, ' ').split(/\s*;\s*/);

    // loop through..
    for (let i = 0; i < lines.length; i++)
    {
        const line = lines[i].trim();

        if (line.indexOf('uniform') > -1)
        {
            const splitLine = line.split(' ');
            const type = splitLine[1];

            let name = splitLine[2];
            let size = 1;

            if (name.indexOf('[') > -1)
            {
                // array!
                nameSplit = name.split(/\[|]/);
                name = nameSplit[0];
                size *= Number(nameSplit[1]);
            }

            if (!name.match(maskRegex))
            {
                uniforms[name] = {
                    value: defaultValue(type, size),
                    name,
                    type,
                };
            }
        }
    }
    return uniforms;
}

Если перед объявлением униформы есть комментарий к строке, как в вашем фрагментном шейдере до iTime, то униформа не может быть найдена.Это приводит к тому, что механизм автоматической синхронизации PixiJS выходит из строя и значение униформы не устанавливается.

Обходной путь прост, просто удалите комментарии после униформ:

precision mediump float;

uniform vec3 iResolution;
uniform float iTime; 

....

См.Пример:

let width = window.innerWidth;
let height = window.innerHeight;
let app = new PIXI.Application(width, height);
document.body.appendChild(app.view);

let shaderFrag = `
    precision mediump float;

    uniform vec3 iResolution;
    uniform float iTime; 

    void main() {

        // Normalized pixel coordinates (from 0 to 1)
        vec2 uv = gl_FragCoord.xy/iResolution.xy;

        // Time varying pixel color
        vec3 col = 0.5 + 0.5*cos(iTime+uv.xyx+vec3(0,2,4));

        // Output to screen
        gl_FragColor = vec4(col,1.0);
    }
`;

let container = new PIXI.Container();
container.filterArea = app.screen;
app.stage.addChild(container);

let filter = new PIXI.Filter(null, shaderFrag);
filter.uniforms.iResolution = [width, height, 1.0];
filter.uniforms.iTime = [1.0];
container.filters = [filter];

app.ticker.add(function(delta) {
    filter.uniforms.iTime[0] += 0.1;
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/pixi.js/4.8.2/pixi.min.js"></script>
...