2016-12-15 12 views
1

У меня есть этот шейдер, который я портировал из shadertoy в металлический шейдер для iOS. Оригинальный работает отлично, но теперь я получаю странное поведение, когда я переместил его в iOS. В принципе, в течение первых нескольких секунд, когда работает шейдер, все смещается. Я думаю, что это потому, что зеркало на оси X, что верно, но вертикальные координаты также были как-то перевернуты с одной стороны. Может ли кто-нибудь сказать мне, как я должен это исправить?Решение нечетного поведения re: glsl/metal shader. (непреднамеренное преобразование координат)

Оригинал Shadertoy: https://www.shadertoy.com/view/ltl3Dj

Моя версия, превращается в металлический язык затенения:

#include <metal_stdlib> 
using namespace metal; 

//////////////// 

///CSB CONSTANTS (not required, just make sure it's handled properly at the bottom) 
constant float2 resolution = (1, 1); 
constant float contrast = 1.0; 
constant float saturation = 1.02; 
constant float brightness = 1.5; 

struct FloweringQuadVertexToFragmentVariables 
{ 
    //basic Active Shader Variables 
    float4 position [[ position ]]; 
    float2 textureCoordinates; 
    float time; 

    //Shader specific variables go here (not required) 

}; 

vertex FloweringQuadVertexToFragmentVariables FloweringQuadVertexShader (constant float4 *positions [[ buffer(0) ]], 
                   constant float2 *textureCoordinates [[ buffer(1) ]], 
                   constant float *shaderFloatZero [[buffer(2)]], 
                   uint vertexID [[ vertex_id ]]) 
{ 
    FloweringQuadVertexToFragmentVariables output; 

    //basic variables output here 
    output.position = positions[vertexID]; 
    output.textureCoordinates = textureCoordinates[vertexID]; 
    output.time = *shaderFloatZero; 

    //additional variables here 

    //output 

    return output; 
} 
// Remember, can do [color(0)] etc. for rendering to attachments other than just [0] 

float3 FloweringContrastSaturationBrightness(float3 color, float brt, float sat, float con) 
{ 
    // Increase or decrease theese values to adjust r, g and b color channels seperately 
    const float AvgLumR = 0.4; 
    const float AvgLumG = 0.4; 
    const float AvgLumB = 0.4; 

    const float3 LumCoeff = float3(0.2125, 0.7154, 0.0721); //luminosity coefficient 

    float3 AvgLumin = float3(AvgLumR, AvgLumG, AvgLumB); 
    float3 brtColor = color * brt; 
    float3 intensity = float3(dot(brtColor, LumCoeff)); 
    float3 satColor = mix(intensity, brtColor, sat); 
    float3 conColor = mix(AvgLumin, satColor, con); 

    return conColor; 
} 

float4 hue(float4 color, float shift) { 

    const float4 kRGBToYPrime = float4 (0.299, 0.587, 0.114, 0.0); 
    const float4 kRGBToI  = float4 (0.596, -0.275, -0.321, 0.0); 
    const float4 kRGBToQ  = float4 (0.212, -0.523, 0.311, 0.0); 

    const float4 kYIQToR = float4 (1.0, 0.956, 0.621, 0.0); 
    const float4 kYIQToG = float4 (1.0, -0.272, -0.647, 0.0); 
    const float4 kYIQToB = float4 (1.0, -1.107, 1.704, 0.0); 

    // Convert to YIQ 
    float YPrime = dot (color, kRGBToYPrime); 
    float I  = dot (color, kRGBToI); 
    float Q  = dot (color, kRGBToQ); 

    // Calculate the hue and chroma 
    float hue  = atan (Q/ I); 
    float chroma = sqrt (I * I + Q * Q); 

    // Make the user's adjustments 
    hue += shift; 

    // Convert back to YIQ 
    Q = chroma * sin (hue); 
    I = chroma * cos (hue); 

    // Convert back to RGB 
    float4 yIQ = float4 (YPrime, I, Q, 0.0); 
    color.r = dot (yIQ, kYIQToR); 
    color.g = dot (yIQ, kYIQToG); 
    color.b = dot (yIQ, kYIQToB); 

    return color; 
} 

float2 kale(float2 uv, float angle, float base, float spin) { 
    float a = atan(uv.y/uv.x)+spin; 
    float d = length(uv); 
    a = fmod(a,angle*2.0); 
    a = abs(a-angle); 
    uv.x = sin(a+base)*d; 
    uv.y = cos(a+base)*d; 
    return uv; 
} 

float2 rotate(float px, float py, float angle){ 
    float2 r = float2(0); 
    r.x = cos(angle)*px - sin(angle)*py; 
    r.y = sin(angle)*px + cos(angle)*py; 
    return r; 
} 

float floweringlum(float3 c) { 
    return dot(c, float3(0.3, 0.59, 0.11)); 
} 

float3 floweringclipcolor(float3 c) { 
    float l = floweringlum(c); 
    float n = min(min(c.r, c.g), c.b); 
    float x = max(max(c.r, c.g), c.b); 

    if (n < 0.0) { 
     c.r = l + ((c.r - l) * l)/(l - n); 
     c.g = l + ((c.g - l) * l)/(l - n); 
     c.b = l + ((c.b - l) * l)/(l - n); 
    } 
    if (x > 1.0) { 
     c.r = l + ((c.r - l) * (1.0 - l))/(x - l); 
     c.g = l + ((c.g - l) * (1.0 - l))/(x - l); 
     c.b = l + ((c.b - l) * (1.0 - l))/(x - l); 
    } 

    return c; 
} 

float3 setfloweringlum(float3 c, float l) { 
    float d = l - floweringlum(c); 
    c = c + float3(d); 
    return floweringclipcolor(c); 
} 

fragment float4 FloweringQuadFragmentShader(FloweringQuadVertexToFragmentVariables input [[ stage_in ]], 
             texture2d<float> fragmentTexture [[ texture(0) ]], 
             sampler samplr [[sampler(0) ]]) 
{ float timeElapsed = input.time; 

    float4 textureColor = fragmentTexture.sample(samplr, input.textureCoordinates); 


    /////// 
    float2 iResolution = (1, 1); 
    float2 texCoords = input.textureCoordinates; 
    //float2 p = texCoords.xy/iResolution.xy; 

    //////// 
    float p = 3.14159265359; 
    float i = timeElapsed*.5; 
    float2 uv = texCoords.xy/iResolution.xy*5.0-2.5; 


    uv = kale(uv, p/6.0,i,i*0.2); 
    float4 c = float4(1.0); 
    const float2x2 m = float2x2(float2(sin(uv.y*cos(uv.x+i)+i*0.1)*20.0, -6.0), 
         float2(sin(uv.x+i*1.5)*3.0,-cos(uv.y-i)*2.0)); 


    uv = rotate(uv.x,uv.y,length(uv)+i*.4); 
    c.rg = cos(sin(uv.xx+uv.yy)*m-i); 
    c.b = sin(rotate(uv.x,uv.x,length(uv.xx)*3.0+i).x-uv.y+i); 
    float4 color = float4(1.0-hue(c,i).rgb,1.0); 
    //////// 
    float4 finalColor; 
    float4 FloweringColor; 
    /*FloweringColor.r = (color.r+(textureColor.r*1.3))/2; 
    FloweringColor.g = (color.g + (textureColor.g*1.3))/2; 
    FloweringColor.b = (color.b + (textureColor.b*1.3))/2; 
    FloweringColor.a = 1.0;*/ 

    float4 cam = textureColor; 
    float4 overlay = color; 

    FloweringColor = float4(cam.rgb * (1.0 - overlay.a) + setfloweringlum(overlay.rgb, floweringlum(cam.rgb)) * overlay.a, cam.a); 

    float3 csbcolor = FloweringContrastSaturationBrightness(FloweringColor.rgb, contrast, saturation, brightness); 
    float alpha = 1.0; 
    finalColor = float4(csbcolor.r, csbcolor.g, csbcolor.b, alpha); 

    return finalColor;//float4(textureColor.a, textureColor.a, textureColor.a, 1.0); 
} 

ответ

2

Это происходит из-за разницы в поведении между mod функции GLSL и fmod функции металла. В Metal, мод функция GLSL была бы выглядеть следующим образом:

float mod(float x, float y) { 
    return x - y * floor(x/y); 
} 

в то время как собственный fmod металла эквивалентно

float fmod(float x, float y) { 
    return x - y * trunc(x/y); 
} 

Промежуточные операции соответственно полу (в сторону отрицательной бесконечности) или укоротить (к нулю). Если вы замените свои звонки на fmod с помощью вызовов к версии mod выше, которая эмулирует GLSL, вы должны наблюдать одинаковое поведение между ними.

Вы можете перевернуть систему координат, чтобы соответствовать GL, заменив любые вхождения текстурных координат (u, v) на (u, 1-v). Это приведет к тому, что лопасти будут вращаться по часовой стрелке, а не против часовой стрелки, как это происходит в настоящее время в реализации Металла. Проще всего сделать это преобразование один раз в функции вершин.

+0

Удивительный ответ! Спасибо :) –