2011-01-29 14 views
13

muszę utworzyć gradient wieloetapową po torze kołowym, jak pokazano w poniższym obrazie:Tworzenie Gradient Brush torze kołowym

Wheel Gradient

Czy ktoś ma jakieś pomysły, jak to może być zrealizowane w XAML zamiast kodu? Czy byłoby możliwe wykorzystanie istniejących pędzelków gradientowych lub złożenie ich w jakiś sposób, aby uzyskać ten efekt?

+0

Dlaczego wybory kolorów? Nie jest to zgodne z mapowaniem kolorów smołowych, które widziałem wcześniej, a synestezycy [zazwyczaj postrzegają to inaczej] (http://rhythmiclight.com/archives/ideas/colorscales.html). Wygląda również na to, że nie pasuje on do [Color Piano Project] (http://colorpiano.com/). –

+0

Wybory kolorów są arbitralne i wybrane wyłącznie ze względów estetycznych. Nie ma korelacji z wysokością dźwięku. – Charlie

Odpowiedz

15

Można uzyskać efekt krzyżowy za pomocą transformacji bez afinicznej, takiej jak przekształcenie perspektywy. Kiedyś idei tego artykułu Charles Petzold:

stworzyć obszar XAML tylko pierścieniowa o przekroju promieniowego gradientu. Oto markup:

<Canvas x:Name="LayoutRoot"> 
    <Canvas.Resources> 
     <x:Array x:Key="sampleData" Type="sys:Object"> 
      <x:Array Type="sys:Object"> 
       <sys:Double>0</sys:Double> 
       <LinearGradientBrush StartPoint="0,0" EndPoint="1,0"> 
        <GradientStop Color="Red" Offset="0"/> 
        <GradientStop Color="Yellow" Offset="0.5"/> 
        <GradientStop Color="Blue" Offset="1"/> 
       </LinearGradientBrush> 
      </x:Array> 
      <x:Array Type="sys:Object"> 
       <sys:Double>90</sys:Double> 
       <LinearGradientBrush StartPoint="0,0" EndPoint="1,0"> 
        <GradientStop Color="Blue" Offset="0"/> 
        <GradientStop Color="Green" Offset="0.5"/> 
        <GradientStop Color="Red" Offset="1"/> 
       </LinearGradientBrush> 
      </x:Array> 
      <x:Array Type="sys:Object"> 
       <sys:Double>180</sys:Double> 
       <LinearGradientBrush StartPoint="0,0" EndPoint="1,0"> 
        <GradientStop Color="Red" Offset="0"/> 
        <GradientStop Color="Yellow" Offset="0.5"/> 
        <GradientStop Color="Blue" Offset="1"/> 
       </LinearGradientBrush> 
      </x:Array> 
      <x:Array Type="sys:Object"> 
       <sys:Double>270</sys:Double> 
       <LinearGradientBrush StartPoint="0,0" EndPoint="1,0"> 
        <GradientStop Color="Blue" Offset="0"/> 
        <GradientStop Color="Green" Offset="0.5"/> 
        <GradientStop Color="Red" Offset="1"/> 
       </LinearGradientBrush> 
      </x:Array> 
     </x:Array> 
    </Canvas.Resources> 
    <ItemsControl ItemsSource="{StaticResource sampleData}"> 
     <ItemsControl.OpacityMask> 
      <RadialGradientBrush> 
       <GradientStop Color="Transparent" Offset="0.95"/> 
       <GradientStop Color="White" Offset="0.949"/> 
       <GradientStop Color="White" Offset="0.501"/> 
       <GradientStop Color="Transparent" Offset="0.5"/> 
      </RadialGradientBrush> 
     </ItemsControl.OpacityMask> 
     <ItemsControl.Template> 
      <ControlTemplate TargetType="ItemsControl"> 
       <ItemsPresenter/> 
      </ControlTemplate> 
     </ItemsControl.Template> 
     <ItemsControl.ItemsPanel> 
      <ItemsPanelTemplate> 
       <Canvas/> 
      </ItemsPanelTemplate> 
     </ItemsControl.ItemsPanel> 
     <ItemsControl.ItemTemplate> 
      <DataTemplate> 
       <Canvas Width="1" Height="1"> 
        <Canvas.RenderTransform> 
         <RotateTransform Angle="{Binding [0]}" CenterX="124" CenterY="124"/> 
        </Canvas.RenderTransform> 
        <Viewport3D Width="250" Height="250"> 
         <ModelVisual3D> 
          <ModelVisual3D.Content> 
           <Model3DGroup> 
            <GeometryModel3D> 
             <GeometryModel3D.Geometry> 
              <MeshGeometry3D Positions="0 0 0, 0 1 0, 1 0 0, 1 1 0" TextureCoordinates="0 1, 0 0, 1 1, 1 0" TriangleIndices="0 2 1, 2 3 1"/> 
             </GeometryModel3D.Geometry> 
             <GeometryModel3D.Material> 
              <DiffuseMaterial Brush="{Binding [1]}"/> 
             </GeometryModel3D.Material> 
             <GeometryModel3D.Transform> 
              <MatrixTransform3D Matrix="0.002,0,0,0,-0.499,-0.498,0,-0.998,0,0,1,0,0.499,0.5,0,1"/> 
             </GeometryModel3D.Transform> 
            </GeometryModel3D> 
            <AmbientLight Color="White" /> 
           </Model3DGroup> 
          </ModelVisual3D.Content> 
         </ModelVisual3D> 
         <Viewport3D.Camera> 
          <OrthographicCamera Position="0.5 0.5 1" LookDirection="0 0 -1" UpDirection="0 1 0" Width="1"/> 
         </Viewport3D.Camera> 
        </Viewport3D> 
       </Canvas> 
      </DataTemplate> 
     </ItemsControl.ItemTemplate> 
    </ItemsControl> 
</Canvas> 

i tutaj jest efektem wizualnym:

enter image description here

Efekt wykorzystuje zbiór źródła danych z elementów, które mają dwie właściwości, kąt i pędzlem. Rysuje cztery ćwiartki (w górę, w prawo, w dół i w lewo) za pomocą innego pędzla dla każdego kwadrantu. Następnie całość przycina się do pierścieniowego obszaru za pomocą maski krycia.

+0

To wygląda dla mnie naprawdę dobrze, ale jak wygląda klasa Tuple - wystarczy dodać do niej kilka właściwości, a moje narzuty wyrzucają błędy takie jak "Klasa", która nie obsługuje bezpośredniej treści, itp. – Charlie

+0

Skończyło się konfigurowanie Krotki w kodzie, a nie w marży (wciąż ciekawy, jak wygląda ta klasa), a to wydaje się być właśnie tym, czego potrzebuję. Dzięki za naprawdę sprytne rozwiązanie, Rick. :) – Charlie

+0

Żałuję, że nie było klasy standardowej, takiej jak mój kontener 'Tuple', tylko po to, aby uporządkować dane przykładowe bez konieczności definiowania klas. Możesz użyć x: Array of x: Array lub własnych struktur danych. Zaktualizuję przykład, aby użyć poprzedniej metody. –

0

Spójrz na Shazzam Możesz napisać wskaźnik pikseli, który renderuje ten gradient.

Myślę, że na dłuższą metę będzie to łatwiejsze niż łączenie gradientów liniowych. Inną opcją jest po prostu narysowanie bitmapy i użycie jej.

+0

Dzięki za sugestię, ale cieniowanie pikseli wydaje się być przesadą dla tego scenariusza - po co pisać C/HLSL, kiedy mógłbym napisać kod C#, aby osiągnąć to bardziej bezpośrednio? Ale moim prawdziwym celem było sprawdzenie, czy można to zrobić w XAML. – Charlie

+0

Jak widać (odpowiedź Ricka Sladkeya) można to zrobić jednak uważam, że jego rozwiązanie (transformacje 3D) będzie znacznie wolniejsze, a kod dla elementu Piksele byłby bardzo zwarty. –

1

W GDI +/WinForm można użyć PathGradientBrush to zrobić:

http://www.bobpowell.net/pgb.htm

http://msdn.microsoft.com/en-us/library/system.drawing.drawing2d.pathgradientbrush.aspx

Niestety nie ma wsparcia dla PathGradientBrush w WPF, ale kilka osób pytało o to tutaj :

http://dotnet.uservoice.com/forums/40583-wpf-feature-suggestions/suggestions/480949-add-a-pathgradientbrush-like-in-winforms-

(może być warta odlewa g również Twój głos!)

Z powodu braku wsparcia nie możesz zrobić tego bezpośrednio w XAML, możesz jednak użyć kodu GDI + do utworzenia obrazu, a następnie użyć obrazu w swoim XAML. Może to zapewnić lepszą wydajność niż przy użyciu transformacji nie-afinicznej.

+0

Wypróbuj [Charles Petzold's GradientPath] (http://www.charlespetzold.com/blog/2009/02/Graphical-Paths-with-Gradient-Colors.html). – xmedeko