Загрузка ресурсов в игре DirectX
Большинство игр, в некоторых точках, загружают ресурсы и ресурсы (например, шейдеры, текстуры, предопределенные сетки или другие графические данные) из локального хранилища или другого потока данных. Здесь мы рассмотрим высокоуровневое представление о том, что необходимо учитывать при загрузке этих файлов для использования в игре DirectX C/C++ универсальная платформа Windows (UWP).
Например, сетки для многоугольников в игре могли быть созданы с помощью другого инструмента и экспортированы в определенный формат. То же самое верно для текстур, и тем более: в то время как плоская, несжатая растровая карта может быть обычно написана большинством инструментов и понятна большинством графических API, она может быть чрезвычайно неэффективной для использования в вашей игре. Здесь мы рассмотрим основные шаги по загрузке трех различных типов графических ресурсов для использования с Direct3D: сетками (моделями), текстурами (растровыми изображениями) и скомпилированных объектов шейдера.
Это важно знать
Технологии
- Библиотека параллельных шаблонов (ppltasks.h)
Необходимые компоненты
- Основные среда выполнения Windows
- Общие сведения об асинхронных задачах
- Ознакомьтесь с основными понятиями трехмерного программирования графики.
Этот пример также содержит три файла кода для загрузки ресурсов и управления ими. В этом разделе вы увидите объекты кода, определенные в этих файлах.
- BasicLoader.h/.cpp
- BasicReaderWriter.h/.cpp
- DDSTextureLoader.h/.cpp
Полный код для этих примеров можно найти по следующим ссылкам.
Полный код для класса и методов, которые преобразуют и загружают объекты графической сетки в память.
Полный код для класса и методов для чтения и записи двоичных файлов данных в целом. Используется классом BasicLoader .
Полный код для класса и метода, который загружает текстуру DDS из памяти.
Instructions
Асинхронная загрузка
Асинхронная загрузка обрабатывается с помощью шаблона задачи из библиотеки параллельных шаблонов (PPL). Задача содержит вызов метода, за которым следует лямбда-код, который обрабатывает результаты асинхронного вызова после завершения и обычно соответствует формату:
task(async code to execute).then((parameters for lambda)< lambda code contents >); .
Задачи можно объединить с помощью синтаксиса .then(), чтобы при завершении одной операции можно выполнить другую асинхронную операцию, зависящую от результатов предыдущей операции. Таким образом, вы можете загружать, преобразовывать и управлять сложными ресурсами в отдельных потоках таким образом, что он почти невидим для проигрывателя.
Теперь рассмотрим базовую структуру для объявления и создания асинхронного метода загрузки файлов ReadDataAsync .
#include // . concurrency::task^> ReadDataAsync( _In_ Platform::String^ filename); // . using concurrency; task^> BasicReaderWriter::ReadDataAsync( _In_ Platform::String^ filename ) < return task(m_location->GetFileAsync(filename)).then([=](StorageFile^ file) < return FileIO::ReadBufferAsync(file); >).then([=](IBuffer^ buffer) < auto fileData = ref new Platform::Array(buffer->Length); DataReader::FromBuffer(buffer)->ReadBytes(fileData); return fileData; >); >
В этом коде при вызове метода ReadDataAsync, определенного выше, создается задача для чтения буфера из файловой системы. Завершив работу, задача с цепочкой принимает буфер и передает байты из этого буфера в массив с помощью статического типа DataReader .
m_basicReaderWriter = ref new BasicReaderWriter(); // . return m_basicReaderWriter->ReadDataAsync(filename).then([=](const Platform::Array^ bytecode) < // Perform some operation with the data when the async load completes. >);
Вот вызов readDataAsync. По завершении код получает массив байтов, считываемых из предоставленного файла. Так как функция ReadDataAsync определена как задача, можно использовать лямбда-операцию для выполнения определенной операции при возврате массива байтов, например передачу данных байтов в функцию DirectX, которая может использовать ее.
Если ваша игра достаточно проста, загрузите ресурсы с помощью такого метода, как это, когда пользователь запускает игру. Это можно сделать перед началом основного цикла игры с некоторой точки в последовательности вызовов реализации IFrameworkView::Run . Опять же, вы вызываете методы загрузки ресурсов асинхронно, чтобы игра может начаться быстрее, и поэтому игроку не придется ждать завершения загрузки, прежде чем участвовать в ранних взаимодействиях.
Однако вы не хотите запускать игру правильно, пока не завершится все асинхронная загрузка! Создайте некоторый метод для сигнала при завершении загрузки, например определенное поле, и используйте лямбда-файлы в методах загрузки, чтобы задать этот сигнал после завершения. Перед запуском всех компонентов, использующих загруженные ресурсы, проверьте переменную.
Ниже приведен пример использования асинхронных методов, определенных в BasicLoader.cpp для загрузки шейдеров, сетки и текстуры при запуске игры. Обратите внимание, что оно задает определенное поле для объекта игры, m_loadingComplete, когда все методы загрузки завершены.
void ResourceLoading::CreateDeviceResources() < // DirectXBase is a common sample class that implements a basic view provider. DirectXBase::CreateDeviceResources(); // . // This flag will keep track of whether or not all application // resources have been loaded. Until all resources are loaded, // only the sample overlay will be drawn on the screen. m_loadingComplete = false; // Create a BasicLoader, and use it to asynchronously load all // application resources. When an output value becomes non-null, // this indicates that the asynchronous operation has completed. BasicLoader^ loader = ref new BasicLoader(m_d3dDevice.Get()); auto loadVertexShaderTask = loader->LoadShaderAsync( "SimpleVertexShader.cso", nullptr, 0, &m_vertexShader, &m_inputLayout ); auto loadPixelShaderTask = loader->LoadShaderAsync( "SimplePixelShader.cso", &m_pixelShader ); auto loadTextureTask = loader->LoadTextureAsync( "reftexture.dds", nullptr, &m_textureSRV ); auto loadMeshTask = loader->LoadMeshAsync( "refmesh.vbo", &m_vertexBuffer, &m_indexBuffer, nullptr, &m_indexCount ); // The && operator can be used to create a single task that represents // a group of multiple tasks. The new task's completed handler will only // be called once all associated tasks have completed. In this case, the // new task represents a task to load various assets from the package. (loadVertexShaderTask && loadPixelShaderTask && loadTextureTask && loadMeshTask).then([=]() < m_loadingComplete = true; >); // Create constant buffers and other graphics device-specific resources here. >
Обратите внимание, что задачи были агрегированы с помощью оператора &>, чтобы лямбда-код, задающий флаг завершения загрузки, активируется только после завершения всех задач. Обратите внимание, что если у вас несколько флагов, у вас есть возможность гонки условий. Например, если лямбда-файл устанавливает два флага последовательно в одно и то же значение, другой поток может видеть только первый набор флагов, если он проверяет их до установки второго флага.
Вы узнали, как асинхронно загружать файлы ресурсов. Синхронные загрузки файлов гораздо проще, и вы можете найти примеры из них в полном коде для BasicReaderWriter и Полного кода для BasicLoader.
Конечно, различные типы ресурсов и ресурсов часто требуют дополнительной обработки или преобразования, прежде чем они будут готовы к использованию в графическом конвейере. Рассмотрим три конкретных типа ресурсов: сетки, текстуры и шейдеры.
Загрузка сетки
Сетки — это данные вершин, которые создаются процедурно по коду в игре или экспортируются в файл из другого приложения (например, 3DStudio MAX или Alias WaveFront) или средства. Эти сетки представляют модели в игре, от простых примитивов, таких как куби и сферы до автомобилей и домов и символов. Они часто содержат данные цвета и анимации, а также в зависимости от их формата. Мы сосредоточимся на сетках, содержащих только данные вершин.
Чтобы правильно загрузить сетку, необходимо знать формат данных в файле сетки. Наш простой тип BasicReaderWriter выше просто считывает данные в виде потока байтов. Он не знает, что данные байтов представляют сетку, гораздо меньше определенного формата сетки, как экспортируется другим приложением! При переносе данных сетки в память необходимо выполнить преобразование.
(Вы всегда должны пытаться упаковать данные активов в формате, который максимально близок к внутреннему представлению. Это приведет к снижению использования ресурсов и экономии времени.)
Давайте получим данные байтов из файла сетки. В этом примере предполагается, что файл является суффиксом конкретного формата с помощью VBO. (Опять же, этот формат не совпадает с форматом VBO OpenGL.) Каждая вершина сопоставляется с типом BasicVertex , который является структурой, определенной в коде для средства преобразователя obj2vbo. Макет данных вершин в VBO-файле выглядит следующим образом:
- Первые 32 бита (4 байта) потока данных содержат количество вершин (numVertices) в сетке, представленное как значение uint32.
- Следующие 32 бита (4 байта) потока данных содержат количество индексов в сетке (numIndices), представленное как значение uint32.
- После этого последующие биты (numVertices * sizeof(BasicVertex)) содержат данные вершин.
- Последние (numIndices * 16) биты данных содержат данные индекса, представленные в виде последовательности значений uint16.
Это так: знают макет битового уровня загруженных данных сетки. Кроме того, убедитесь, что вы согласованы с эндиан-ness. Все платформы Windows 8 являются маленькими.
В примере вы вызываете метод CreateMesh из метода LoadMeshAsync для выполнения этой интерпретации битового уровня.
task BasicLoader::LoadMeshAsync( _In_ Platform::String^ filename, _Out_ ID3D11Buffer** vertexBuffer, _Out_ ID3D11Buffer** indexBuffer, _Out_opt_ uint32* vertexCount, _Out_opt_ uint32* indexCount ) < return m_basicReaderWriter->ReadDataAsync(filename).then([=](const Platform::Array^ meshData) < CreateMesh( meshData->Data, vertexBuffer, indexBuffer, vertexCount, indexCount, filename ); >); >
CreateMesh интерпретирует данные байтов, загруженные из файла, и создает буфер вершин и буфер индекса для сетки путем передачи списков вершин и индексов соответственно в ID3D11Device::CreateBuffer и указание D3D11_BIND_VERTEX_BUFFER или D3D11_BIND_INDEX_BUFFER. Ниже приведен код, используемый в BasicLoader:
void BasicLoader::CreateMesh( _In_ byte* meshData, _Out_ ID3D11Buffer** vertexBuffer, _Out_ ID3D11Buffer** indexBuffer, _Out_opt_ uint32* vertexCount, _Out_opt_ uint32* indexCount, _In_opt_ Platform::String^ debugName ) < // The first 4 bytes of the BasicMesh format define the number of vertices in the mesh. uint32 numVertices = *reinterpret_cast(meshData); // The following 4 bytes define the number of indices in the mesh. uint32 numIndices = *reinterpret_cast(meshData + sizeof(uint32)); // The next segment of the BasicMesh format contains the vertices of the mesh. BasicVertex* vertices = reinterpret_cast(meshData + sizeof(uint32) * 2); // The last segment of the BasicMesh format contains the indices of the mesh. uint16* indices = reinterpret_cast(meshData + sizeof(uint32) * 2 + sizeof(BasicVertex) * numVertices); // Create the vertex and index buffers with the mesh data. D3D11_SUBRESOURCE_DATA vertexBufferData = ; vertexBufferData.pSysMem = vertices; vertexBufferData.SysMemPitch = 0; vertexBufferData.SysMemSlicePitch = 0; CD3D11_BUFFER_DESC vertexBufferDesc(numVertices * sizeof(BasicVertex), D3D11_BIND_VERTEX_BUFFER); m_d3dDevice->CreateBuffer( &vertexBufferDesc, &vertexBufferData, vertexBuffer ); D3D11_SUBRESOURCE_DATA indexBufferData = ; indexBufferData.pSysMem = indices; indexBufferData.SysMemPitch = 0; indexBufferData.SysMemSlicePitch = 0; CD3D11_BUFFER_DESC indexBufferDesc(numIndices * sizeof(uint16), D3D11_BIND_INDEX_BUFFER); m_d3dDevice->CreateBuffer( &indexBufferDesc, &indexBufferData, indexBuffer ); if (vertexCount != nullptr) < *vertexCount = numVertices; >if (indexCount != nullptr) < *indexCount = numIndices; >>
Обычно вы создаете пару буферов вершин и индекса для каждой сетки, используемой в игре. Где и когда вы загружаете сетки. Если у вас много сеток, может потребоваться только загрузить некоторые из диска в определенных точках игры, например во время определенных предопределенных состояний загрузки. Для больших сеток, таких как данные ландшафта, можно передавать вершины из кэша, но это более сложная процедура, а не в область этой статьи.
Опять же, знают формат данных вершины! Существует множество способов представления данных вершин в средствах, используемых для создания моделей. Существует также множество различных способов представления входного макета данных вершин в Direct3D, таких как списки треугольников и полосы. Дополнительные сведения о данных вершин см. в статье «Введение в буферы» в Direct3D 11 и «Примитивные».
Далее рассмотрим загрузку текстур.
Загрузка текстур
Наиболее распространенный ресурс в игре ( и тот, который состоит из большинства файлов на диске и в памяти), являются текстурами. Как и сетки, текстуры могут поступать в различных форматах, и вы преобразуете их в формат, который Direct3D может использовать при их загрузке. Текстуры также имеют широкий спектр типов и используются для создания различных эффектов. Уровни MIP для текстур можно использовать для улучшения внешнего вида и производительности объектов расстояния; карты грязи и света используются для слоя эффектов и детализации на основе базовой текстуры; и обычные карты используются в вычислениях освещения на пиксель. В современной игре типичные сцены могут иметь тысячи отдельных текстур, и код должен эффективно управлять ими.
Кроме того, как сетки, существуют ряд конкретных форматов, используемых для эффективного использования памяти. Так как текстуры могут легко использовать большую часть памяти GPU (и системы), они часто сжимаются в некотором порядке. Вам не требуется использовать сжатие для текстур игры, и вы можете использовать любые алгоритмы сжатия и декомпрессии, если вы предоставляете шейдеры Direct3D с данными в формате, который он может понять (например, растровое изображение Texture2D ).
Direct3D поддерживает алгоритмы сжатия текстур DXT, хотя каждый формат DXT не поддерживается в графическом оборудовании проигрывателя. Файлы DDS содержат текстуры DXT (и другие форматы сжатия текстур) и суффиксируются с DDS.
DDS-файл — это двоичный файл, содержащий следующие сведения:
- DWORD (магическое число), содержащее четыре значения кода символа DDS (0x20534444).
- Описание данных в файле. Данные описываются с описанием заголовка с помощью DDS_HEADER; формат пикселя определяется с помощью DDS_PIXELFORMAT. Обратите внимание, что структуры DDS_HEADER и DDS_PIXELFORMAT заменяют устаревшие структуры DDSURFACEDESC2, DDSCAPS2 и DDPIXELFORMAT DirectDraw 7. DDS_HEADER является двоичным эквивалентом DDSURFACEDESC2 и DDSCAPS2. DDS_PIXELFORMAT является двоичным эквивалентом DDPIXELFORMAT.
DWORD dwMagic; DDS_HEADER header;
Если для значений dwFlags в DDS_PIXELFORMAT задано значение DDPF_FOURCC и dwFourCC задано значение DX10, DDS_HEADER_DXT10 для размещения массивов текстур или форматов DXGI, которые не могут быть выражены как форматы пикселей RGB, такие как форматы с плавающей запятой, форматы sRGB и т. д. Когда DDS_HEADER_DXT10 структура присутствует, все описание данных будет выглядеть следующим образом.
DWORD dwMagic; DDS_HEADER header; DDS_HEADER_DXT10 header10;
BYTE bdata[]
BYTE bdata2[]
Многие средства экспортируются в формат DDS. Если у вас нет инструмента для экспорта текстуры в этот формат, попробуйте создать его. Дополнительные сведения о формате DDS и его работе в коде см . в руководстве по программированию для DDS. В нашем примере мы будем использовать DDS.
Как и в случае с другими типами ресурсов, вы считываете данные из файла в виде потока байтов. После завершения задачи загрузки лямбда-вызов запускает код ( метод CreateTexture ), чтобы обработать поток байтов в формате, который Direct3D может использовать.
task BasicLoader::LoadTextureAsync( _In_ Platform::String^ filename, _Out_opt_ ID3D11Texture2D** texture, _Out_opt_ ID3D11ShaderResourceView** textureView ) < return m_basicReaderWriter->ReadDataAsync(filename).then([=](const Platform::Array^ textureData) < CreateTexture( GetExtension(filename) == "dds", textureData->Data, textureData->Length, texture, textureView, filename ); >); >
В предыдущем фрагменте лямбда-проверка, чтобы узнать, имеет ли имя файла расширение dds. Если это так, предполагается, что это текстура DDS. Если нет, используйте API компонента образов Windows (WIC), чтобы обнаружить формат и декодировать данные в виде растрового изображения. В любом случае результатом является растровое изображение Texture2D (или ошибка).
void BasicLoader::CreateTexture( _In_ bool decodeAsDDS, _In_reads_bytes_(dataSize) byte* data, _In_ uint32 dataSize, _Out_opt_ ID3D11Texture2D** texture, _Out_opt_ ID3D11ShaderResourceView** textureView, _In_opt_ Platform::String^ debugName ) < ComPtrshaderResourceView; ComPtr texture2D; if (decodeAsDDS) < ComPtrresource; if (textureView == nullptr) < CreateDDSTextureFromMemory( m_d3dDevice.Get(), data, dataSize, &resource, nullptr ); >else < CreateDDSTextureFromMemory( m_d3dDevice.Get(), data, dataSize, &resource, &shaderResourceView ); >resource.As(&texture2D); > else < if (m_wicFactory.Get() == nullptr) < // A WIC factory object is required in order to load texture // assets stored in non-DDS formats. If BasicLoader was not // initialized with one, create one as needed. CoCreateInstance( CLSID_WICImagingFactory, nullptr, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&m_wicFactory)); >ComPtr stream; m_wicFactory->CreateStream(&stream); stream->InitializeFromMemory( data, dataSize); ComPtr bitmapDecoder; m_wicFactory->CreateDecoderFromStream( stream.Get(), nullptr, WICDecodeMetadataCacheOnDemand, &bitmapDecoder); ComPtr bitmapFrame; bitmapDecoder->GetFrame(0, &bitmapFrame); ComPtr formatConverter; m_wicFactory->CreateFormatConverter(&formatConverter); formatConverter->Initialize( bitmapFrame.Get(), GUID_WICPixelFormat32bppPBGRA, WICBitmapDitherTypeNone, nullptr, 0.0, WICBitmapPaletteTypeCustom); uint32 width; uint32 height; bitmapFrame->GetSize(&width, &height); std::unique_ptr bitmapPixels(new byte[width * height * 4]); formatConverter->CopyPixels( nullptr, width * 4, width * height * 4, bitmapPixels.get()); D3D11_SUBRESOURCE_DATA initialData; ZeroMemory(&initialData, sizeof(initialData)); initialData.pSysMem = bitmapPixels.get(); initialData.SysMemPitch = width * 4; initialData.SysMemSlicePitch = 0; CD3D11_TEXTURE2D_DESC textureDesc( DXGI_FORMAT_B8G8R8A8_UNORM, width, height, 1, 1 ); m_d3dDevice->CreateTexture2D( &textureDesc, &initialData, &texture2D); if (textureView != nullptr) < CD3D11_SHADER_RESOURCE_VIEW_DESC shaderResourceViewDesc( texture2D.Get(), D3D11_SRV_DIMENSION_TEXTURE2D ); m_d3dDevice->CreateShaderResourceView( texture2D.Get(), &shaderResourceViewDesc, &shaderResourceView); > > if (texture != nullptr) < *texture = texture2D.Detach(); >if (textureView != nullptr) < *textureView = shaderResourceView.Detach(); >>
После завершения этого кода у вас есть текстура2D в памяти, загруженная из файла изображения. Как и с сетками, у вас, вероятно, много из них в вашей игре и в любой конкретной сцене. Рекомендуется создавать кэши для регулярного доступа к текстурам на сцену или на уровне, а не загружать их все при запуске игры или уровня.
(The Метод CreateDDSTextureFromMemory , вызываемого в приведенном выше примере, можно просмотреть полностью в полном коде для DDSTextureLoader.)
Кроме того, отдельные текстуры или текстуры «кожи» могут сопоставляться с конкретными многоугольниками сетки или поверхностями. Обычно эти данные сопоставления экспортируются художником или дизайнером, используемым для создания модели и текстур. Убедитесь, что эти сведения также записываются при загрузке экспортированных данных, так как при выполнении затенения фрагментов используются правильные текстуры с соответствующими поверхностями.
Загрузка шейдеров
Шейдеры компилируют файлы языка шейдеров высокого уровня (HLSL), которые загружаются в память и вызываются на определенных этапах графического конвейера. Наиболее распространенными и важными шейдерами являются вершины и шейдеры пикселей, которые обрабатывают отдельные вершины сетки и пиксели в окнах просмотра сцены соответственно. Код HLSL выполняется для преобразования геометрии, применения эффектов освещения и текстур и выполнения после обработки на отрисованной сцене.
Игра Direct3D может иметь несколько различных шейдеров, каждый из которых компилируется в отдельный CSO-файл (скомпилированный объект шейдера, CSO). Как правило, у вас не так много, что вам нужно загружать их динамически, и в большинстве случаев вы можете просто загрузить их при запуске игры или на уровне (например, шейдер для эффектов дождя).
Код в классе BasicLoader предоставляет ряд перегрузок для различных шейдеров, включая вершины, геометрию, пиксель и шейдеры корпуса. Приведенный ниже код охватывает шейдеры пикселей в качестве примера. (Полный код можно просмотреть в Полный код для BasicLoader.)
concurrency::task LoadShaderAsync( _In_ Platform::String^ filename, _Out_ ID3D11PixelShader** shader ); // . task BasicLoader::LoadShaderAsync( _In_ Platform::String^ filename, _Out_ ID3D11PixelShader** shader ) < return m_basicReaderWriter->ReadDataAsync(filename).then([=](const Platform::Array^ bytecode) < m_d3dDevice->CreatePixelShader( bytecode->Data, bytecode->Length, nullptr, shader); >); >
В этом примере экземпляр BasicReaderWriter (m_basicReaderWriter) используется для чтения в предоставленном файле скомпилированного шейдера (CSO) в виде потока байтов. После завершения этой задачи лямбда-код вызывает ID3D11Device::CreatePixelShader с данными байтов, загруженными из файла. Обратный вызов должен задать некоторый флаг, указывающий на успешность загрузки, и код должен проверка этот флаг перед запуском шейдера.
Вершинные шейдеры немного сложнее. Для шейдера вершин также загружается отдельный входной макет, определяющий данные вершин. Следующий код можно использовать для асинхронной загрузки шейдера вершин вместе с пользовательским макетом входных данных вершин. Убедитесь, что данные вершин, загруженные из сетки, могут быть правильно представлены этим макетом входных данных!
Создадим входной макет перед загрузкой шейдера вершин.
void BasicLoader::CreateInputLayout( _In_reads_bytes_(bytecodeSize) byte* bytecode, _In_ uint32 bytecodeSize, _In_reads_opt_(layoutDescNumElements) D3D11_INPUT_ELEMENT_DESC* layoutDesc, _In_ uint32 layoutDescNumElements, _Out_ ID3D11InputLayout** layout ) < if (layoutDesc == nullptr) < // If no input layout is specified, use the BasicVertex layout. const D3D11_INPUT_ELEMENT_DESC basicVertexLayoutDesc[] = < < "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0 >, < "NORMAL", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 12, D3D11_INPUT_PER_VERTEX_DATA, 0 >, < "TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 24, D3D11_INPUT_PER_VERTEX_DATA, 0 >, >; m_d3dDevice->CreateInputLayout( basicVertexLayoutDesc, ARRAYSIZE(basicVertexLayoutDesc), bytecode, bytecodeSize, layout); > else < m_d3dDevice->CreateInputLayout( layoutDesc, layoutDescNumElements, bytecode, bytecodeSize, layout); > >
В этом конкретном макете каждая вершина имеет следующие данные, обработанные шейдером вершин:
- Положение координат 3D (x, y, z) в пространстве координат модели, представленное в виде трио 32-разрядных значений с плавающей запятой.
- Обычный вектор вершины, который также представлен тремя 32-разрядными значениями с плавающей запятой.
- Преобразованное 2D-значение координат текстуры (u, v), представленное в виде пары 32-разрядных значений с плавающей запятой.
Эти входные элементы на вершине называются семантикой HLSL, и они представляют собой набор определенных регистров, используемых для передачи данных и из скомпилированного объекта шейдера. Конвейер запускает шейдер вершин один раз для каждой вершины в сетке, которую вы загрузили. Семантика определяет входные данные (и выходные данные из) шейдера вершин при выполнении и предоставляет эти данные для вычислений вершин в коде HLSL шейдера.
Теперь загрузите объект шейдера вершин.
concurrency::task LoadShaderAsync( _In_ Platform::String^ filename, _In_reads_opt_(layoutDescNumElements) D3D11_INPUT_ELEMENT_DESC layoutDesc[], _In_ uint32 layoutDescNumElements, _Out_ ID3D11VertexShader** shader, _Out_opt_ ID3D11InputLayout** layout ); // . task BasicLoader::LoadShaderAsync( _In_ Platform::String^ filename, _In_reads_opt_(layoutDescNumElements) D3D11_INPUT_ELEMENT_DESC layoutDesc[], _In_ uint32 layoutDescNumElements, _Out_ ID3D11VertexShader** shader, _Out_opt_ ID3D11InputLayout** layout ) < // This method assumes that the lifetime of input arguments may be shorter // than the duration of this task. In order to ensure accurate results, a // copy of all arguments passed by pointer must be made. The method then // ensures that the lifetime of the copied data exceeds that of the task. // Create copies of the layoutDesc array as well as the SemanticName strings, // both of which are pointers to data whose lifetimes may be shorter than that // of this method's task. shared_ptr> layoutDescCopy; shared_ptr> layoutDescSemanticNamesCopy; if (layoutDesc != nullptr) < layoutDescCopy.reset( new vector( layoutDesc, layoutDesc + layoutDescNumElements ) ); layoutDescSemanticNamesCopy.reset( new vector(layoutDescNumElements) ); for (uint32 i = 0; i < layoutDescNumElements; i++) < layoutDescSemanticNamesCopy->at(i).assign(layoutDesc[i].SemanticName); > > return m_basicReaderWriter->ReadDataAsync(filename).then([=](const Platform::Array^ bytecode) < m_d3dDevice->CreateVertexShader( bytecode->Data, bytecode->Length, nullptr, shader); if (layout != nullptr) < if (layoutDesc != nullptr) < // Reassign the SemanticName elements of the layoutDesc array copy to point // to the corresponding copied strings. Performing the assignment inside the // lambda body ensures that the lambda will take a reference to the shared_ptr // that holds the data. This will guarantee that the data is still valid when // CreateInputLayout is called. for (uint32 i = 0; i < layoutDescNumElements; i++) < layoutDescCopy->at(i).SemanticName = layoutDescSemanticNamesCopy->at(i).c_str(); > > CreateInputLayout( bytecode->Data, bytecode->Length, layoutDesc == nullptr ? nullptr : layoutDescCopy->data(), layoutDescNumElements, layout); > >); >
В этом коде после чтения в данных байтов для CSO-файла вершинного шейдера создайте шейдер вершин путем вызова ID3D11Device::CreateVertexShader . После этого создайте макет ввода для шейдера в той же лямбда-лямбда-схеме.
Другие шейдеры, такие как шейдеры корпуса и геометрии, также могут требовать определенную конфигурацию. Полный код для различных методов загрузки шейдера представлен в полном коде для BasicLoader и в примере загрузки ресурсов Direct3D.
Замечания
На этом этапе вы должны понимать и иметь возможность создавать или изменять методы асинхронной загрузки общих игровых ресурсов и ресурсов, таких как сетки, текстуры и скомпилированные шейдеры.
См. также
- Пример загрузки ресурсов Direct3D
- Полный код для BasicLoader
- Полный код для BasicReaderWriter
- Полный код для DDSTextureLoader
Как очистить место на диске Windows 11
Операционная система Windows 11 теперь может сообщать какие файлы и приложения нужно очистить, чтобы освободить место на диске вашего компьютера. Наша инструкция покажет как использовать новую функцию рекомендаций по очистке.
Windows 11 поставляется с функцией «рекомендаций по очистке», предназначенной для автоматизации процесса определения содержимого и может помочь освободить место на диске компьютера.
Новинка автоматически определяет и отображает данные которые могут быть очищены. Удалению подлежат большие или неиспользуемые файлы, забытые приложения или бесхозные копии файлов.
Как очистить место на диске Windows 11
1. Откройте параметры через меню «Пуск«.
2. Выберите категорию «Система» и зайдите в раздел «Память«.
3. Под заголовком «Управление хранилищем» выберите пункт «Рекомендации по очистке«.
4. Отметьте временные файлы, больше не используемые, файлы синхронизации с облаком, неиспользуемые приложения и нажмите кнопку «Очистить«.
5. Чтобы освободить еще больше пространства, вернитесь обратно в категорию «Память» и пройдите в раздел «Временные файлы«.
6. И удалите на ваше усмотрение:
- Файлы обновлений Windows.
- Файлы оптимизации доставки.
- Временные файлы.
- Базы средства просмотра диагностических данных.
- Эскизы.
- Антивирусная программа Microsoft Defender.
- Отчеты об ошибках.
- Загрузки.
- Кэш построителя текстуры DirectX.
После выполнения всех действий, у вас будет больше места на диске для хранения других важных файлов, и в зависимости от объема удаленных данных, производительность дисковой подсистемы компьютера под управлением операционной системы Windows 11 должна немного улучшиться.
Рекомендуемый контент
Windows 10 включает инструмент для быстрого анализа и выяснения того, как используется пространство диска, помогая определить, что можно удалить и высвободить место.
Windows 10
Читать подробнее
Когда в Safari возникают трудности с загрузкой страниц или авторизацией на веб-ресурсах, наша инструкция по очистке кэша и файлов cookie должна помочь вам избавится от проблемы.
Читать подробнее
Если вы установили обновление Windows 10 2022 Update версия 22H2 с помощью ISO-файла поверх или другим доступным способом и не обнаружили проблем, то пришло время очистить занимаемое пространство на диске предыдущей версией
Windows 10
Читать подробнее
При возникновении трудностей с отображением или входом на сайты, используйте наше руководство по очистке данных веб-браузера Opera, для устранения проблемы.
Читать подробнее
Windows 10 отображает часто используемые папки и последние файлы в быстром доступе при открытии проводника. Эта функция может быть полезна, если вам необходим быстрый доступ к ресурсам. Но может и раздражать, когда вы
Как освободить место на диске в Microsoft Windows
Узнайте, как освободить пространство на диске компьютера. Включает удаление временных файлов, теневых копий и т. д.
Сводка: Узнайте, как освободить пространство на диске компьютера. Включает удаление временных файлов, теневых копий и т. д.
- Содержание статьи
- Свойства статьи
- Оцените эту статью
Возможно, эта статья была переведена автоматически. Если вы хотите поделиться своим мнением о ее качестве, используйте форму обратной связи в нижней части страницы.
Содержание статьи
Инструкции
Узнайте, как освободить место на жестком диске компьютера в Microsoft Windows. Если на компьютере недостаточно свободного места, можно заметить следующие признаки: ошибка недостаточного места на диске, ошибка заполнения диска, не удается установить важные обновления Windows, предупреждение о том, что на диске осталось менее 10% свободного места, недостаточно места на диске в разделе и другие ошибки.
Запустите программу очистки диска
Microsoft Windows имеет интегрированный инструмент, который удаляет временные файлы и другие неважные данные. Чтобы удалить временные файлы с помощью программы очистки диска в Windows, выполните следующие действия.
- Нажмите Пуск.
- Найдите приложение Очистка диска и нажмите, чтобы открыть его.
- Если в компьютере имеется несколько накопителей или разделов, в раскрывающемся меню «Диски» выберите диск (C:).
- Нажмите OK.
- Нажмите Очистка системных файлов.
- Если в компьютере имеется несколько накопителей или разделов, в раскрывающемся меню «Диски» выберите диск (C:).
- Нажмите OK.
- Проверьте все содержимое, которое необходимо удалить, чтобы освободить место, в том числе следующее:
Примечание.: Список компонентов может отличаться в зависимости от установки.- Антивирусная программа Защитник Windows
- Файлы журнала модернизации Windows
- Временные файлы Интернета
- Файлы отчетов об ошибках Windows, созданные системой
- Кэш построителя текстуры DirectX
- Файлы оптимизации доставки
- Пакеты драйверов устройства
- Файлы языковых ресурсов
- Предыдущие установки Windows
- Корзина
- Временные файлы
- Временные файлы установки Windows
- Эскизы
- Нажмите OK.
- Нажмите Удалить файлы.
Удаление восстановления системы и теневых копий с помощью программы очистки диска
Утилита очистки диска помогает удалить старые файлы восстановления системы для высвобождения дополнительного места в хранилище. Чтобы удалить точки восстановления системы, за исключением последней, выполните следующие действия.
- Нажмите Пуск.
- Найдите приложение Очистка диска и нажмите, чтобы открыть его.
- Если в компьютере имеется несколько накопителей или разделов, в раскрывающемся меню «Диски» выберите диск (C:).
- Нажмите OK.
- Нажмите Очистка системных файлов.
- Если в компьютере имеется несколько накопителей или разделов, в раскрывающемся меню «Диски» выберите диск (C:).
- Нажмите OK.
- Щелкните вкладку Дополнительные параметры.
- В разделе Восстановление системы и теневые копии нажмите Очистить.
- Нажмите Удалить.
Освобождение места на диске с помощью контроля памяти (Windows 10)
Контроль памяти в Windows 10 помогает удалять временные файлы с диска компьютера, а также с дополнительных или внешних дисков. Чтобы освободить место на диске с помощью контроля памяти, выполните следующие действия.
- Нажмите кнопку Пуск и откройте приложение Параметры
- Нажмите Система.
- Нажмите Хранилище.
- Переведите переключатель контроля памяти во включенное положение.
- В разделе Хранилище нажмите Настроить контроль памяти или запустить его сейчас.
- В разделе Временные файлы установите флажок Удалить временные файлы, которые не используются приложениями.
- Нажмите Очистить сейчас.
Чтобы удалить временные файлы с помощью контроля памяти, выполните следующие действия.
- Нажмите кнопку Пуск и откройте приложение Параметры
- Нажмите Система.
- Нажмите Хранилище.
- В разделе «Локальный диск (C:)» нажмите Временные файлы.
- Проверьте все содержимое, которое необходимо удалить, чтобы освободить место, в том числе следующее:
Примечание.: Список компонентов может отличаться в зависимости от установки.- Антивирусная программа Защитник Windows
- Файлы журнала модернизации Windows
- Временные файлы Интернета
- Файлы отчетов об ошибках Windows, созданные системой
- Кэш построителя текстуры DirectX
- Файлы оптимизации доставки
- Пакеты драйверов устройства
- Файлы языковых ресурсов
- Предыдущие установки Windows
- Корзина
- Временные файлы
- Временные файлы установки Windows
- Эскизы
- Нажмите Удалить файлы.
Удаление неважных приложений и игр
Удаление неважных приложений — это еще один способ высвобождения дополнительного места в хранилище на компьютере. Чтобы удалить приложения или игры, выполните следующие действия.
- Нажмите кнопку Пуск и откройте приложение Параметры
- Нажмите Приложения.
- Нажмите Приложения и функции.
- Щелкните фильтр Сортировать по и выберите вид Размер, чтобы быстро определить приложения и игры, которые занимают большего всего места.
- Выберите ненужное приложение или игру.
- Нажмите Удалить.
- Следуйте инструкциям на экране, чтобы выполнить удаление.
- Повторите эти действия, чтобы удалить другие неважные приложения и игры.
- После удаления всех неважных приложений и игр перезагрузите компьютер.
Перенос личных данных на внешний жесткий диск
Личные файлы, такие как изображения, видео, музыка, документы и т. д., могут занимать много места на жестком диске. Перемещение таких больших файлов на внешний диск позволяет освободить место на жестком диске.
- Подключите к компьютеру внешний диск, например USB-накопитель.
- Нажмите кнопку Пуск и откройте Проводник.
- Перейдите в папку с файлами, которые необходимо переместить.
- Выберите файлы, перейдите на вкладку Главная, затем нажмите Переместить в и нажмите Выбрать местоположение.
- Выберите подключенный внешний диск, затем нажмите Переместить.
Сохранение новых личных файлов на другой жесткий диск
Сохранение новых файлов на другой диск помогает предотвратить проблемы с нехваткой места на диске. Вместо сохранения всех новых файлов на диске по умолчанию (C:\) можно сохранить некоторые крупные файлы на другой диск, на котором больше свободного места.
- Подключите к компьютеру внешний диск, например USB-накопитель.
- Нажмите кнопку Пуск и откройте приложение Параметры
- Нажмите Система и выберите Хранилище.
- В разделе Дополнительные настройки хранилища выберите Изменить место сохранения нового содержимого.
- Для каждого типа файлов выберите диск из раскрывающегося меню.
Отключение гибернации в Windows
Функция гибернации в Windows сохраняет данные из памяти на жестком диске, позволяя завершить работу компьютера, сохраняя текущий сеанс. Благодаря этому вы можете продолжить работу с того момента, на котором остановились, при повторном включении компьютера. Для сохранения информации в файле hiberfil.sys требуется значительное пространство на жестком диске. Если на компьютере заканчивается свободное место, отключение функции гибернации позволяет освободить дополнительное пространство для хранения критически важных файлов.
- Нажмите Пуск.
- Найдите командную строку, нажмите правой кнопкой мыши на значок командной строки и выберите Запуск от имени администратора.
- Введите следующую команду, чтобы отключить гибернацию, и нажмите клавишу Enter: powercfg /hibernate off
- Перезапустите компьютер.
Сканирование компьютера с помощью антивирусного программного обеспечения
Вирус или другое вредоносное ПО может занимать значительное пространство на жестком диске, повреждая системные файлы. Сканирование компьютера с помощью антивирусного приложения, например Защитника Windows, McAfee, Norton, помогает удалить зараженные файлы с компьютера.
Дополнительная информация
Рекомендованные статьи
Ниже приведены некоторые рекомендованные статьи по этой теме, которые могут вас заинтересовать.
- Общие рекомендации по техническому обслуживанию компьютера Dell
- Как устранить снижение производительности
- Свободное дисковое пространство для устранения проблемы «Недостаточно места на диске»
Свойства статьи
Затронутый продукт
Alienware, Inspiron, OptiPlex, Vostro, XPS, G Series, G Series, Alienware, Inspiron, Latitude, Vostro, XPS
Я отчищаю диск С, что можно удалить?
1.Отчиска обновлений Windows
2.Windows Defender Antivirus
3.Файлы журнала обновлений Windows
4.Загруженные файлы программ
5.Временные файлы интернета
6.Файлы дампа памяти для системных ошибок
7.Файлы мини-дампа для системных ошибок
8.Диагностические данные, полученные. чем-то там
9.Кэш построителя текстуры DirectX
10.Файлы оптимизации доставки
11.Пакеты драйверов устройств
12.Загрузки (но загрузки не надо трогать)
13.Файлы языковых ресурсов
14.Корзина
15.Временные файлы
16.Временные файлы установки Windows
17.Эскизы
Голосование за лучший ответ
Всё это хлам и это можно удалять.
Как освободить место на диске С
https://www.youtube.com/watch?v=uCGoANYcUCI
10 способов освободить место на диске «С»
https://www.youtube.com/watch?v=-vDj_Td_jOs
Очистка диска и оптимизация Windows 10, МАКСИМАЛЬНАЯ ОЧИСТКА диска С от ХЛАМА
https://www.youtube.com/watch?v=boij7txHtUU
4, 5, 6, 7, 14, 15, 16, 17
ЕгорЗнаток (495) 2 года назад
А можно удалить контрольные точки восстановления?
Князь Мыслитель (5234) Егор Синявцев, не могу сказать точно
все в труху!
В «Очистка диска» можно удалить хоть всё вообще. Лично я-бы оставил кэши и эскизы, что-бы потом не ждать пока новые создадутся (но если с ними есть проблема или слишком уж мало места, можно и их удалить).
ЕгорЗнаток (495) 2 года назад
А можно удалить контрольные точки восстановления?
Eternally Against Искусственный Интеллект (239061) Егор Синявцев,