GDI, programación 2D mediante API Mediados de los 90: Primeros juegos 3D reales. Al poco, surgen las aceleradoras 3D: Filtrado de texturas, altas resoluciones, efectos… Aparecen las APIs 3D: OpenGL y DirectX Con la llegada de .NET: Primeros wrappers de DirectX Managed DirectX 9: API .NET para emplear DirectX sin desarrollar wrappers
versión nativa Rendimiento: Alrededor del 80-85% respecto a DirectX nativo con C/C++ Sencillez, rapidez, mejor estructuración de código, aprovechar las virtudes de .NET… Soporte (Beta de momento) de .NET 2.0 Distintos lenguajes (Managed C++, C#, VB.NET…)
La aplicación (a grandes rasgos) espera acciones del usuario. Se emplean eventos (click, load,…) Videojuegos: Game-Loop, Render-Loop (aplicaciones activas) Game-Loop: Un gran bucle que itera hasta que termina el juego. Dentro del mismo se gestionan movimiento, IA, gráficos,… Render-Loop: Se re-dibujan todos los gráficos presentados en pantalla varias veces por segundo (FPS).
un formulario Método simple. Convierte un formulario en un pilar de la aplicación al llevar lógica. Opción 2: Independiente, con llamadas en cada iteración del Game-Loop Método clásico. Ayuda a una buena estructuración. Opción 3: Independiente, llamado cuando la aplicación esta Idle (empleando P/Invoke) Método óptimo. Parece complejo (muy similar a la opción 2, pero en lugar de bucle activo itera sólo cuando la aplicación “está disponible”).
Matrices y el álgebra en general. En DirectX realizaremos operaciones sobre los objetos multiplicandolos mediante matrices y vectores. Por defecto, sistema de coords mano izq. Coordenadas mano izquierda Coordenadas mano derecha
Espacio 3D : se emplea para situar los objetos Device.Transform.View Cámara : Información de la cámara Device.Transform.Projection View fustrum: zona de visión (explicado más adelante)
matemáticas Microsoft.DirectX.Direct3D Toda la parte de 3D y Helpers Microsoft.DirectX.Direct3DX Extensiones de las 3D Microsoft.DirectX.DirectInput Controladores (Teclado, Mouse, Joystick…) Microsoft.DirectX.DirectSound Sonido 2D y 3D, efectos de sonido Microsoft.DirectX.AudioVideoPlayback Videos, sonidos (gestión simplificada)
gira en torno a él Encargado de dibujar en pantalla (o parte de ésta) Inicialización, finalización y pintado de escena … // Creación del Device Device dxDevice = new Device(adapter, DeviceType.Hardware, this, createFlags, presentParams); … // En la parte de representar la escena // Vaciar Pantalla/Dispositivo dxDevice.Clear(ClearFlags.Target, System.Drawing.Color.Black, 1.0f, 0); // Comienzo del dibujado de objetos dxDevice.BeginScene(); … // Fin del dibujado los objetos dxDevice.EndScene(); … // Volcado del buffer a la pantalla dxDevice.Present();
aceleradora 3D, y si no tiene soporte Hardware, podemos escoger modo emulado por software. // Obtenemos el adaptador/tarjeta gráfica por defecto int adapter = Manager.Adapters.Default.Adapter; // Obtenemos sus capacidades 3D Caps deviceCaps = Manager.GetDeviceCaps(adapter, DeviceType.Hardware); // Si soporta H&L por hardware, lo activamos, sino emulación software CreateFlags createFlags = deviceCaps.DeviceCaps.SupportsHardwareTransformAndLight ? CreateFlags.HardwareVertexProcessing : CreateFlags.SoftwareVertexProcessing; // Comprobamos si soporta iluminación, shaders, etc. if (deviceCaps.DeviceCaps.SupportsPureDevice && createFlags == CreateFlags.HardwareVertexProcessing) createFlags |= CreateFlags.PureDevice;
(ventana o fullscreen, funcionamiento de los buffers, etc.) Todo esto se usa al inicializar el Device PresentParameters presentParams = new PresentParameters(); // Descartar contenido del backbuffer y volcar al front buffer directamente presentParams.SwapEffect = SwapEffect.Discard; // Modo ventana presentParams.Windowed = true; … Device dxDevice = new Device(adapter, DeviceType.Hardware, this, createFlags, presentParams); Formulario o control donde pintar
Este estilo de pintado evita borrados del formulario por repintados nativos de windows Lógicamente, el fondo será opaco (2º parámetro) // En el constructor del formulario que contendrá el Device // justo tras la llamada al InitializeComponent this.SetStyle(ControlStyles.AllPaintingInWmPaint|ControlStyles.Opaque,true);
de un triángulo no está visible, no se dibuja. Para calcularlo (y evitar pérdida de triángulos) se unen los vértices de los triángulos en un determinado orden (ClockWise, CounterClockWise, None). // Modo por defecto y el adecuado para eje de coords mano izquierda dxDevice.RenderState.CullMode = Cull.CounterClockWise;
this.Width / this.Height, 1.0f, 100.0f); dxDevice.Transform.View = Matrix.LookAtLH(new Vector3(0, 0, 5.0f), new Vector3(), new Vector3(0, 1, 0)); Plano de clipping frontal Plano de clipping trasero View frustrum Cámara FOV
visión) 2 : Ratio de aspecto 3 : Front clipping plane (plano de clipping frontal) 4 : Back clipping plane (plano de clipping trasero) Matrix.LookAtLH(_1_,_2_,_3_); 1 : Posición de la cámara 2 : Objetivo de la cámara 3 : Vector Arriba de la cámara dxDevice.Transform.Projection = Matrix.PerspectiveFovLH((float)Math.PI / 4, this.Width / this.Height, 1.0f, 100.0f); dxDevice.Transform.View = Matrix.LookAtLH(new Vector3(0, 0, 5.0f), new Vector3(), new Vector3(0, 1, 0));
elementos básicos Puntos, lineas y triángulos Todos se forman mendiante vértices Básicos: Vector3, Vector4,… CustomVertex Position/Transformed, Colored, Textured, Normal Se pueden combinar CustomVertex myVert = new CustomVertex.PositionColoredTextured();
triángulos formando una figura Pueden estar divididos en segmentos DirectX los almacena en formato .X Incluye información de los materiales y texturas Direct3D proporciona algunos básicos: Box (caja/cubo) Torus (donut) Teapot (tetera) Sphere (esfera) Cylinder (cilindro) Polygon (polígono)
pueden cargar desde archivo Mesh.FromFile Más información en el SDK y código en la Demo Importante calcular sus normales si no las tiene Mesh cube = new Mesh.Box(dxDevice,width,height,size); if ((mesh.VertexFormat & VertexFormats.Normal) != VertexFormats.Normal) { Mesh tempMesh = mesh.Clone(mesh.Options.Value, mesh.VertexFormat | VertexFormats.Normal, device); tempMesh.ComputeNormals(); mesh.Dispose(); mesh = tempMesh; }
Z Sin activarlo, todos los objetos se pintan en el eje Z = 0, y se producen artefactos/fallos de pintado No olvidar limpiar el Z-Buffer/Depth Buffer Para mejor rendimiento, procurar pintar siempre los elementos del mas alejado (mayor Z) al más cercano (menor Z) presentParams.EnableAutoDepthStencil = true; presentParams.AutoDepthStencilFormat = DepthFormat.D16; dxDevice.Clear(ClearFlags.Target | ClearFlags.Zbuffer, Color.Black, 1.0f, 0);
texturizado, y se les establecen las coordenadas UV a cada uno CustomVertex.PositionTextured[] verts = new CustomVertex.PositionTextured[6]; verts[0] = new CustomVertex.PositionTextured(-1.0f, 1.0f, 1.0f, 0.0f, 0.0f); verts[1] = new CustomVertex.PositionTextured(-1.0f, -1.0f, 1.0f, 0.0f, 1.0f); verts[2] = new CustomVertex.PositionTextured(1.0f, 1.0f, 1.0f, 1.0f, 0.0f); verts[3] = new CustomVertex.PositionTextured(-1.0f, -1.0f, 1.0f, 0.0f, 1.0f); verts[4] = new CustomVertex.PositionTextured(1.0f, -1.0f, 1.0f, 1.0f, 1.0f); verts[5] = new CustomVertex.PositionTextured(1.0f, 1.0f, 1.0f, 1.0f, 0.0f); 0 2 5 1 3 4
pintar el modelo o fragmento de él, se indica la textura que empleará (o null si no pintamos textura) Texture texture1 = new Texture(dxDevice, new Bitmap(this.GetType(), “rock.bmp"), 0, Pool.Managed); dxDevice.SetTexture(0, texture1); dxDevice.DrawPrimitives(PrimitiveType.TriangleList, 0, 6);
(por defecto viene desactivada) Activando la iluminación, todo queda oscuro y hemos de definir la iluminación DirectX proporciona distintos modelos de iluminación Mediante los materiales definiremos cómo se comportan los objetos respecto a la luz, al color, etc. dxDevice.RenderState.Lighting = false;
objetos Sólo se le indica un color Se puede emplear siempre ya que afecta al Device y no emplea un punto de luz // Iluminación gris dxDevice.RenderState.Ambient = System.Drawing.Color.FromArgb(0x404040);
las direcciones desde un punto inicial, con un alcance máximo dxDevice.Lights[0].Type = LightType.Point; dxDevice.Lights[0].Diffuse = Color.Red; dxDevice.Lights[0].Range = 100.0f; dxDevice.Lights[0].Position = new Vector3( 0.0f, 0.0f, 0.0f ); dxDevice.Lights[0].Attenuation0 = 1.0f; dxDevice.Lights[0].Update(); dxDevice.Lights[0].Enabled = true;
mesh o fragmento del mismo respecto de la luz Cómo refleja la luz (Ambiental, Diffuse, Specular) Si emite luz propia de algún color (Emissive) Material material1 = new Material(); Material1.Ambient = Color.White; Material1.Diffuse = Color.White; … dxDevice.Material = material1; dxDevice.DrawPrimitives(PrimitiveType.TriangleList, 0, 6);
iluminación avanzada: Device.DeviceCaps.VertexProcessingCaps.SupportsDirectionalLights Obtener el número máximo de luces soportadas por la tarjeta gráfica: Device.DeviceCaps.MaxActiveLights No abusar de la iluminación Cada fuente de luz supone realizar muchos cálculos adicionales por fotograma
mediante operaciones con matrices y vectores Meshes Cámara (posición y/o orientación) Posiciones de las luces Movemos desde el eje (coords [0,0,0]) Multiplicando combinamos movimientos // Situamos el mundo en [0,0,2] dxDevice.Transform.World = Matrix.Translation(0.0f, 0.0f, 2.0f); … // Dibujamos un objeto // Situamos el mundo en [1,1,1] y rotamos sobre el eje Z dxDevice.Transform.World = Matrix.Translation(1.0f, 1.0f, 1.0f) * Matrix.RotationZ(0.2f); … // Dibujamos otro objeto
(ratón, teclado, joysticks,…) Similar (pero más completo) a la gestión de .NET Funcionamiento simple: Configuración Inicialización y adquisición del dispositivo Lectura de entradas (en el Game-Loop) Liberado del dispositivo
botones Valores delta de las coordenadas Diferencia entre la posición anterior y la posición actual Los joysticks, track-pads, etc. se obtienen preguntando al sistema por los dispositivos de juego conectados. Una vez inicializados, funcionan de igual forma que un Mouse Para más información sobre la obtención de Joysticks, consultar el SDK
HLSL : Programación a bajo nivel con Shaders Animación de meshes, efectos, fog Sprites / gráficos 2D Networking, IA, Interfaz de usuario, diseño de videojuegos, … Para otra charla ;-)
in part or in whole without written permission of the author and the user group is prohibited The w ork contained in this presentation is show n AS IS w ithout any implied w arranty or liability for any damage derived from it use. All the expressions and opinions are personal and resposability of the speaker.