OGeek|极客世界-中国程序员成长平台

标题: ios - 解决奇怪的行为 re : glsl/metal shader.(无意的坐标翻转) [打印本页]

作者: 菜鸟教程小白    时间: 2022-12-12 12:33
标题: ios - 解决奇怪的行为 re : glsl/metal shader.(无意的坐标翻转)

我有这个着色器,我从着色器玩具移植到 iOS 的 Metal 着色器。原来的工作正常,但现在我已经把它移到了 iOS,我得到了一些奇怪的行为。基本上,在着色器运行的最初几秒钟内,一切都未对齐。我认为这是因为 X 轴上有镜像,这是正确的,但垂直坐标也以某种方式在一侧翻转。谁能告诉我应该如何解决这个问题?

原始着色玩具: https://www.shadertoy.com/view/ltl3Dj

我的版本,转换成 Metal 底纹语言:

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



Best Answer-推荐答案


这是由于 GLSL 的 mod 函数和 Metal 的 fmod 函数之间的行为差​​异。在 Metal 中,GLSL 的 mod 函数如下所示:

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

而 Metal 自己的 fmod 等价于

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

中间操作分别取底(朝向负无穷大)或截断(朝向零)。如果您将您对 fmod 的调用替换为对上述模拟 GLSL 的 mod 版本的调用,您应该观察到两者之间的相同行为。

您可以翻转坐标系以匹配 GL,方法是将任何出现的纹理坐标 (u, v) 替换为 (u, 1-v)。这将使叶片顺时针而不是逆时针旋转,就像它们目前在您的 Metal 实现中所做的那样。在顶点函数中只进行一次这种转换是最简单的。

关于ios - 解决奇怪的行为 re : glsl/metal shader.(无意的坐标翻转),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41169747/






欢迎光临 OGeek|极客世界-中国程序员成长平台 (http://ogeek.cn/) Powered by Discuz! X3.4