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

Сторінка оновлюється :
Дата створення сторінки :

Середовище перевірки

Вікна
  • вікна 11
Редактор єдності
  • 2020.3.25f1
Visual Studio
  • Visual Studio 2022
ASP.NET Core
  • ASP.NET Core 6.0
Інформаційні служби Інтернету (IIS)
  • IIS 10.0

Спочатку

Дізнайтеся, як запустити вихід гри як WebGL в Unity на веб-сервері, на якому запущено ASP.NET Core. Для ігрових програм використовуйте ті, що виводяться в підказках нижче. У прикладі гри використовується мікрогра 2D Platformer, яку можна створити з Unity Hub.

Я поясню, як налаштувати "Unsimed WebGL", "WebGL, стиснута за допомогою Gzip" та "WebGL, стиснута за допомогою Brotli" для запуску ігор WebGL. Процедура однакова для всіх них.

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

Створення ASP.NET основного проекту

Запустіть "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
  • Будувати
  • TemplateData

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.

Клацніть правою кнопкою миші папку Сторінки у проекті, щоб додати новий елемент.

Виберіть Сторінка бритви - Порожня. Конкретне ім'я не вказано, але воно додано тут 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.

Створення сторінки бритви

Цього разу WebGLGzip.cshtml створіть файл, використовуючи ту саму процедуру, що й у нестисненому.

Код виглядає наступним чином з посиланням на Output in 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 встановлює rewrite 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.

Створення сторінки бритви

Створіть файл, використовуючи ті ж кроки, що WebGLBrotli.cshtml і для Gzip.

Код виглядає наступним чином з посиланням на Output in 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, ви можете використовувати той самий код.

Після її виправлення запустіть debug і перевірте, чи працює гра.

Якщо ви налаштували її правильно, але гра все одно не відображається, спробуйте очистити кеш веб-браузера, щоб очистити файли cookie.

Загальні відомості про проблеми доступу до файлів Brotli на веб-сервері IIS

Служба IIS типово не підтримує Brotli, тому необхідне налаштування на стороні служб 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)