Не рендерится прямоугольник DirectX C#
Делаю аркадный космический 3D симулятор на DirectX C# средствами SharpDX. Основную часть сделал, осталось только реализовать интерфейс пользователя. По требованию HUD необходимо реализовать средствами Direct3D. HUD элементарный: должен включать в себя главное меню, представленное задним фоном(прямоугольник, растянутый на весь экран) и две прямоугольных кнопки "Начать игру" и "Выйти из игры". Понятно, что нужно просто нарисовать три прямоугольника, которые будут иметь позицию, размер и определённый цвет(с текстурами решил не заморачиваться и просто покрасить их в цвета). Я создал вершинный шейдер:
cbuffer ConstantBuffer : register(b0)
{
matrix worldViewProjectionMatrix;
};
struct VertexInput
{
float2 position : POSITION;
float4 color : COLOR;
};
struct VertexOutput
{
float4 position : SV_POSITION;
float4 color : COLOR;
};
VertexOutput main(VertexInput input)
{
VertexOutput output;
// Преобразование позиции вершины
output.position = mul(float4(input.position, 0.0f, 1.0f), worldViewProjectionMatrix);
// Передача цвета вершины
output.color = input.color;
return output;
}
И пиксельный шейдер
struct PixelInput
{
float4 position : SV_POSITION; // Позиция пикселя в пространстве экрана
float4 color : COLOR; // Цвет пикселя
};
float4 main(PixelInput input) : SV_Target
{
return input.color;
}
Далее создал класс HUDRenderer:
using SharpDX;
using SharpDX.D3DCompiler;
using SharpDX.Direct3D11;
using SharpDX.DXGI;
using System;
using System.Runtime.InteropServices;
using static SimpleDXApp.Renderer;
using Buffer = SharpDX.Direct3D11.Buffer;
namespace SimpleDXApp
{
public class HUDRenderer : IDisposable
{
private DirectX3DGraphics _directX3DGraphics;
private DeviceContext _deviceContext;
private VertexShader _vertexShader;
private PixelShader _pixelShader;
private ShaderSignature _shaderSignature;
private InputLayout _inputLayout;
[StructLayout(LayoutKind.Sequential)]
public struct VertexDataStruct
{
public Vector2 position;
public Color4 color;
}
public HUDRenderer(DirectX3DGraphics directX3DGraphics)
{
_directX3DGraphics = directX3DGraphics;
_deviceContext = _directX3DGraphics.DeviceContext;
// Компиляция и создание вершинного шейдера
var vertexShaderByteCode = ShaderBytecode.CompileFromFile("HUD/hud_vertex.hlsl", "main", "vs_5_0");
_vertexShader = new VertexShader(_directX3DGraphics.Device, vertexShaderByteCode);
_shaderSignature = ShaderSignature.GetInputSignature(vertexShaderByteCode);
_inputLayout = new InputLayout(_directX3DGraphics.Device, _shaderSignature, new[]
{
new InputElement("POSITION", 0, SharpDX.DXGI.Format.R32G32_Float, 0, 0),
new InputElement("COLOR", 0, SharpDX.DXGI.Format.R32G32B32A32_Float, 8, 0)
});
_deviceContext.InputAssembler.InputLayout = _inputLayout;
_deviceContext.VertexShader.Set(_vertexShader);
// Компиляция и создание пиксельного шейдера
var pixelShaderByteCode = ShaderBytecode.CompileFromFile("HUD/hud_pixel.hlsl", "main", "ps_5_0");
_pixelShader = new PixelShader(_directX3DGraphics.Device, pixelShaderByteCode);
_deviceContext.PixelShader.Set(_pixelShader);
// Очистка ресурсов шейдеров
Utilities.Dispose(ref vertexShaderByteCode);
Utilities.Dispose(ref pixelShaderByteCode);
}
public void Dispose()
{
// Освобождение ресурсов
Utilities.Dispose(ref _inputLayout);
Utilities.Dispose(ref _shaderSignature);
Utilities.Dispose(ref _vertexShader);
Utilities.Dispose(ref _pixelShader);
}
public void BeginRender()
{
_directX3DGraphics.ClearBuffers(Color.Transparent);
}
public void EndRender()
{
_directX3DGraphics.SwapChain.Present(1, PresentFlags.Restart);
}
public void DrawRectangle(Vector2 position, Vector2 size, Color4 color)
{
VertexDataStruct[] vertices = new VertexDataStruct[4]
{
new VertexDataStruct { position = new Vector2(position.X, position.Y), color = color },
new VertexDataStruct { position = new Vector2(position.X + size.X, position.Y), color = color },
new VertexDataStruct { position = new Vector2(position.X, position.Y - size.Y), color = color },
new VertexDataStruct { position = new Vector2(position.X + size.X, position.Y - size.Y), color = color }
};
// Создание вершинного буфера
using (var vertexBuffer = Buffer.Create(_directX3DGraphics.Device, BindFlags.VertexBuffer, vertices))
{
// Установка вершинного буфера
_deviceContext.InputAssembler.SetVertexBuffers(0, new VertexBufferBinding(vertexBuffer, Utilities.SizeOf<VertexDataStruct>(), 0));
// Установка примитивного типа
_deviceContext.InputAssembler.PrimitiveTopology = SharpDX.Direct3D.PrimitiveTopology.TriangleStrip;
// Отрисовка прямоугольника
_deviceContext.Draw(vertices.Length, 0);
}
}
}
}
В классе Game создал экземпляр этого класса и попытался нарисовать прямоугольник следующим образом:
_hudRenderer.BeginRender();
_hudRenderer.DrawRectangle(new Vector2(10, 10), new Vector2(800, 600), new Color4(1, 1, 0, 1));
_hudRenderer.EndRender();
Но при запуске вижу просто черный экран, ничего не рисуется. Но почему? Понимаю, что код, может, неграмотный и надо было бы создать класс для элементов HUD, но вопрос в другом: почему не рендерится? Скидываю полный код класса Game:
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Media.Effects;
using SharpDX;
using SharpDX.Direct3D;
using SharpDX.Direct3D11;
using Device = SharpDX.Direct3D11.Device;
using Buffer = SharpDX.Direct3D11.Buffer;
using SharpDX.DirectInput;
using SharpDX.Windows;
using ObjLoader.Loader.Loaders;
using static SimpleDXApp.Renderer;
using System.Windows.Media.Media3D;
using System.Windows.Forms;
using System.Text.RegularExpressions;
using System.Timers;
using Rectangle = SharpDX.Rectangle;
using SharpDX.Direct2D1;
using ObjLoader.Loader.Data.VertexData;
using SharpDX.DXGI;
using System.Drawing;
using RectangleF = SharpDX.RectangleF;
using FeatureLevel = SharpDX.Direct3D.FeatureLevel;
using DeviceContext = SharpDX.Direct3D11.DeviceContext;
using Color = SharpDX.Color;
using SharpDX.D3DCompiler;
using System.Numerics;
using Vector2 = SharpDX.Vector2;
using Vector3 = SharpDX.Vector3;
using Vector4 = SharpDX.Vector4;
using NAudio.CoreAudioApi;
using System.Windows;
namespace SimpleDXApp
{
public class Game : IDisposable
{
private RenderForm _renderForm;
private List<MeshObject> _planets = new List<MeshObject>(); //планеты
private List<Vector4> _planetVelocities = new List<Vector4>();
private List<MeshObject> _asteroids = new List<MeshObject>();
private float _timeSinceLastPlanet = 0.0f;
private float _planetSpawnInterval = 5.0f; // Интервал появления планет в секундах
private Camera _camera;
Texture _squareAntiprismTexture; //Текстура планеты
Texture _backgroundTexture; //Текстура фона
Texture _boarderTexture; //Текстура границы
private Texture _asteroidTexture; //Текстура астероида
protected DirectX3DGraphics _directX3DGraphics;
protected DirectX3DGraphics _directX3DGraphicsHUD;
protected Renderer _renderer;
private TimeHelper _timeHelper;
private DInput _dInput;
private float sceneSize = 10000.0f; //Размер сцены
private MeshObject _spaceship;
private Texture _spaceshipTexture;
private BoundingSphere _spaceshipCollider;
private MeshObject _spaceshipColliderObject;
private BoundingSphere _planetCollider;
private BoundingSphere _asteroidCollider;
private float movementSpeed = 3f;
private bool canControlSpaceship = true;
private Vector3 spaceshipVelocity = Vector3.Zero;
private MeshObject _bullet;
private BoundingSphere _bulletCollider;
private Texture _bulletTexture;
static bool accelerationAvailable = false;
private AudioManager audioManager; //Музыка
private bool audio = false; //Звук полёта
MeshObject _skybox;
List<MeshObject> _colliders = new List<MeshObject>();
List<BoundingSphere> _planetColliders = new List<BoundingSphere>();
List<BoundingSphere> _asteroidColliders = new List<BoundingSphere>();
List<MeshObject> _planetCollidersObjects = new List<MeshObject>();
//Физические константы
private const float planetMass = 9500000000000000f;
private const float asteroidMass = 15f;
private const float spaceshipMass = 1f;
//HUD
private HUDRenderer _hudRenderer;
//Звуковые ффекты
private AudioManager asteroidDestruction;
//Визуальные эффекты
public Game()
{
_renderForm = new RenderForm("FPS: ");
_renderForm.WindowState = FormWindowState.Maximized;
_renderForm.FormBorderStyle = FormBorderStyle.None;
_dInput = new DInput(_renderForm);
_renderForm.UserResized += RenderFormResizedCallback;
_directX3DGraphics = new DirectX3DGraphics(_renderForm);
_directX3DGraphicsHUD = new DirectX3DGraphics(_renderForm);
_renderer = new Renderer(_directX3DGraphics);
_renderer.CreateConstantBuffer();
_hudRenderer = new HUDRenderer(_directX3DGraphicsHUD);
Loader loader = new Loader(_directX3DGraphics);
_backgroundTexture = loader.LoadTextureFromFile("images/space2.jpg", _renderer.AnisotropicSampler);
_boarderTexture = loader.LoadTextureFromFile("images/boarder.png", _renderer.AnisotropicSampler);
_spaceshipTexture = loader.LoadTextureFromFile("images/spaceship.jpg", _renderer.AnisotropicSampler);
_squareAntiprismTexture = loader.LoadTextureFromFile("images/planet.png", _renderer.AnisotropicSampler);
_asteroidTexture = loader.LoadTextureFromFile("images/asteroid.png", _renderer.AnisotropicSampler);
_bulletTexture = loader.LoadTextureFromFile("images/laser.jpg", _renderer.AnisotropicSampler);
_camera = new Camera(new Vector4(0.0f, 2.0f, -3.1f, 1.0f));
_timeHelper = new TimeHelper();
loader.Dispose();
loader = null;
Background();
AddSpaceship();
AccelerationTimer();
audioManager = new AudioManager("Assets/Sounds/BackgroundMusic.mp3");
audioManager.Play();
//Cursor.Hide();
}
public void RenderFormResizedCallback(object sender, EventArgs args)
{
_directX3DGraphics.Resize();
_camera.Aspect = _renderForm.ClientSize.Width /
(float)_renderForm.ClientSize.Height;
}
private bool _firstRun = true;
private bool _renderGameContent = false;
public void RenderLoopCallback()
{
FormOptions();
if (_renderGameContent)
{
// Вызов методов для обновления игровой логики
Collisions();
ApplyGravity();
SpaceShipControl();
PlanetSpawner();
Shot();
if (accelerationAvailable) UseAcceleration();
// Рендеринг игрового контента
Render();
}
else
{
// Рендеринг только HUD
DrawHUD();
}
}
private void DrawHUD()
{
_hudRenderer.BeginRender();
_hudRenderer.DrawRectangle(new Vector2(10, 10), new Vector2(800, 600), new Color4(1, 1, 0, 1));
_hudRenderer.EndRender();
}
private void FormOptions()
{
_dInput.UpdateKeyboardState();
_dInput.UpdateMouseState();
if (_firstRun)
{
RenderFormResizedCallback(this, EventArgs.Empty);
_firstRun = false;
}
_timeHelper.Update();
_renderForm.Text = "FPS: ";
if (_dInput.KeyboardState.IsPressed(Key.Escape)) _renderForm.Close();
}
public void Run()
{
RenderLoop.Run(_renderForm, RenderLoopCallback);
}
public void Dispose()
{
//_bullet.Dispose();
foreach (var asteroid in _asteroids)
{
asteroid.Dispose();
}
_spaceship.Dispose();
_squareAntiprismTexture.Dispose();
_renderer.Dispose();
_hudRenderer.Dispose();
_directX3DGraphics.Dispose();
}
//Остальные методы, не имеющие отношения к HUD не были включены в код
}
}