Запуск 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.cshtml
index.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.cshtml
WebGL
Додайте посилання на .
<!-- 省略 -->
<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
wwwroot
webgl-gzip
Створіть папку під Gzip і скопіюйте папку , з файлу Build
TemplateData
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
wwwroot
webgl-brotli
У розділі Створити папку скопіюйте папку , з файлу WebGL, створеного Build
TemplateData
за допомогою 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. Начебто з цим можна впоратися, зробивши розширені настройки, але я не буду пояснювати це в цій пораді. Будь ласка, зверніться до інформації, посилання на яку наведено нижче.
- asp.net ядро 2.2 стиснення бротлі не працює на IIS?
- Огляд стиснення служб IIS
- WebGL: зразок коду конфігурації сервера
- WebGL - розгортання стислих збірок
Повідомлення про помилку
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)