2009-10-08 9 views
7

Tôi đang tìm cách để thực hiện chức năng tìm thấy trong HLSL trong C#, cho những người không quen thuộc với cái này - nó được sử dụng để truy cập phần tử vector dễ dàng.HLSL Swizzle - in C#

Vector4 v1, v2; 
// (t,x,y,z) or (alpha,r,g,b) 
v1 = new Vector4 (1,2,0,0); 
v2 = new Vector4 (0,0,3,4); 

// v1 (Green, Z) = v2 (Y, Blue) 
v1.gz = v2.yb; 
// Result : v1 = (1,2,3,4) 

Có thể tạo nhiều thuộc tính (một cho mỗi kết hợp có thể). Tôi có cảm giác có thể làm được thông qua Linq nhưng tôi không thực sự có nhiều kinh nghiệm với nó.

Tôi không biết nếu XNA có bất cứ điều gì giống như loại, nhưng tôi không muốn đi xuống con đường đó vì đây là tất cả tôi sẽ sử dụng nó cho, đó là, nếu nó có nó.

Cảm ơn.

+0

Xin vui lòng xem các chỉnh sửa câu trả lời của tôi, tôi đã bao gồm một giải pháp làm việc thực tế cho vấn đề này, nhưng nó đòi hỏi C# 4.0 –

Trả lời

8

Trong C# 3.5 trở xuống, đặt cược tốt nhất của bạn là chỉ cần sử dụng toàn bộ nhóm thuộc tính. Tuy nhiên, bạn có thể sử dụng dynamic nhập và phân lớp DynamicObject để có được chức năng mà bạn đang tìm Điều này có thể hoặc không thể là một lựa chọn tốt hơn, tôi không biết nhiều về chức năng này.

EDIT:

Tôi rất hấp dẫn bởi câu hỏi, mà tôi đã đi và thực hiện một giải pháp C# 4.0 để này. Mã sau, nhưng bạn cũng có thể download a full solution if that's more your thing [github]. Như thường lệ, bạn được phép sử dụng/ngắt/tạo mã này theo bất kỳ cách nào bạn muốn, không đổ lỗi cho tôi nếu nó xóa ổ đĩa cứng của bạn.

EDIT 3: Đây là chỉnh sửa cuối cùng tôi sẽ thực hiện ở đây, nhưng tôi có lẽ sẽ chơi với hơn này, và tôi sẽ giữ phiên bản liên kết được cập nhật cho bất cứ ai đến bởi đây sau.

EDIT 2:

Trước khi tôi cho phép bạn có thể mã, có những ví dụ về những gì sẽ và sẽ không làm việc trong Program.Main() trong mã riêng của mình.

Và bây giờ, trên mã.

namespace Swizzle 
{ 
    /// <summary> 
    /// This implements the Vector4 class as described in the question, based on our totally generic 
    /// Vector class. 
    /// </summary> 
    class Vector4 : Vector<int> 
    { 
     public Vector4(int val0, int val1, int val2, int val3) 
      : base(new Dictionary<char, int> { {'t', 0}, {'x', 1}, {'y', 2}, {'z', 3}, 
               {'a', 0}, {'r', 1}, {'g', 2}, {'b', 3}}, 
        new int[] { val0, val1, val2, val3 }) 
     { } 
    } 

    class Program 
    { 
     static void Main(string[] args) 
     { 
      dynamic v1, v2, v3; 

      v1 = new Vector4(1, 2, 3, 4); 

      v2 = v1.rgb; 
      // Prints: v2.r: 2 
      Console.WriteLine("v2.r: {0}", v2.r); 
      // Prints: red: 2 
      int red = v2.r; 
      Console.WriteLine("red: {0}", red); 
      // Prints: v2 has 3 elements. 
      Console.WriteLine("v2 has {0} elements.", v2.Length); 

      v3 = new Vector4(5, 6, 7, 8); 
      v3.ar = v2.gb; // yes, the names are preserved! v3 = (3, 4, 7, 8) 

      v2.r = 5; 
      //v2.a = 5; // fails: v2 has no 'a' element, only 'r', 'g', and 'b' 

      // Something fun that will also work 
      Console.WriteLine("v3.gr: {0}", v3.gr); 
      v3.rg = v3.gr; // switch green and red 
      Console.WriteLine("v3.gr: {0}", v3.gr); 

      Console.WriteLine("\r\nPress any key to continue."); 
      Console.ReadKey(true); 
     } 
    } 

    class Vector<T> : DynamicObject 
    { 
     private T[] m_values; 
     private Dictionary<char, int> m_positions; 

     public Vector(Dictionary<char, int> positions, params T[] values) 
     { 
      this.m_positions = positions; 
      this.m_values = values; 
     } 

     public T this[int index] { 
      get { return this.m_values[index]; } 
     } 

     public int Length 
     { 
      get { return this.m_values.Length; } 
     } 

     public override string ToString() 
     { 
      List<string> elements = new List<string>(this.Length); 

      for (int i = 0; i < this.Length; i++) 
      { 
       elements.Add(m_values[i].ToString()); 
      } 

      return string.Join(", ", elements.ToArray()); 
     } 

     public override bool TryGetMember(GetMemberBinder binder, out object result) 
     { 
      if (binder.Name == "Length") { 
       result = this.Length; 
       return true; 
      } 

      if (binder.Name.Length == 1 && this.m_positions.ContainsKey(binder.Name[0])) 
      { 
       result = m_values[this.m_positions[binder.Name[0]]]; 
       return true; 
      } 

      Dictionary<char, int> positions = new Dictionary<char, int>(binder.Name.Length); 
      List<T> values = new List<T>(binder.Name.Length); 
      int i = 0; 
      foreach (char c in binder.Name) 
      { 
       if (!this.m_positions.ContainsKey(c)) 
        return base.TryGetMember(binder, out result); 

       values.Add(m_values[m_positions[c]]); 
       positions.Add(c, i); 

       i++; 
      } 

      result = new Vector<T>(positions, values.ToArray()); 
      return true; 
     } 

     public override bool TrySetMember(SetMemberBinder binder, object value) 
     { 
      // sanity checking. 
      foreach (char c in binder.Name) 
      { 
       if (!this.m_positions.ContainsKey(c)) 
        return base.TrySetMember(binder, value); 
      } 

      Vector<T> vectorValue = value as Vector<T>; 

      if (vectorValue == null && binder.Name.Length == 1 && value is T) 
      { 
       m_values[m_positions[binder.Name[0]]] = (T)value; 
       return true; 
      } 
      else if (vectorValue == null) 
       throw new ArgumentException("You may only set properties of a Vector to another Vector of the same type."); 
      if (vectorValue.Length != binder.Name.Length) 
       throw new ArgumentOutOfRangeException("The length of the Vector given does not match the length of the Vector to assign it to."); 

      int i = 0; 
      foreach (char c in binder.Name) 
      { 
       m_values[m_positions[c]] = vectorValue[i]; 
       i++; 
      } 

      return true; 
     } 
    } 
} 
+0

Bạn luôn có thể khái quát hóa nó hơn nữa và làm cho nó một 'Vector ', nhưng tôi đã được chỉ hạnh phúc nhận được những điều cơ bản làm việc độc đáo. Điều này thực sự có vẻ hữu ích, do đó, đạo cụ để đưa nó lên. –

+0

Chúc mừng, tôi chắc chắn sẽ xem xét điều đó (Tôi chưa có bất kỳ điều gì liên quan đến các loại động). Một điều khác có thể sử dụng việc thực hiện HLSL là gán các vectơ với các kích cỡ khác nhau (vec2 = vec4.xy) vv. Tôi tin rằng với một chút chơi có thể là tốt. –

+0

Mã của tôi trả về một lớp Vector là một tập hợp con của vectơ gốc khi bạn truy cập nó. Tôi sẽ chỉnh sửa trong một số ví dụ. –