2017-01-23 16 views
0

WPF에서 간단한 3 색 각도 구배를 얻으려고합니다. 가장 좋은 시나리오는 XAML만의 대답이지만, 이것이 불가능하다는 것을 확신합니다.3 색 WPF의 AngleGradient

이 질문은 &입니다. 답변 (AngleGradient in WPF)은 내가 원하는 것의 절반입니다. 나는 코드를 가지고 노려 보았으나 분명히 수학을 올바르게 이해하지 못한다. 내가 정확히 위의 질문에 요청합니다 어떻게 할 수 있지만, 3 색 컬러 3 질문에서 색 1 (사이 그라디언트는 그라디언트에서 어울려 위 :

enter image description here

내 질문은 파란색에서 흰색이지만 직선에서 파란색으로 바뀌면 흰색에서 파란색으로 역방향 그라디언트가 좋음).

완전한 수평베이스가있는 등변 삼각형으로 생각하십시오. 예를 들어 상단 모서리에 빨간색, 왼쪽 하단 모서리에 녹색, 오른쪽 하단 모서리에 파란색과 그 사이에 완벽한 각진 방사능을 원합니다.

enter image description here

나는 대답 같은 .PS로 컴파일 할 필요가 괜찮다는 다른 스레드 :)에

덕분에 많은 제안!

답변

0

나는 다른 스레드가 당신이해야 할 일을 설명 할 수 있다고 생각한다. 셰이더에 세 가지 색을 모두 전달한 다음 원하는 픽셀을 얻으려면 픽셀 단위로 계산해야합니다.

다른 답변과 같은 방법으로 현재 픽셀의 각도를 0에서 1로 가져옵니다. 그런 다음 해당 각도로 적절한 색상을 선택하십시오.

쉐이더

sampler2D inputSampler : register(S0); 
float2 center : register(C0); 
float4 firstColor : register(C1); 
float4 secondColor : register(C2); 
float4 thirdColor : register(C3); 

float4 main(float2 uv : TEXCOORD) : COLOR 
{ 
    // Put the three colors into an array. 
    float4 colors[3] = { firstColor, secondColor, thirdColor }; 

    // Figure out where this pixel is in relation to the center point 
    float2 pos = center - uv; 

    // Compute the angle of this pixel relative to the center (in radians), 
    // then divide by 2 pi to normalize the angle into a 0 to 1 range. 
    // We are flipping the Y here so that 0 is at the top (instead of the bottom) and we 
    // rotate clockwise. Could also flip X if we want to rotate counter-clockwise. 
    float value = (atan2(pos.x, -pos.y) + 3.141596)/(2.0 * 3.141596); 

    // Scale the angle based on the size of our array and determine which indices 
    // we are currently between, wrapping around to 0 at the end. 
    float scaledValue = value * 3; 
    float4 prevColor = colors[(int)scaledValue]; 
    float4 nextColor = colors[((int)scaledValue + 1) % 3]; 

    // Figure out how far between the two colors we are 
    float lerpValue = scaledValue - (float)((int)scaledValue); 

    // Get the alpha of the incoming pixel from the sampler. 
    float alpha = tex2D(inputSampler, uv).a; 

    // Lerp between the colors. Multiply each color by its own alpha and the result by the 
    // incoming alpha becuse WPF expects shaders to return premultiplied alpha pixel values. 
    return float4(
     lerp(prevColor.rgb * prevColor.a, nextColor.rgb * nextColor.a, lerpValue) * alpha, 
     lerp(prevColor.a, nextColor.a, lerpValue) * alpha); 
} 

효과

class AngleGradientEffect : ShaderEffect 
{ 
    public Brush Input 
    { 
     get { return (Brush)GetValue(InputProperty); } 
     set { SetValue(InputProperty, value); } 
    } 
    public static readonly DependencyProperty InputProperty = RegisterPixelShaderSamplerProperty("Input", typeof(AngleGradientEffect), 0); 

    public Point Center 
    { 
     get { return (Point)GetValue(CenterProperty); } 
     set { SetValue(CenterProperty, value); } 
    } 
    public static readonly DependencyProperty CenterProperty = DependencyProperty.Register("Center", typeof(Point), typeof(AngleGradientEffect), 
     new PropertyMetadata(new Point(0.5, 0.5), PixelShaderConstantCallback(0))); 

    public Color FirstColor 
    { 
     get { return (Color)GetValue(FirstColorProperty); } 
     set { SetValue(FirstColorProperty, value); } 
    } 
    public static readonly DependencyProperty FirstColorProperty = DependencyProperty.Register("FirstColor", typeof(Color), typeof(AngleGradientEffect), 
     new PropertyMetadata(Color.FromRgb(255, 0, 0), PixelShaderConstantCallback(1))); 

    public Color SecondColor 
    { 
     get { return (Color)GetValue(SecondColorProperty); } 
     set { SetValue(SecondColorProperty, value); } 
    } 
    public static readonly DependencyProperty SecondColorProperty = DependencyProperty.Register("SecondColor", typeof(Color), typeof(AngleGradientEffect), 
     new PropertyMetadata(Color.FromRgb(0, 255, 0), PixelShaderConstantCallback(2))); 

    public Color ThirdColor 
    { 
     get { return (Color)GetValue(ThirdColorProperty); } 
     set { SetValue(ThirdColorProperty, value); } 
    } 
    public static readonly DependencyProperty ThirdColorProperty = DependencyProperty.Register("ThirdColor", typeof(Color), typeof(AngleGradientEffect), 
     new PropertyMetadata(Color.FromRgb(0, 0, 255), PixelShaderConstantCallback(3))); 

    public AngleGradientEffect() 
    { 
     // ResourceHelper is my own utility that formats URIs for me. The returned URI 
     // string will be something like /AssemblyName;component/Effects/AngleGradient.ps 
     PixelShader = new PixelShader() { UriSource = ResourceHelper.GetResourceUri("Effects/AngleGradient.ps", relative: true)}; 

     UpdateShaderValue(InputProperty); 
     UpdateShaderValue(CenterProperty); 
     UpdateShaderValue(FirstColorProperty); 
     UpdateShaderValue(SecondColorProperty); 
     UpdateShaderValue(ThirdColorProperty); 
    } 
} 

사용

<Ellipse 
    Width="200" 
    Height="200" 
    Fill="White"> 
    <Ellipse.Effect> 
     <effects:AngleGradientEffect 
      FirstColor="Red" 
      SecondColor="Lime" 
      ThirdColor="Blue" /> 
    </Ellipse.Effect> 
</Ellipse> 

enter image description here

RGB 공간에서 서로 다른 색상 사이의 보간을 수행하면 일부 경우 추악한 결과가 나타납니다. HSV로 변환하고 색상이 보간 될 것으로 예상되는 경우 보간하는 것이 좋습니다.

+0

나는 셰이더를 만드는 것에 대한 지식이 전혀 없으며 셰이더 부분을 분명히 이해하지 못합니다. 그러나 그것은 작동합니다! :) 내가 놓친 유일한 이유는 처음 색 센터를 얻을 수 있도록 (셰이더에서) 솔루션을 회전하는 방법을 이해하는 것입니다. 위로 가기 – ericmas001

+0

간단한 변화입니다. 세로로 뒤집을 각도를 계산할 때 셰이더에서 위치의 y 구성 요소를 반전합니다. 'float value = (atan2 (pos.x, -pos.y) + 3.141596)/(2.0 * 3.141596);'가로로 뒤집고 싶다면 x를 뒤집을 수도 있습니다. – Xavier

+0

나는 Y 축을 뒤집기 위해 쉐이더를 편집했고, 소스의 알파 값은 전달 된 색상뿐만 아니라 존중되도록 알파 처리를 변경했습니다. 셰이더가 무엇을하고 있는지 설명하기 위해 코드 주석을 추가했습니다. – Xavier