Executando o Unity WebGL com ASP.NET Core
Ambiente de verificação
- Windows
-
- Janelas 11
- Unity Editor
-
- 25.3.2020F1
- Estúdio Visual
-
- Visual Studio 2022
- ASP.NET Núcleo
-
- ASP.NET Core 6.0
- Serviços de Informações da Internet (IIS)
-
- IIS 10.0
Inicialmente
Saiba como executar uma saída de jogo como WebGL no Unity em um servidor Web executando o ASP.NET Core. Para programas de jogos, use a saída nas etapas de dicas abaixo. O exemplo de jogo usa o Microgame de plataforma 2D, que pode ser criado a partir do Unity Hub.
Vou explicar como configurar "WebGL descompactado", "WebGL compactado com Gzip" e "WebGL compactado com Brotli" para rodar jogos WebGL. O procedimento é o mesmo para todos eles.
Estamos usando o Visual Studio 2022, ASP.NET Core 6.0, mas versões mais antigas provavelmente funcionarão. No entanto, a estrutura do código inicial é diferente para cada versão, portanto, entenda as diferenças.
Criando um projeto ASP.NET Core
Inicie o "Visual Studio 2022" no menu Iniciar.
Selecione Criar novo projeto.
Desta vez, selecione "ASP.NET Core Web App" como exemplo. Se você estiver executando no ASP.NET Core, poderá executar outros modelos, mas precisará seguir cada modelo sobre como criá-lo.
Defina o nome e o local do projeto arbitrariamente.
Deixe as informações adicionais como estão.
O projeto foi criado.
Executar WebGL descompactado
Prepare um programa WebGL criado sem compactação.
Certifique-se de que o jogo funciona rapidamente
ASP.NET Tente executar um jogo WebGL com menos configurações sem seguir a etiqueta principal.
No ASP.NET Core, você não pode acessar alguns arquivos WebGL emitidos pelo Unity no estado padrão. Torne isso acessível.
Programação.cs
Abra a partir do seu Program.cs
projeto. Aplica-se a versões Startup.cs
anteriores do ASP.NET Core.
Adicione um namespace à parte superior do código e substitua o seguinte no código 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
, para que, quando um arquivo for acessado, .wasm
ele possa ser retornado ao cliente com o arquivo .Content-Type
Implantação do WebGL
Coloque as seguintes pastas de arquivos do Unity em seu projeto wwwroot
.
- índice.html
- Construir
- TemplateData
Index.cshtml
index.html
Abra o link para que você possa acessá-lo.
<!-- 省略 -->
<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>
Execute o programa e certifique-se de que o jogo funciona.
Executar um programa WebGL em uma página do Razor
O jogo anterior rodava em um arquivo HTML estático, então ele roda em um lugar que não tem nada a ver com ASP.NET Core. Não é muito desejável para uniformidade de programa, então vamos mover o comportamento do arquivo HTML para Razor Pages.
Clique com o botão direito do mouse na pasta Páginas do seu projeto para adicionar um novo item.
Selecione Página do Razor - Vazia. Não há nenhum nome específico especificado, mas ele é adicionado aqui WebGL.cshtml
.
O código é exibido.
index.html
Consulte o conteúdo do arquivo e a porta para WebGL.cshtml
.
link
Existem alguns pontos estranhos, como a forma de colocar a tag, mas vou deixá-la como está por uma questão de simplicidade de explicação.
@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
Adicione um link para o .
<!-- 省略 -->
<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>
Tente executar o programa. Você pode ver que o cabeçalho e o rodapé _Layout.cshtml
são exibidos na página WebGL de acordo com o .
Alterar o local dos arquivos WebGL
Eu coloquei o arquivo WebGL diretamente sob , mas esse método irá substituí-lo quando você colocar dois ou mais arquivos WebGL wwwroot
.
Vou explicar como colocar isso em pastas separadas e movê-lo.
Primeiro de tudo, crie uma nova pasta chamada "webgl" e mova-a para lá. As duas pastas a Build
serem movidas são , TemplateData
.
index.html
Eu já o portei para o Razor Pages e posso excluí-lo com segurança.
Uma vez que WebGL.cshtml
aprofundamos a hierarquia de pastas, também aprofundaremos o caminho descrito em . A correção é de 3 linhas.
Antes da correção
<link rel="shortcut icon" href="TemplateData/favicon.ico">
<link rel="stylesheet" href="TemplateData/style.css">
var buildUrl = "Build";
Após correção
<link rel="shortcut icon" href="webgl/TemplateData/favicon.ico">
<link rel="stylesheet" href="webgl/TemplateData/style.css">
var buildUrl = "webgl/Build";
Execute o programa para ver se ele funciona corretamente.
Executando WebGL compactado com Gzip
A extensão do arquivo compactado pelo Gzip é , e é .gz
um arquivo que pode ser manipulado pelo ASP.NET Core,
Unity WebGL Content-Type
e são tratados de forma diferente e exigem conversão.
Primeiro, crie uma página e implantação de arquivo WebGL.
Posicionamento do arquivo WebGL
wwwroot
webgl-gzip
Crie uma pasta em Gzip e copie a pasta , do arquivo Build
TemplateData
WebGL que você criou com o Gzip.
Criar uma página do Razor
Desta vez WebGLGzip.cshtml
, crie o arquivo usando o mesmo procedimento de quando descompactado.
O código é o seguinte com referência a Saída em index.html
Unity.
O caminho corresponde à pasta criada webgl-gzip
anteriormente para os arquivos 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>
}
Modificar para permitir a navegação para Index.cshtml
esta página.
<!-- 省略 -->
<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>
Programa de fixação.cs
app.UseStaticFiles
Modifique a parte que está processando o método da seguinte maneira.
Antes da correção
// ここから追加
var provider = new FileExtensionContentTypeProvider();
provider.Mappings[".data"] = "application/octet-stream";
provider.Mappings[".wasm"] = "application/wasm";
app.UseStaticFiles(new StaticFileOptions()
{
ContentTypeProvider = provider,
});
// ここまで追加
Após correção
// ここから追加
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");
}
}
},
});
// ここまで追加
No ASP.NET Core .gz
, o arquivo Content-Type
application/x-gzip
retorna com .
Como é, Unity WebGL no cliente não pode determiná-lo, então .gz
eu reescrevo-o e devolvo-o de acordo Content-Type
com a extensão do arquivo que exclui .
Content-Encoding
Eu também defini porque gzip
é necessário.
A propósito, eu também coloquei o código Brotli junto, para que você possa usar esse código como está na correspondência Brotli do próximo item.
Brotli também .br
define rewrite Content-Encoding
br
para corresponder Content-Type
à extensão do arquivo sem .
No entanto, o arquivo é inacessível por padrão no ASP.NET Core,.br
então provider.Mappings
eu adicionei-o com .br
.
Depois disso, execute a depuração e verifique se o jogo funciona corretamente.
Se você o configurou corretamente e o jogo ainda não será exibido, tente limpar o cache do navegador da Web para limpar seus cookies.
Executando WebGL compactado com Brotli
O procedimento é quase o mesmo do Gzip, substituindo a parte Gzip pelo Brotli. No entanto, os arquivos Brotli (.br) não são acessíveis por padrão no ASP.NET Core. Você precisa configurá-lo para que você possa acessá-lo, mas se você estiver usando o código no momento do Gzip, ele é suportado.
Primeiro, crie uma página e implantação de arquivo WebGL.
Posicionamento do arquivo WebGL
wwwroot
webgl-brotli
Em Criar uma pasta, copie a pasta , do arquivo WebGL criado com BrotliBuild
TemplateData
.
Criar uma página do Razor
Crie o arquivo usando WebGLBrotli.cshtml
as mesmas etapas do Gzip.
O código é o seguinte com referência a Saída em index.html
Unity.
O caminho corresponde à pasta criada webgl-brotli
anteriormente para os arquivos 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>
}
Modificar para permitir a navegação para Index.cshtml
esta página.
<!-- 省略 -->
<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>
Programa de fixação.cs
Se você modificá-lo quando o Gzip for suportado, você poderá usar o mesmo código.
Depois de corrigi-lo, execute o debug e verifique se o jogo funciona.
Se você o configurou corretamente e o jogo ainda não será exibido, tente limpar o cache do navegador da Web para limpar seus cookies.
Compreendendo os sintomas de acessar arquivos Brotli em um servidor Web IIS
O Brotli não é suportado pelo IIS por padrão, portanto, a configuração no lado do IIS é necessária. Parece que ele pode ser manipulado fazendo configurações avançadas, mas não vou explicar isso nessa dica. Consulte as informações vinculadas abaixo.
- asp.net núcleo 2.2 brotli compressão não funciona no IIS?
- Visão geral da compactação do IIS
- WebGL: Exemplo de código de configuração do servidor
- WebGL - Implantando compilações compactadas
mensagem de erro
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)