2010-02-23 20 views
12

Tôi đang làm việc trên một ứng dụng giống như trò chơi có tới một nghìn hình dạng (hình elip và đường thẳng) liên tục thay đổi ở 60 khung hình/giây. Sau khi đọc một số excellent article on rendering many moving shapes, tôi đã triển khai điều này bằng cách sử dụng con cháu Canvas tùy chỉnh ghi đè OnRender để thực hiện bản vẽ qua DrawingContext. Hiệu suất là khá hợp lý, mặc dù việc sử dụng CPU vẫn cao. Tuy nhiên, bài viết gợi ý rằng cách tiếp cận hiệu quả nhất cho các hình ảnh liên tục di chuyển là sử dụng nhiều trường hợp DrawingVisual thay vì OnRender. Thật không may mặc dù nó không giải thích được lý do tại sao sẽ nhanh hơn cho trường hợp này.Hiệu suất của DrawingVisual và Canvas.OnRender cho nhiều hình dạng liên tục thay đổi

Thay đổi việc triển khai theo cách này không phải là một nỗ lực nhỏ, vì vậy tôi muốn hiểu lý do và liệu chúng có thể áp dụng cho tôi trước khi quyết định thực hiện chuyển đổi hay không. Tại sao phương pháp tiếp cận DrawingVisual dẫn đến việc sử dụng CPU thấp hơn cách tiếp cận OnRender trong trường hợp này?

+0

Romkyns, bạn có thể tạo một số phiên bản đơn giản với DrawingVisual và Canvas.OnRender() để phù hợp với hiệu suất, trước khi bạn nghiên cứu những thay đổi lớn. Về phần trả lời - tôi hoàn toàn đồng ý với Charlie. – Anvaka

Trả lời

7

Tôi nghĩ Petzold giải thích trong đoạn này;

ScatterPlotPhiên bản này hoạt động bằng cách tạo đối tượng DrawingVisual cho mỗi DataPoint. Khi các thuộc tính của thay đổi đối tượng DataPoint, lớp chỉ cần thay đổi DrawingVisual được kết hợp với DataPoint đó.

Được xây dựng trên trước đó giải thích;

Bất cứ khi nào ItemsSource tài sản thay đổi, hoặc những thay đổi bộ sưu tập, hoặc một thuộc tính của đối tượng Datapoint trong những thay đổi bộ sưu tập, ScatterPlotRender gọi InvalidateVisual. Điều này tạo ra một cuộc gọi tới OnRender, thu hút toàn bộ âm mưu phân tán.

Đây có phải là điều bạn yêu cầu không? Bằng cách này, this là một hướng dẫn WPF hiệu suất cao gần đây, hàng chục nghìn điểm trong cốt truyện đó, nó được dựng hình 3D và hoạt hình (thậm chí sử dụng đầu vào chuột để điều khiển một số biến đổi).

+2

Vâng, có vẻ như tôi đã nhầm lẫn vì không nhận ra rằng phương pháp 'DrawingVisual' chỉ được cho là phương pháp" tốt nhất "cho kịch bản cụ thể này - nơi nhiều điểm thay đổi, nhưng không phải là toàn bộ. Khi mọi thứ chuyển động (đó là trường hợp của tôi), 'OnRender' có vẻ giống như cách tiếp cận tốt nhất. Liên kết tốt đẹp, quá - cảm ơn. –

+0

Có một cách tiếp cận khác mà tôi đã nhận thấy đó là hiệu suất tốt nhất để thay đổi ứng dụng bằng "nhiều hình dạng liên tục thay đổi", đó là câu hỏi của OP. Ứng dụng của bạn có thể thao tác một cây của DrawingGroups. Bạn chỉ phải gọi RenderOpen/DrawDrawing một lần, khi khởi động ứng dụng, trên thư mục gốc của cây này.Từ đó trở đi, WPF thông báo tất cả các chỉnh sửa cho cây và cập nhật tự động, bao gồm các biến đổi và chèn/xóa các trẻ em DrawingGroup lồng nhau sâu sắc. Bạn sẽ cần một cấu trúc dữ liệu theo dõi/duy trì trạng thái của cây. Xem nhận xét của tôi tại http://stackoverflow.com/a/716469/147511. –

15

Từ Pro WPF trong C# 2008:

Vấn đề đặt ra bởi những các ứng dụng không phải là sự phức tạp của nghệ thuật, nhưng số lượng tuyệt đối của yếu tố đồ họa riêng biệt. Ngay cả khi bạn thay thế các phần tử Đường dẫn của mình bằng các đối tượng Hình học trọng lượng nhẹ hơn , chi phí vẫn sẽ cản trở hiệu suất của ứng dụng . Giải pháp WPF cho loại tình huống này là để sử dụng lớp hình ảnh cấp thấp hơn mô hình. Ý tưởng cơ bản là bạn xác định từng phần tử đồ họa là một đối tượng hình ảnh , là một thành phần nhẹ cực kỳ có ít hơn một đối tượng Hình học hoặc đối tượng Đường dẫn .

Điều gì nó tóm tắt là mỗi một trong những hình elip và đường mà bạn đang tạo là riêng biệt FrameworkElement; điều đó có nghĩa là nó hỗ trợ không chỉ thử nghiệm truy cập mà còn hỗ trợ bố cục, đầu vào, tiêu điểm, sự kiện, kiểu, ràng buộc dữ liệu, tài nguyên và hoạt ảnh. Đó là một vật nặng cân nặng cho những gì bạn đang cố gắng làm! Đối tượng Visual bỏ qua tất cả điều đó và kế thừa trực tiếp từ DependencyObject. Nó vẫn cung cấp hỗ trợ cho thử nghiệm hit, phối hợp chuyển đổi, và tính toán hộp bounding, nhưng không ai trong số những thứ khác mà các hình dạng hỗ trợ. Nó nhẹ hơn rất nhiều và có thể cải thiện hiệu suất của bạn vô cùng.

EDIT:

Ok, tôi hiểu sai câu hỏi của bạn lần đầu tiên xung quanh.

Trong trường hợp bạn đang sử dụng OnRender, nó thực sự phụ thuộc vào cách bạn đang tạo hình ảnh và hiển thị chúng. Nếu bạn đang sử dụng DrawingContext và thêm tất cả các hình ảnh vào một phần tử, điều này không khác với cách tiếp cận DrawingVisual. Nếu bạn đã tạo một phần tử riêng cho mỗi Visual được tạo, thì đây sẽ là một vấn đề. Dường như với tôi rằng bạn đang làm việc đúng cách.

+2

Câu trả lời rất hay! +1 từ tôi. – Anvaka

+1

Đợi đã, tôi không tạo bất kỳ FrameworkElements nào! :) Tôi đang sử dụng 'OnRender' +' DrawingContext', vì vậy trừ khi DrawingContext tạo ra một loạt các FrameworkElements đằng sau hậu trường (mà tôi nghi ngờ) đây không phải là trường hợp. –

+0

Tệ của tôi. Đã thêm chỉnh sửa. :) – Charlie

7

Mọi người trong câu trả lời đều sai. Câu hỏi đặt ra là liệu việc kết xuất trực tiếp các hình dạng trong bối cảnh vẽ có nhanh hơn việc tạo DrawingVisual hay không. Câu trả lời rõ ràng là 'có'. Các chức năng như DrawLine, DrawEllipse, DrawRectangle vv không tạo bất kỳ phần tử giao diện người dùng nào. DrawingVisual chậm hơn nhiều vì nó tạo ra một phần tử UI, mặc dù một phần tử nhẹ. Sự nhầm lẫn trong câu trả lời là bởi vì mọi người chỉ cần sao chép/dán DrawingVisual thực hiện tốt hơn so với tuyên bố hình dạng UIElement riêng biệt từ MSDN.

+4

Tôi không hoàn toàn chắc chắn câu trả lời là điều này rõ ràng. Trong trường hợp hầu hết các hình dạng không di chuyển, không phải ngữ cảnh vẽ * chậm hơn *? Nó vẽ lại mọi thứ, trong khi phương pháp DrawingVisual cho phép khung làm việc để lưu trữ và sử dụng lại những thứ được vẽ trước đó. Hay điều này không phải vậy? –

+3

DrawingContext không vẽ lại mọi thứ vì WPF có mô hình bản vẽ được giữ lại. DrawingVisual bao gồm logic kiểm soát việc có nên vẽ lại hình ảnh hay không. Bạn có thể thực hiện cùng một logic trong phương thức OnRender() và chỉ vẽ khi cần thiết. WPF sẽ không làm mất hiệu lực bản vẽ của bạn ở 60 khung hình/giây, OnRender() được gọi chỉ khi bạn gọi InvalidateVisual() hoặc khi WPF cần vô hiệu hóa bản vẽ của bạn. – user275587

2

Trong thử nghiệm của tôi tuy nhiên (panning hình động), tôi nhận thấy không có sự khác biệt về tốc độ. Tôi sẽ nói rằng sử dụng một yếu tố máy chủ cho nhiều hình ảnh vẽ nhanh hơn một chút. Cách tiếp cận này, nơi bạn xây dựng cây thị giác của mình với nhiều hình ảnh cho phép bạn kiểm soát nhiều hơn. Hơn nữa, khi bạn muốn thực hiện một thử nghiệm nhấn phức tạp, quá trình lọc nhanh hơn vì bạn có thể bỏ qua toàn bộ "nhánh" của hình ảnh

Các vấn đề liên quan