2016-12-15 1 views
1

J'ai ce shader que j'ai porté d'un shadertoy dans un shader métallique pour iOS. L'original fonctionne très bien, mais je reçois un comportement étrange maintenant que je l'ai déplacé vers iOS. Fondamentalement, pendant les premières secondes que le shader fonctionne, tout est désaligné. Je pense que c'est parce qu'il y a un miroir sur l'axe X, ce qui est correct, mais les coordonnées verticales ont aussi été retournées d'un côté. Quelqu'un peut-il me dire comment je devrais y remédier?Résoudre un comportement étrange re: glsl/metal shader. (retournement de coordonnées involontaire)

originale Shadertoy: https://www.shadertoy.com/view/ltl3Dj

Ma version, convertie en langage d'ombrage en métal:

#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); 
} 

Répondre

2

Cela est dû à une différence de comportement entre la fonction de GLSL mod et la fonction Metal fmod. En métal, la fonction mod GLSL ressemblerait à ceci:

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

en propre fmod de métal est équivalent à

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

Les opérations intermédiaires respectivement étage (vers l'infini négatif) ou tronquer (vers zéro). Si vous remplacez vos appels à fmod par des appels à la version de mod ci-dessus qui émule GLSL, vous devez observer un comportement identique entre les deux.

Vous pouvez inverser le système de coordonnées pour qu'il corresponde à GL en remplaçant les occurrences des coordonnées de texture (u, v) par (u, 1-v). Cela fera tourner les lobes dans le sens des aiguilles d'une montre plutôt que dans le sens inverse des aiguilles d'une montre comme ils le font actuellement dans votre implémentation Metal. Il est plus facile de faire cette transformation une seule fois dans la fonction vertex.

+0

Super réponse! Je vous remercie :) –