Запуск Unity WebGL с ASP.NET Core

Страница обновлена :
Дата создания страницы :

Среда верификации

Виндоус
  • Windows 11
Редактор Unity
  • 2020.3.25f1
Visual Studio
  • Visual Studio 2022
ASP.NET ядро
  • ASP.NET Core 6.0
Службы IIS
  • IIS 10.0

Сначала

Узнайте, как запустить вывод игры в формате WebGL в Unity на веб-сервере, работающем под управлением ASP.NET Core. Для игровых программ используйте те, которые выводятся в шагах советов ниже. В примере игры используется 2D-платформер Microgame, который можно создать из Unity Hub.

Я объясню, как настроить «Несжатый WebGL», «WebGL сжатый с помощью Gzip» и «WebGL сжатый с помощью Brotli» для запуска игр WebGL. Процедура одинакова для всех.

Мы используем Visual Studio 2022 ASP.NET Core 6.0, но, вероятно, будут работать более старые версии. Однако структура исходного кода различна для каждой версии, поэтому, пожалуйста, разберитесь в различиях самостоятельно.

Создание проекта ASP.NET Core

Запустите Visual Studio 2022 из меню «Пуск».

Выберите Создать новый проект.

На этот раз выберите «ASP.NET Core Web App» в качестве примера. Если вы работаете на ASP.NET Core, вы можете запускать другие шаблоны, но вам нужно будет следовать каждому шаблону, чтобы создать его.

Произвольно задайте имя и местоположение проекта.

Дополнительную информацию оставьте как есть.

Проект создан.

Запуск несжатого WebGL

Подготовьте программу WebGL, созданную без сжатия.

Убедитесь, что игра работает быстро

ASP.NET Попробуйте запустить игру WebGL с меньшим количеством настроек, не соблюдая основной этикет.

В ASP.NET Core вы не можете получить доступ к некоторым файлам WebGL, создаваемым Unity в состоянии по умолчанию. Сделайте это доступным.

Программа.cs

Откройте из проекта Program.cs . Относится к более ранним версиям Startup.cs ASP.NET Core.

Добавьте пространство имен в верхнюю часть кода и замените в нем app.UseStaticFiles(); следующее:

// ここから追加
using Microsoft.AspNetCore.StaticFiles;
// ここまで追加

var builder = WebApplication.CreateBuilder(args);

// --- 省略 ---

app.UseHttpsRedirection();

//app.UseStaticFiles();
// ここから追加
var provider = new FileExtensionContentTypeProvider();
provider.Mappings[".data"] = "application/octet-stream";
provider.Mappings[".wasm"] = "application/wasm";

app.UseStaticFiles(new StaticFileOptions()
{
  ContentTypeProvider = provider,
});
// ここまで追加

app.UseRouting();

// --- 省略 ---

.data, так что при доступе .wasm к файлу он может быть возвращен клиенту с указанным Content-Type .

Развертывание WebGL

Поместите в проект wwwroot следующие папки с файлами из Unity.

  • индекс.html
  • Строить
  • Данные шаблона

Index.cshtmlindex.html Откройте ссылку, чтобы получить к ней доступ.

<!-- 省略 -->

<div class="text-center">
    <h1 class="display-4">Welcome</h1>
    <p>Learn about <a href="https://docs.microsoft.com/aspnet/core">building Web apps with ASP.NET Core</a>.</p>
</div>

<!-- 追加 -->
<a href="index.html">index.html</a>

Запустите программу и убедитесь, что игра работает.

Запуск программы WebGL на странице Razor

Предыдущая игра запускалась на статическом HTML-файле, поэтому она работает в месте, которое не имеет ничего общего с ASP.NET Core. Это не очень желательно для единообразия программы, поэтому мы перенесем поведение HTML-файла в Razor Pages.

Щелкните правой кнопкой мыши папку Pages в проекте, чтобы добавить новый элемент.

Выберите Razor Page - Empty. Конкретное имя не указано, но оно добавлено сюда WebGL.cshtml .

Отобразится код.

index.html Обратитесь к содержимому файла и переносу в WebGL.cshtml . link Есть некоторые странные моменты, например, как разместить тег, но я оставлю все как есть ради простоты объяснения.

@page
@model UnityPublishWebglAspNetCore.Pages.WebGLModel
@{
}

<div id="unity-container" class="unity-desktop">
  <canvas id="unity-canvas" width=960 height=600></canvas>
  <div id="unity-loading-bar">
    <div id="unity-logo"></div>
    <div id="unity-progress-bar-empty">
      <div id="unity-progress-bar-full"></div>
    </div>
  </div>
  <div id="unity-warning"> </div>
  <div id="unity-footer">
    <div id="unity-webgl-logo"></div>
    <div id="unity-fullscreen-button"></div>
    <div id="unity-build-title">Platformer</div>
  </div>
</div>

@section Scripts {
  <link rel="shortcut icon" href="TemplateData/favicon.ico">
  <link rel="stylesheet" href="TemplateData/style.css">
  <script>
    var container = document.querySelector("#unity-container");
    var canvas = document.querySelector("#unity-canvas");
    var loadingBar = document.querySelector("#unity-loading-bar");
    var progressBarFull = document.querySelector("#unity-progress-bar-full");
    var fullscreenButton = document.querySelector("#unity-fullscreen-button");
    var warningBanner = document.querySelector("#unity-warning");

    // 一時的なメッセージバナー/リボンを数秒間表示するか、
    // type == 'error'の場合はキャンバスの上部に永続的なエラーメッセージを表示します。
    // type == 'warning'の場合、黄色のハイライト色が使用されます。
    // この関数を変更または削除して、重要ではない警告とエラーメッセージがユーザーに表示されるように
    // 視覚的に表示される方法をカスタマイズします。
    function unityShowBanner(msg, type) {
      function updateBannerVisibility() {
        warningBanner.style.display = warningBanner.children.length ? 'block' : 'none';
      }
      var div = document.createElement('div');
      div.innerHTML = msg;
      warningBanner.appendChild(div);
      if (type == 'error') div.style = 'background: red; padding: 10px;';
      else {
        if (type == 'warning') div.style = 'background: yellow; padding: 10px;';
        setTimeout(function() {
          warningBanner.removeChild(div);
          updateBannerVisibility();
        }, 5000);
      }
      updateBannerVisibility();
    }

    var buildUrl = "Build";
    var loaderUrl = buildUrl + "/WebGL.loader.js";
    var config = {
      dataUrl: buildUrl + "/WebGL.data",
      frameworkUrl: buildUrl + "/WebGL.framework.js",
      codeUrl: buildUrl + "/WebGL.wasm",
      streamingAssetsUrl: "StreamingAssets",
      companyName: "DefaultCompany",
      productName: "Platformer",
      productVersion: "2.1.0",
      showBanner: unityShowBanner,
    };

    // デフォルトでは、Unity は WebGL キャンバスレンダリングのターゲットサイズを
    // キャンバス要素の DOM サイズ(window.devicePixelRatio でスケーリング)と一致させます。
    // この同期がエンジン内で発生しないようにする場合は、これを false に設定し、
    // 代わりにサイズを大きくします。 キャンバスの DOM サイズと WebGL は、
    // ターゲットサイズを自分でレンダリングします。
    // config.matchWebGLToCanvasSize = false;

    if (/iPhone|iPad|iPod|Android/i.test(navigator.userAgent)) {
      container.className = "unity-mobile";
      // モバイルデバイスでフィルレートのパフォーマンスを低下させないようにし、
      // モバイルブラウザで低 DPI モードをデフォルト/オーバーライドします。
      config.devicePixelRatio = 1;
      unityShowBanner('WebGL builds are not supported on mobile devices.');
    } else {
      canvas.style.width = "960px";
      canvas.style.height = "600px";
    }
    loadingBar.style.display = "block";

    var script = document.createElement("script");
    script.src = loaderUrl;
    script.onload = () => {
      createUnityInstance(canvas, config, (progress) => {
        progressBarFull.style.width = 100 * progress + "%";
      }).then((unityInstance) => {
        loadingBar.style.display = "none";
        fullscreenButton.onclick = () => {
          unityInstance.SetFullscreen(1);
        };
      }).catch((message) => {
        alert(message);
      });
    };
    document.body.appendChild(script);
  </script>
}

Index.cshtmlWebGL Добавьте ссылку на .

<!-- 省略 -->

<div class="text-center">
    <h1 class="display-4">Welcome</h1>
    <p>Learn about <a href="https://docs.microsoft.com/aspnet/core">building Web apps with ASP.NET Core</a>.</p>
</div>

<!-- 追加 -->
<ul>
  <li><a href="index.html">index.html</a></li>
  <li><a href="WebGL">WebGL</a></li>
</ul>

Попробуйте запустить программу. Вы можете видеть, что верхний и нижний колонтитулы _Layout.cshtml отображаются на странице WebGL в соответствии с .

Изменение местоположения файлов WebGL

Я поместил файл WebGL непосредственно в , но этот метод перезапишет его, когда вы поместите два или более файлов WebGL wwwroot . Я объясню, как поместить это в отдельные папки и переместить.

Прежде всего, создайте новую папку под названием «webgl» и переместите ее туда. Две папки, которые необходимо переместить Build: , TemplateData . index.html Я уже портировал его на Razor Pages и могу безопасно удалить.

Поскольку WebGL.cshtml мы углубили иерархию папок, мы также углубим путь, описанный в . Коррекция составляет 3 строки.

Перед коррекцией

<link rel="shortcut icon" href="TemplateData/favicon.ico">
<link rel="stylesheet" href="TemplateData/style.css">
    var buildUrl = "Build";

После коррекции

<link rel="shortcut icon" href="webgl/TemplateData/favicon.ico">
<link rel="stylesheet" href="webgl/TemplateData/style.css">
    var buildUrl = "webgl/Build";

Запустите программу, чтобы убедиться, что она работает правильно.

Запуск WebGL, сжатого с помощью Gzip

Расширение файла, сжатого Gzip, - .gz , и это файл, который может быть обработан ASP.NET Core, Unity WebGL Content-Type и обрабатываются по-разному и требуют преобразования.

Во-первых, создайте развертывание файла WebGL и страницу.

Размещение файла WebGL

wwwrootwebgl-gzip Создайте папку в Gzip и скопируйте папку , из файла BuildTemplateData WebGL, созданного с помощью Gzip.

Создание страницы Razor

На этот раз WebGLGzip.cshtml создайте файл, используя ту же процедуру, что и при распаковке.

Код выглядит следующим образом со ссылкой на Output в index.html Unity. Путь совпадает с папкой, созданной webgl-gzip ранее для файлов WebGL.

@page
@model UnityPublishWebglAspNetCore.Pages.WebGLGzipModel
@{
}

<div id="unity-container" class="unity-desktop">
  <canvas id="unity-canvas" width=960 height=600></canvas>
  <div id="unity-loading-bar">
    <div id="unity-logo"></div>
    <div id="unity-progress-bar-empty">
      <div id="unity-progress-bar-full"></div>
    </div>
  </div>
  <div id="unity-warning"> </div>
  <div id="unity-footer">
    <div id="unity-webgl-logo"></div>
    <div id="unity-fullscreen-button"></div>
    <div id="unity-build-title">Platformer</div>
  </div>
</div>

@section Scripts {
  <link rel="shortcut icon" href="webgl-gzip/TemplateData/favicon.ico">
  <link rel="stylesheet" href="webgl-gzip/TemplateData/style.css">
  <script>
    var container = document.querySelector("#unity-container");
    var canvas = document.querySelector("#unity-canvas");
    var loadingBar = document.querySelector("#unity-loading-bar");
    var progressBarFull = document.querySelector("#unity-progress-bar-full");
    var fullscreenButton = document.querySelector("#unity-fullscreen-button");
    var warningBanner = document.querySelector("#unity-warning");

    // 一時的なメッセージバナー/リボンを数秒間表示するか、
    // type == 'error'の場合はキャンバスの上部に永続的なエラーメッセージを表示します。
    // type == 'warning'の場合、黄色のハイライト色が使用されます。
    // この関数を変更または削除して、重要ではない警告とエラーメッセージがユーザーに表示されるように
    // 視覚的に表示される方法をカスタマイズします。
    function unityShowBanner(msg, type) {
      function updateBannerVisibility() {
        warningBanner.style.display = warningBanner.children.length ? 'block' : 'none';
      }
      var div = document.createElement('div');
      div.innerHTML = msg;
      warningBanner.appendChild(div);
      if (type == 'error') div.style = 'background: red; padding: 10px;';
      else {
        if (type == 'warning') div.style = 'background: yellow; padding: 10px;';
        setTimeout(function() {
          warningBanner.removeChild(div);
          updateBannerVisibility();
        }, 5000);
      }
      updateBannerVisibility();
    }

    var buildUrl = "webgl-gzip/Build";
    var loaderUrl = buildUrl + "/WebGL_Gzip.loader.js";
    var config = {
      dataUrl: buildUrl + "/WebGL_Gzip.data.gz",
      frameworkUrl: buildUrl + "/WebGL_Gzip.framework.js.gz",
      codeUrl: buildUrl + "/WebGL_Gzip.wasm.gz",
      streamingAssetsUrl: "StreamingAssets",
      companyName: "DefaultCompany",
      productName: "Platformer",
      productVersion: "2.1.0",
      showBanner: unityShowBanner,
    };

    // デフォルトでは、Unity は WebGL キャンバスレンダリングのターゲットサイズを
    // キャンバス要素の DOM サイズ(window.devicePixelRatio でスケーリング)と一致させます。
    // この同期がエンジン内で発生しないようにする場合は、これを false に設定し、
    // 代わりにサイズを大きくします。 キャンバスの DOM サイズと WebGL は、
    // ターゲットサイズを自分でレンダリングします。
    // config.matchWebGLToCanvasSize = false;

    if (/iPhone|iPad|iPod|Android/i.test(navigator.userAgent)) {
      container.className = "unity-mobile";
      // モバイルデバイスでフィルレートのパフォーマンスを低下させないようにし、
      // モバイルブラウザで低 DPI モードをデフォルト/オーバーライドします。
      config.devicePixelRatio = 1;
      unityShowBanner('WebGL builds are not supported on mobile devices.');
    } else {
      canvas.style.width = "960px";
      canvas.style.height = "600px";
    }
    loadingBar.style.display = "block";

    var script = document.createElement("script");
    script.src = loaderUrl;
    script.onload = () => {
      createUnityInstance(canvas, config, (progress) => {
        progressBarFull.style.width = 100 * progress + "%";
      }).then((unityInstance) => {
        loadingBar.style.display = "none";
        fullscreenButton.onclick = () => {
          unityInstance.SetFullscreen(1);
        };
      }).catch((message) => {
        alert(message);
      });
    };
    document.body.appendChild(script);
  </script>
}

Изменяйте, чтобы разрешить переход на Index.cshtml эту страницу.

<!-- 省略 -->

<div class="text-center">
    <h1 class="display-4">Welcome</h1>
    <p>Learn about <a href="https://docs.microsoft.com/aspnet/core">building Web apps with ASP.NET Core</a>.</p>
</div>

<!-- 追加 -->
<ul>
  <li><a href="index.html">index.html</a></li>
  <li><a href="WebGL">WebGL</a></li>
  <li><a href="WebGLGzip">WebGLGzip</a></li>
</ul>

Программа исправления.cs

app.UseStaticFiles Измените часть, обрабатывающую метод, следующим образом.

Перед коррекцией

// ここから追加
var provider = new FileExtensionContentTypeProvider();
provider.Mappings[".data"] = "application/octet-stream";
provider.Mappings[".wasm"] = "application/wasm";

app.UseStaticFiles(new StaticFileOptions()
{
  ContentTypeProvider = provider,
});
// ここまで追加

После коррекции

// ここから追加
var provider = new FileExtensionContentTypeProvider();
provider.Mappings[".data"] = "application/octet-stream";
provider.Mappings[".wasm"] = "application/wasm";
provider.Mappings[".br"] = "application/octet-stream";   // .br ファイルにアクセスできるように追加
provider.Mappings[".js"] = "application/javascript";     // 後の変換の為に追加

app.UseStaticFiles(new StaticFileOptions()
{
  ContentTypeProvider = provider,
  OnPrepareResponse = context =>
  {
    var path = context.Context.Request.Path.Value;
    var extension = Path.GetExtension(path);

    // 「.gz」「.br」ファイルにアクセスした場合は Content-Type と Content-Encoding を設定する
    if (extension == ".gz" || extension == ".br")
    {
      var fileNameWithoutExtension = Path.GetFileNameWithoutExtension(path) ?? "";
      if (provider.TryGetContentType(fileNameWithoutExtension, out string? contentType))
      {
        context.Context.Response.ContentType = contentType;
        context.Context.Response.Headers.Add("Content-Encoding", extension == ".gz" ? "gzip" : "br");
      }
    }
  },
});
// ここまで追加

В ASP.NET Core .gz файл Content-Type application/x-gzip возвращается с расширением . Как бы то ни было, Unity WebGL на клиенте не может его определить, поэтому .gz я переписываю и возвращаю его в соответствии с Content-Type расширением файла, исключающим . Content-Encoding Я его тоже поставил, потому что так gzip надо.

Кстати, я также собрал код Brotli, так что вы можете использовать этот код в том виде, в каком он есть в соответствии Brotli следующего элемента. Brotli также .br устанавливает перезапись Content-Encoding br в соответствии с Content-Type расширением файла без . Однако файл недоступен по умолчанию в ASP.NET Core,.br поэтому provider.Mappings я добавил его с .br помощью .

После этого запустите отладку и проверьте, корректно ли работает игра.

Если вы настроили его правильно, но игра по-прежнему не отображается, попробуйте очистить кэш веб-браузера, чтобы очистить файлы cookie.

Запуск WebGL, сжатого с помощью Brotli

Процедура почти такая же, как и у Gzip, заменяя часть Gzip на Brotli. Однако файлы Brotli (.br) по умолчанию недоступны в ASP.NET Core. Вам нужно настроить его так, чтобы вы могли получить к нему доступ, но если вы используете код во время Gzip, он поддерживается.

Во-первых, создайте развертывание файла WebGL и страницу.

Размещение файла WebGL

wwwrootwebgl-brotli В разделе Создание папки скопируйте папку , из файла WebGL, созданного BuildTemplateData с помощью Brotli.

Создание страницы Razor

Создайте файл, выполнив WebGLBrotli.cshtml те же действия, что и для Gzip.

Код выглядит следующим образом со ссылкой на Output в index.html Unity. Путь совпадает с папкой, созданной webgl-brotli ранее для файлов WebGL.

@page
@model UnityPublishWebglAspNetCore.Pages.WebGLBrotliModel
@{
}

<div id="unity-container" class="unity-desktop">
  <canvas id="unity-canvas" width=960 height=600></canvas>
  <div id="unity-loading-bar">
    <div id="unity-logo"></div>
    <div id="unity-progress-bar-empty">
      <div id="unity-progress-bar-full"></div>
    </div>
  </div>
  <div id="unity-warning"> </div>
  <div id="unity-footer">
    <div id="unity-webgl-logo"></div>
    <div id="unity-fullscreen-button"></div>
    <div id="unity-build-title">Platformer</div>
  </div>
</div>

@section Scripts {
  <link rel="shortcut icon" href="webgl-brotli/TemplateData/favicon.ico">
  <link rel="stylesheet" href="webgl-brotli/TemplateData/style.css">
  <script>
    var container = document.querySelector("#unity-container");
    var canvas = document.querySelector("#unity-canvas");
    var loadingBar = document.querySelector("#unity-loading-bar");
    var progressBarFull = document.querySelector("#unity-progress-bar-full");
    var fullscreenButton = document.querySelector("#unity-fullscreen-button");
    var warningBanner = document.querySelector("#unity-warning");

    // 一時的なメッセージバナー/リボンを数秒間表示するか、
    // type == 'error'の場合はキャンバスの上部に永続的なエラーメッセージを表示します。
    // type == 'warning'の場合、黄色のハイライト色が使用されます。
    // この関数を変更または削除して、重要ではない警告とエラーメッセージがユーザーに表示されるように
    // 視覚的に表示される方法をカスタマイズします。
    function unityShowBanner(msg, type) {
      function updateBannerVisibility() {
        warningBanner.style.display = warningBanner.children.length ? 'block' : 'none';
      }
      var div = document.createElement('div');
      div.innerHTML = msg;
      warningBanner.appendChild(div);
      if (type == 'error') div.style = 'background: red; padding: 10px;';
      else {
        if (type == 'warning') div.style = 'background: yellow; padding: 10px;';
        setTimeout(function() {
          warningBanner.removeChild(div);
          updateBannerVisibility();
        }, 5000);
      }
      updateBannerVisibility();
    }

    var buildUrl = "webgl-brotli/Build";
    var loaderUrl = buildUrl + "/WebGL_Brotli.loader.js";
    var config = {
      dataUrl: buildUrl + "/WebGL_Brotli.data.br",
      frameworkUrl: buildUrl + "/WebGL_Brotli.framework.js.br",
      codeUrl: buildUrl + "/WebGL_Brotli.wasm.br",
      streamingAssetsUrl: "StreamingAssets",
      companyName: "DefaultCompany",
      productName: "Platformer",
      productVersion: "2.1.0",
      showBanner: unityShowBanner,
    };

    // デフォルトでは、Unity は WebGL キャンバスレンダリングのターゲットサイズを
    // キャンバス要素の DOM サイズ(window.devicePixelRatio でスケーリング)と一致させます。
    // この同期がエンジン内で発生しないようにする場合は、これを false に設定し、
    // 代わりにサイズを大きくします。 キャンバスの DOM サイズと WebGL は、
    // ターゲットサイズを自分でレンダリングします。
    // config.matchWebGLToCanvasSize = false;

    if (/iPhone|iPad|iPod|Android/i.test(navigator.userAgent)) {
      container.className = "unity-mobile";
      // モバイルデバイスでフィルレートのパフォーマンスを低下させないようにし、
      // モバイルブラウザで低 DPI モードをデフォルト/オーバーライドします。
      config.devicePixelRatio = 1;
      unityShowBanner('WebGL builds are not supported on mobile devices.');
    } else {
      canvas.style.width = "960px";
      canvas.style.height = "600px";
    }
    loadingBar.style.display = "block";

    var script = document.createElement("script");
    script.src = loaderUrl;
    script.onload = () => {
      createUnityInstance(canvas, config, (progress) => {
        progressBarFull.style.width = 100 * progress + "%";
      }).then((unityInstance) => {
        loadingBar.style.display = "none";
        fullscreenButton.onclick = () => {
          unityInstance.SetFullscreen(1);
        };
      }).catch((message) => {
        alert(message);
      });
    };
    document.body.appendChild(script);
  </script>
}

Изменяйте, чтобы разрешить переход на Index.cshtml эту страницу.

<!-- 省略 -->

<div class="text-center">
    <h1 class="display-4">Welcome</h1>
    <p>Learn about <a href="https://docs.microsoft.com/aspnet/core">building Web apps with ASP.NET Core</a>.</p>
</div>

<!-- 追加 -->
<ul>
  <li><a href="index.html">index.html</a></li>
  <li><a href="WebGL">WebGL</a></li>
  <li><a href="WebGLGzip">WebGLGzip</a></li>
  <li><a href="WebGLBrotli">WebGLBrotli</a></li>
</ul>

Программа исправления.cs

Если вы измените его при поддержке Gzip, вы сможете использовать тот же код.

После исправления запустите отладку и проверьте, работает ли игра.

Если вы настроили его правильно, но игра по-прежнему не отображается, попробуйте очистить кэш веб-браузера, чтобы очистить файлы cookie.

Общие сведения о симптомах доступа к файлам Brotli на веб-сервере IIS

Brotli не поддерживается IIS по умолчанию, поэтому требуется настройка на стороне IIS. Кажется, что с этим можно справиться, выполнив расширенные настройки, но я не буду объяснять это в этом совете. Пожалуйста, ознакомьтесь с информацией, указанной ниже.

сообщение об ошибке

Unable to load file webgl-brotli/Build/WebGL_Brotli.framework.js.br! Check that the file exists on the remote server. (also check browser Console and Devtools Network tab to debug)