Así que estoy haciendo un desarrollo de DirectX, usando SharpDX bajo .NET para ser exactos (pero las soluciones API de DirectX / C ++ son aplicables). Estoy buscando la forma más rápida de representar líneas en una proyección ortogonal (por ejemplo, simulando un dibujo lineal 2D para aplicaciones científicas) usando DirectX.
A continuación se muestra una captura de pantalla de los tipos de parcelas que intento representar:
No es raro que este tipo de parcelas tengan líneas con millones de segmentos, de espesor variable, con o sin antialiasing por línea (o pantalla completa AA activada / desactivada). Necesito actualizar los vértices de las líneas con mucha frecuencia (por ejemplo, 20 veces / segundo) y descargar la mayor cantidad posible a la GPU.
Hasta ahora he intentado:
- La representación de software, por ejemplo, GDI + en realidad no es un mal rendimiento, pero obviamente es pesado en la CPU
- Direct2D API: más lento que GDI, especialmente con Antialiasing en
- Direct3D10 usando este método para emular AA usando colores de vértice y teselación en el lado de la CPU. También lento (lo perfilé y se pasa el 80% del tiempo calculando las posiciones de los vértices)
Para el tercer método, estoy usando Vertex Buffers para enviar una franja triangular a la GPU y actualizar cada 200 ms con nuevos vértices. Estoy obteniendo una frecuencia de actualización de alrededor de 5FPS para 100,000 segmentos de línea. ¡Necesito millones idealmente!
Ahora estoy pensando que la forma más rápida sería hacer la teselación en la GPU, por ejemplo, en un sombreador de geometría. Podría enviar los vértices como una lista de líneas o empaquetar en una textura y desempaquetar en un sombreador de geometría para crear los quads. O simplemente envíe puntos sin procesar a un sombreador de píxeles e implemente el dibujo lineal de Bresenham completamente en un sombreador de píxeles. Mi HLSL es un modelo oxidado y sombreado 2 de 2006, así que no sé qué cosas locas pueden hacer las GPU modernas.
Entonces la pregunta es: ¿Alguien ha hecho esto antes y tiene alguna sugerencia que probar? - ¿Tiene alguna sugerencia para mejorar el rendimiento actualizando rápidamente la geometría (por ejemplo, una nueva lista de vértices cada 20 ms)?
ACTUALIZACIÓN 21 de enero
Desde entonces he implementado el método (3) anterior usando sombreadores Geometry usando LineStrip y Dynamic Vertex Buffers. Ahora obtengo 100FPS en 100k puntos y 10FPS en 1,000,000 puntos. Esta es una gran mejora, pero ahora tengo una tasa de relleno y un cálculo limitados, así que pensé en otras técnicas / ideas.
- ¿Qué pasa con la instalación de hardware de una geometría de segmento de línea?
- ¿Qué pasa con Sprite Batch?
- ¿Qué pasa con otros métodos orientados (sombreador de píxeles)?
- ¿Puedo sacrificar eficientemente la GPU o la CPU?
Sus comentarios y sugerencias son muy apreciados!
Respuestas:
Si solo va a representar
Y = f(X)
gráficos, le sugiero que pruebe el siguiente método.Los datos de la curva se pasan como datos de textura , haciéndolos persistentes y permitiendo actualizaciones parciales,
glTexSubImage2D
por ejemplo. Si necesita desplazarse, incluso podría implementar un búfer circular y solo actualizar algunos valores por fotograma. Cada curva se representa como un quad de pantalla completa y el sombreador de píxeles realiza todo el trabajo.El contenido de textura de un componente podría verse así:
El trabajo del sombreador de píxeles es el siguiente:
41.3
, elegiría40
,41
,42
y43
.X,Y
pares al espacio de la pantallaEs posible que desee sustituir 4 con valores más grandes según el nivel de zoom potencial.
He escrito un sombreador GLSL muy rápido y sucio que implementa esta característica . Puedo agregar la versión HLSL más tarde, pero deberías poder convertirla sin demasiado esfuerzo. El resultado se puede ver a continuación, con diferentes tamaños de línea y densidades de datos:
Una ventaja clara es que la cantidad de datos transferidos es muy baja, y el número de llamadas es solo uno.
fuente
Hubo un capítulo de GPU Gems sobre la representación de líneas antialias: Líneas prefiltradas rápidas . La idea básica es representar cada segmento de línea como un quad y calcular, en cada píxel, una función gaussiana de la distancia del centro de píxeles desde el segmento de línea.
Esto significa dibujar cada segmento de línea en el gráfico como un quad separado, pero en D3D11 ciertamente podría usar un sombreador de geometría y / o instancias para generar los quads, reduciendo la cantidad de datos que se transferirán a la GPU solo a los puntos de datos sí mismos. Probablemente configuré los puntos de datos como un StructuredBuffer para que los lea el sombreador de vértices / geometría, luego haría una llamada de dibujo especificando el número de segmentos a dibujar. No habría ningún buffer de vértice real; el sombreador de vértices simplemente usaría SV_VertexID o SV_InstanceID para determinar qué puntos de datos mirar.
fuente
@ Dr.ABT - Disculpas por esto es una pregunta, no una respuesta. No encontré una forma de preguntar en la respuesta de Sam Hocevar anterior.
¿Podría compartir más detalles sobre cómo finalmente implementó las líneas para su gráfico? Tengo la misma necesidad de una aplicación WPF. Gracias de antemano por cualquier detalle o código que pueda compartir sobre esto.
fuente