我有这个着色器,我从着色器玩具移植到 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);
}
这是由于 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/
欢迎光临 OStack程序员社区-中国程序员成长平台 (https://ostack.cn/) | Powered by Discuz! X3.4 |