Essa página acompanha o modelo Talisman: Environment que demonstra as práticas recomendadas para criar ambientes altamente detalhados e realistas. A Talisman foi criada com a utilização de construção modular e práticas recomendadas de otimização no Unreal Editor para Fortnite (UEFN).
Você encontra o modelo na seção Exemplos de funcionalidades do Navegador de Projetos.
Você pode jogar a experiência Talisman apresentada durante a Game Developers Conference (GDC) de 2024 abrindo o Fortnite e digitando o código da ilha: 7100-3544-3074.
A visão geral percorre os desafios de otimização enfrentados durante a criação do projeto Talisman e como cada desafio foi superado:
-
Como gerenciar os limites de memória do projeto e do tempo de execução
-
Como projetar materiais usando o controle de materiais dinâmicos
Como este modelo foi projetado para rodar em todas as plataformas disponíveis, os ativos e o estilo da Talisman precisa seguir os requisitos de limite de memória e tamanho de projeto do UEFN. Isso criou vários desafios para projetos desenvolvidos com um estilo artístico mais detalhado:
-
Tamanho do projeto: ativos altamente detalhados em jogos podem ser grandes e o UEFN tem uma limitação de tamanho de 400 MB por projeto.
-
Limites de memória do tempo de execução: o UEFN tem uma restrição de 100.000 da memória de transmissão da unidade de memória que limita a quantidade de ativos, paisagens personalizadas e dispositivos que podem ficar na tela ao mesmo tempo.
-
Qualidade em todas as plataformas aceitas: esses limites garantem que a sua experiência no UEFN esteja disponível para todos os jogadores em todas as plataformas aceitas pelo Fortnite.
O UEFN aceita várias técnicas para atender a esses requisitos, incluindo níveis de detalhe (LODs), níveis hierárquicos de detalhes (HLODs), World Partition, instanciação de níveis e camadas de dados.
Como aplicar as práticas recomendadas
O modelo Talisman: Environment foi desenvolvido para demonstrar várias práticas e processos recomendados para levar realismo AAA para o Unreal Editor para Fortnite. Esse modelo usa as seguintes práticas recomendadas para gerenciar a memória do projeto e de transmissão para otimizar o desempenho:
-
Criar conteúdo personalizado modular e leve.
-
Aperfeiçoar o visual da geometria de superfície dura usando normais com ponderação de face.
-
Adicionar detalhe às malhas usando decalques de malha.
-
Criar sua experiência para a plataforma-alvo mais básica e adicionar funcionalidades a partir daí.
-
Minimizar draw calls em malhas que não são Nanite.
Como criar conteúdo personalizado modular e leve
O Talisman: Environment foi criado usando kitbashing, uma técnica de modelagem modular que usa malhas preexistentes de um ambiente modular e as modifica para criar novos ativos. Ao reutilizar ativos, os artistas puderam diminuir o tamanho do projeto minimizando o número de malhas de uso único.
Tradicionalmente, os artistas criam este tipo de ambiente mapeando uma malha altamente detalhada e com alta contagem de polígonos sobre uma malha com baixa contagem de polígonos usando mapas de normais incorporados únicos para preservar os detalhes entre as duas. Esse método exige mapas de texturas adicionais que podem aumentar o tamanho do projeto, são custos para o tempo de execução e não são bem dimensionados durante o processo de modelagem.
Malhas midpoly com normais com ponderação de face são usadas para economizar memória e decalques de malha foram usados para adicionar pequenos detalhes.
Consulte mais informações em Design e construção de malhas.
Como criar sua experiência para todas as plataformas-alvo
O Fortnite foi desenvolvido para rodar em várias plataformas. E, para garantir que o seu conteúdo proporciona a melhor experiência aos jogadores em todos esses dispositivos, é importante ter um design pensado para todas as plataformas, e depois adicionar outras funcionalidades para plataformas avançadas durante o desenvolvimento.
Por exemplo, a Geometria Virtualizada Nanite ajuda as plataformas a renderizar malhas altamente detalhadas e a melhorar o desempenho, mas só está disponível para alguns dispositivos avançados, como PCs com DirectX 12. Por isso, ainda é importante otimizar o conteúdo de forma que apresente bom desempenho em todas as plataformas.
Barra de sequência de imagens com configurações Épica, Alta, Média e Baixa
Consulte mais informações sobre como criar seus próprios ativos personalizados para o UEFN em Design e construção de malhas.
Como minimizar draw calls ao usar malhas que não são do Nanite
Draw calls são o processo que informa à API gráfica o que traçar e como traçar durante cada quadro. O Nanite contorna draw calls padrão transmitindo as geometria para a cena de acordo com a necessidade. Para malhas que não são do Nanite, cada uma das seguintes inicia um draw call em uma cena:
-
Cada malha individual.
-
Cada material em uma malha.
-
Cada luz.
-
Cada sombra projetada.
O modelo Talisman: Environment usa tanto malhas do Nanite quanto malhas que não são do Nanite. Para otimizar o desempenho enquanto usa malhas que não são do Nanite, o número de draw calls na cena foi minimizada:
-
Removendo-se malhas não essenciais.
-
Removendo-se decalques de malha não essenciais
-
Removendo-se luz com projeção de sombras e suplementando-as usando funções da luz.
Como gerenciar os limites de memória do projeto e do tempo de execução
O gerenciamento de memória do tempo de execução e do tamanho do projeto são componentes essenciais de qualquer projeto desenvolvido no UEFN. O Talisman: Environment enfrenta estes desafios:
-
Limitação do escopo do projeto.
-
Reutilização de ativos personalizados.
-
Gerenciamento da memória do tempo de execução.
Escopo de projeto limitado
Para atender ao limite de tamanho de projeto de 400 MB, o personagem MetaHuman foi movido para o modelo Talisman: MetaHuman. Você encontra esse modelo na seção Exemplos de funcionalidades do Navegador de Projetos. Para aprender sobre os MetaHuman no UEFN, consulte o modelo Talisman: MetaHuman.
Níveis de detalhes
Cada malha usada para criar o Talisman usa três níveis de detalhes (LODs) para manter o projeto dentro do orçamento da unidade de memória de transmissão de 100.000.
As malhas de LOD são geradas automaticamente usando as ferramentas de LOD automáticas do UEFN e são atribuídas a níveis de qualidade específicos. Para obter mais informações sobre o uso de níveis de detalhe no UEFN, consulte Definindo o nível de detalhe.
Gerenciamento da memória do tempo de execução
O modelo Talisman: Environment usa uma solução de transmissão personalizada criada usando camadas de dados e o Sequencer para manter o nível dentro do orçamento de transmissão da unidade de memória de 100.000. O tamanho vertical das áreas como a área de carga e a extensão dos corredores fazia com que a nave não coubesse na grade de transmissão do World Partition .
Para superar essa limitação, as camadas de dados foram combinadas com o Sequencer para carregar e descarregar as áreas da nave de acordo com a posição do jogador.
Cada espaço tem sua própria camada de dados correspondente e áreas de agentes de mutação espalhadas pela nave que acionam eventos na Sequência de Nível. Esses eventos carregam e descarregam seções da nave conforme o jogador se move pelo nível. As áreas de agentes de mutação são colocadas estrategicamente nas áreas da nave para esconder isso do jogador.
Como usar elementos de IU personalizados
Este modelo usa a linguagem Verse para exibir um widget de ícone de tarefa personalizado e reproduzir áudio quando o jogador interage com o console na sala inicial.
Quando o jogador usa o dispositivo Crew Quarters VO Button, o arquivo de script starting_sequence_device.verse:
using { /Fortnite.com/Devices }
using { /Verse.org/Simulation }
using { /Fortnite.com/Characters }
using { /UnrealEngine.com/Temporary/UI }
using { /UnrealEngine.com/Temporary/Diagnostics }
# Consulte https://dev.epicgames.com/documentation/en-us/uefn/create-your-own-device-in-verse para saber como criar um dispositivo Verse.
# Registra o canal para logs de depuração.
starting_sequence_log := class(log_channel){}
# Coordena o áudio para o início do jogo e habilita o minimapa
# quando um jogador interagir com um console.
starting_sequence_device := class(creative_device):
# Cria um dispositivo para gerar as informações do log de depuração.
Logger:log = log{Channel := starting_sequence_log}
# Cria um dispositivo de mensagem do HUD para exibir a mensagem da tarefa.
@editable
AssignQuestHudMsg:hud_message_device = hud_message_device{}
# Cria o botão para ativar o mapa do convés superior.
@editable
CrewQuartersButton:button_device = button_device{}
# Determina o tempo de espera até habilitar o minimapa e o HUD.
@editable
MapAndHUDDelay:float = 1.0
# Reproduz o áudio quando o indicador do mapa for adicionado.
@editable
MapIndicatorAudio:audio_player_device = audio_player_device{}
# O controle do HUD que exibe apenas o minimapa.
@editable
MapOnlyHud:hud_controller_device = hud_controller_device{}
# O mapa para o convés inferior.
@editable
NewUpperDeckMap:map_controller_device = map_controller_device{}
# Habilita várias áreas de áudio ambiente pela nave.
@editable
TriggerAudioChannelEnable:trigger_device = trigger_device{}
# Inicia a reproduzir o áudio ambiente de várias áreas da nave.
@editable
TriggerAudioChannelPlay:trigger_device = trigger_device{}
# O áudio inicial que é reproduzido quando o jogador surge.
@editable
WelcomeAudio:audio_player_device = audio_player_device{}
# Executado quando o dispositivo é iniciado em um jogo em execução
OnBegin<override>()<suspends>:void =
# Transmite no canal para habilitar os volumes de áudio ambiente pela nave.
TriggerAudioChannelEnable.Trigger()
# Transmite no canal para iniciar a reproduzir o áudio dos volumes de áudio ambiente.
TriggerAudioChannelPlay.Trigger()
# Espera que o jogador interaja com o console no alojamento.
CrewQuartersButton.InteractedWithEvent.Await()
# Cancela o áudio de boas-vindas se já estiver sendo reproduzido.
WelcomeAudio.Stop()
# Habilita o controle do mapa do convés superior, e depois habilitará o minimapa.
Sleep(MapAndHUDDelay)
NewUpperDeckMap.Enable()
MapOnlyHud.Enable()
Sleep(MapAndHUDDelay)
# Exibe a mensagem da tarefa e reproduzirá o áudio do indicador do mapa.
AssignQuestHudMsg.Show()
MapIndicatorAudio.Play()
-
Cancelará o áudio de boas-vindas se a mensagem de áudio ainda estiver sendo reproduzida.
-
Habilitará um minimapa da nave para ajudar os jogadores a explorar a Talisman.
-
Exibirá o Blueprint de widget da IU quest_icon_widget.
-
Reproduzirá um som.
Para obter mais informações sobre o uso de Verse para personalizar seus projetos do UEFN, consulte Guia inicial para programação com o Verse.
Iluminação de espaços amplos
A Talisman usa a iluminação global do Lumen para ajudar a iluminar o ambiente, oferecendo ao jogador sombras e luz indireta precisa pela nave.
O Lumen oferece oclusão de ambiente e iluminação global a objetos que são iluminados pela iluminação direta. Embora o Lumen seja uma ferramenta avançada para a criação de soluções de iluminação, ainda é importante otimizar seu ambiente para otimizar o desempenho. O Lumen é usado com o modelo Talisman: Environment com várias otimizações.
A projeção de sombras está desligada em todas as malhas estáticas que são iluminadas diretamente pelo nível. O Lumen oferece sombras excelentes para essas malhas, assim desligar a propriedade Gerar Sombras aumentou o desempenho sem sacrificar a qualidade visual.
A projeção de sombras também é complementada com o uso das funções de luz e uma textura listrada com luzes pendentes.
O ruído e a intermitência de luz do Lumen dos painéis de luz emissivos são reduzidos com o pareamento de cada um com um holofote que não projeta sombra.
O valor emissivo para cada painel é reduzido e complementado com um holofote que não projeta sombra. Cada holofote recebe um raio pequeno de efeito e oferece luz adicional enquanto faz com que a luz ainda pareça estar vindo do painel de luz.
A iluminação do ambiente foi otimizada ainda mais fazendo com que cada luz tivesse a menor distância de traçado máxima possível. Essa configuração retira cada luz da visualização quando ela não precisa ser renderizada.
O visualizador de complexidade de iluminação também foi usado na iluminação da Talisman.
Esse modo de visualização da janela de visualização mostra o número de luzes não estáticas que afetam a geometria no nível como sombreamento de cor e ajuda a acompanhar o custo de desempenho da iluminação. Esse visualizador é útil para minimizar a sobreposição de luzes no nível para manter os custos de desempenho baixos.
Construção e design de malhas
Malhas personalizadas midpoly e a técnica kitbashing foram usadas para criar o interior detalhado da Talisman. Kitbashing é uma técnica poderosa que ajuda a minimizar o número de ativos que seu projeto precisa enquanto ainda permite que você reutilize e combine as malhas para criar nova geometria.
Cada malha no projeto usa uma variedade de diferentes técnicas para melhorar o visual do ativo sem adicionar mais geometria.
Normais com ponderação de face é uma técnica que alinha as normais do vértice do modelo com faces planas maiores para melhorar o sombreamento sem diminuir o desempenho.
Detalhes como parafusos, marcas e danos foram adicionados usando decalques de malha. Esses decalques usam UVs personalizados para projetar geometria complexa sobre superfícies e permitir o contorno nos cantos ou alongamento em splines enquanto ainda mantém seu visual.
A barra de comparação de imagens. Imagem à direita com os decalques de malha ligados. Imagem à esquerda mostra a malha sem os decalques.
Como projetar materiais usando o controle de materiais dinâmicos
Texturas e materiais geralmente são a maior parte de qualquer projeto do UEFN. Para reduzir ainda mais o tamanho do projeto, o modelo usa uma abordagem dinâmica para as texturas e os materiais que evita o uso de mapas de texturas únicos. Para obter esse resultado final, foi usado um fluxo de trabalho procedural que armazena oclusão de ambiente, curvatura e dados de máscara na malha usando as cores do vértice. Os dados armazenados foram usados para aplicar e mesclar os materiais.
Dados da cor do vértice
É melhor evitar usar mapas de texturas únicos para cada ativo reunindo em pacotes a oclusão de ambiente, a curvatura e os dados da máscara de textura em cada malha usando as cores do vértice. As malhas para a Talisman foram desenvolvidas com geometria e densidade de malha de apoio (polígonos por polegada quadrada) para oferecer gradação suave entre as cores do vértice. Isso ajuda a criar transições limpas entre os materiais.
Os dados são armazenados usando o seguinte método:
Mapa | Canal de cores |
---|---|
Oclusão de ambiente | Vermelho |
Curvatura | Verde |
Máscara do ID de material | Azul |
Para obter mais informações sobre a pintura de cores do vértice, consulte Materiais de cor do vértice.
Os espaços de materiais em cada malha são usados para definir qual parte da malha recebe um material específico. Para obter mais informações sobre os espaços de materiais, consulte Pipeline de material FBX.
Controle de material dinâmico
As malhas para a Talisman usam uma combinação de cinco tipos de materiais principais:
-
Metal
-
Metal pintado
-
Plásticos
-
Borrachas
-
Tecidos
Cada material depende de um material mestre único que usa texturas de ladrilhamento alinhadas ao mundo e parâmetros definidos pelo usuário para gerar o resultado. Isso mantém o custo de memória geral dos materiais baixo reutilizando e permitindo que nossos artistas usem o mesmo material em toda a nave.
Poeira, arranhões e outras marcas de desgaste também são incluídas no material mestre e são aplicadas às malhas usando máscaras orientadas por parâmetro. Esses parâmetros são armazenados na malha com o uso de dados primitivos personalizados.
Como usar o dispositivo Câmera em Órbita
O dispositivo Câmera em Órbita oferece uma visão que segue o personagem jogável, mas que o jogador pode girar para olhar livremente ao seu redor. O modelo usa esse dispositivo para dar ao jogador a capacidade de trocar entre a visão de terceira pessoa e uma visão simulada em primeira pessoa.
Isso é feito usando o script Verse camera_switch_mode_device.
# Esse arquivo lida com a troca entre as diferentes câmeras quando um comando é pressionado.
using { /Fortnite.com/Devices }
using { /Verse.org/Simulation }
using { /Fortnite.com/Characters }
using { /UnrealEngine.com/Temporary/Diagnostics }
# Consulte https://dev.epicgames.com/documentation/en-us/uefn/create-your-own-device-in-verse para saber como criar um dispositivo Verse.
# Registra o canal para logs de depuração.
camera_switch_mode_log := class(log_channel){}
# A classe de contêiner para uma câmera de jogabilidade e se deve
# ocultar o personagem jogável quando a câmera é adicionada a um jogador.
gameplay_camera := class<concrete>():
# O dispositivo de câmera associado a esta classe.
@editable
Camera:gameplay_camera_orbit_device = gameplay_camera_orbit_device{}
# Determina se essa câmera deve ocultar o personagem jogável.
@editable
ShouldHideCharacter:logic = false
# Alterna entre as diferentes câmeras quando um gatilho de comando é ativado.
camera_switch_mode_device := class(creative_device):
# Cria um dispositivo para gerar as informações do log de depuração.
Logger:log = log{Channel := camera_switch_mode_log}
# O tempo de espera antes de ocultar o modelo do personagem jogável
# quando uma câmera é adicionada a um jogador.
@editable
HideDelay:float = 0.20
# O tempo de espera antes de exibir o modelo do personagem jogável
# quando uma câmera é removida de um jogador.
@editable
ShowDelay:float = 0.3
# Ouve um comando e alterna a câmera entre os diferentes modos quando o comando é pressionado.
@editable
SwapCameraInputTrigger:input_trigger_device = input_trigger_device{}
# A matriz de câmeras entre as quais alternar. Você pode alterar a ordem dos elementos nessa
# matriz para alterar a ordem de alternância das câmeras.
@editable
Cameras:[]gameplay_camera = array{}
# É executado quando o dispositivo é iniciado em um jogo em execução
OnBegin<override>()<suspends>:void=
# Gera um loop de câmera por jogador.
Players := GetPlayspace().GetPlayers()
for (Player : Players):
spawn{CameraLoop(Player)}
# Ouve o gatilho de comando e alterna pelas câmeras na matriz Cameras.
CameraLoop(Agent:agent)<suspends>:void=
# O índice da câmera atual na matriz Cameras.
var CameraIndex:int = 0
# A referência à câmera atual.
var MaybeCurrentCamera:?gameplay_camera_device = false
# Ouve continuamente o gatilho de comando, depois alterna
# para a próxima câmera. Volta para a câmera padrão quando
# chega ao fim da matriz.
loop:
SwapCameraInputTrigger.PressedEvent.Await()
# Se o jogador tiver uma câmera, remova-a de sua pilha de câmeras.
if:
CurrentCamera := MaybeCurrentCamera?
then:
CurrentCamera.RemoveFrom(Agent)
Logger.Print("Câmera removida em {CameraIndex}.")
if:
# Obtenha a próxima câmera na matriz Cameras.
NextCamera := Cameras[CameraIndex]
then:
# Adicione a câmera ao agente.
NextCamera.Camera.AddTo(Agent)
set MaybeCurrentCamera = option{NextCamera.Camera}
set CameraIndex += 1
Logger.Print("Câmera adicionada em {CameraIndex}.")
# Verifique se a próxima câmera deve ocultar o fort_character do agente.
# Caso contrário, exiba o fort_character.
if:
NextCamera.ShouldHideCharacter?
then:
HideCharacter(Agent)
else:
ShowCharacter(Agent)
else:
# Caso contrário, volte para a câmera padrão e restaure a
# contagem de CameraIndex
set CameraIndex = 0
set MaybeCurrentCamera = false
ShowCharacter(Agent)
Logger.Print("Restaurar câmeras")
# Suspenda por um curto período para impedir a difusão
# do gatilho de comando.
Sleep(1.0)
# Aguarde uma quantidade de HideDelay em segundos, para ocultar o
# fort_character do agente.
HideCharacter(Agent:agent)<suspends>:void=
Sleep(HideDelay)
if (FortCharacter := Agent.GetFortCharacter[]):
FortCharacter.Hide()
# Aguarde uma quantidade de HideDelay em segundos, para mostrar o
# fort_character do agente.
ShowCharacter(Agent:agent)<suspends>:void=
Sleep(ShowDelay)
if (FortCharacter := Agent.GetFortCharacter[]):
FortCharacter.Show()
O código Verse ouve o jogador acionar a ação de comando criativo-alvo, que, por padrão é mapeada para o clique com o botão direito do mouse ou o gatilho esquerdo de um controle. Então, fará o seguinte:
-
Removerá a câmera atual da pilha de câmeras.
-
Obterá a próxima câmera na matriz Cameras.
-
Adicionará a nova câmera ao agente.
-
Ocultará o personagem jogável, se necessário.
-
Exibirá o personagem jogável, se necessário.