Como mesclar duas câmeras ao viajar através de um portal no Unity3D

18

Antes de chegar à minha pergunta, eu sei que a solução mais óbvia seria usar a porta de visualização normal ret, no entanto, preciso de formas mais complexas que um retângulo, e procurei usar a porta de visualização ret e parece não seja minha solução.

Edição: Algumas pessoas ficaram confusas com a minha pergunta, deixe-me entrar em um pouco mais de detalhes. insira a descrição da imagem aqui O que está acontecendo é que, quando o jogador se move para um portal, eu crio um controlador FPS clone e o movo para fora do outro. Isso me dá duas câmeras e a visão que você vê à direita acima. Está apenas mostrando uma câmera e cortando o portal. O que eu quero é algo semelhante a issoonde as câmeras se misturam para criar a ilusão de uma transição suave. O que eu quero fazer é excluir tudo, desde a imagem do verificador verde à esquerda na imagem abaixo, e substituí-la pela outra câmera. Dessa forma, você obtém a parte da visualização da câmera A que está saindo do portal, combinada com a parte da visualização da câmera B que está saindo do outro portal, para obter uma imagem completa. E à medida que você se move pelo portal, o corte muda apropriadamente.

Estou desenvolvendo um sistema de portal, tenho tudo em ordem, incluindo fazer com que o player se mova suavemente pelo portal. Meu principal problema agora é obter o efeito de mistura da câmera que a Valve faz. Preciso de duas câmeras para combinar perfeitamente, como se você estivesse enfiando a cabeça no portal. E não pode ser apenas um retângulo, tem que corresponder no entanto, o jogador está olhando através do portal.

Minha melhor vantagem agora é projetar um shader de máscara de profundidade atrás de cada portal e transformar a câmera do portal em que você está viajando apenas em profundidade. Então, de alguma forma, misture as duas câmeras. Meu principal problema é descobrir exatamente como eu faria isso, como fazer a segunda câmera renderizar apenas o que está fora do portal e ter o restante como padrão na câmera 1 para obter uma projeção em tela cheia.

Se você puder me dar idéias, ou explicar como posso fazer isso com o shader de máscara de profundidade, seria uma tremenda ajuda. Vou continuar trabalhando nisso e atualizá-lo à medida que avançar.

Timothy Williams
fonte
5
Você pode elaborar qual é o "efeito de mistura da câmera que a Valve faz"? Eu entendi que na renderização do portal uma única câmera é suficiente. Nos jogos em primeira pessoa, ele é anexado ao jogador e é automaticamente transformado no novo local ao passar pelo portal junto com o jogador. Para renderizar o efeito do portal, uma cópia transformada da cena é renderizada. Isso também pode ser alcançado com uma segunda câmera, mas não deve haver necessidade de mistura entre essas câmeras.
msell
11
Eu já tenho os efeitos visuais perfeitamente. O que estou tentando fazer é descobrir como obter o efeito de caminhar pelo portal. Eu já tenho todos os gráficos dos personagens e movendo-se suavemente, só preciso que pareça suave da perspectiva da primeira pessoa.
Timothy Williams
11
Tenho certeza de que muitas pessoas gostariam de ajudá-lo com o problema se entendessem o que era. Você realmente precisa explicar melhor o problema, talvez adicione fotos ou até mesmo um vídeo para visualizar o que está errado.
msell
2
Você poderia adicionar um link a um exemplo de vídeo do efeito?
perfil completo de Mike Baxter
2
E se você usasse apenas uma câmera / controlador FPS? Quando a câmera se move pelo portal, você pode transformá-la no novo local e orientação. Se a renderização do portal estiver correta, a transição deve ser contínua e sem necessidade de mistura.
msell

Respostas:

6

Compreendendo o problema

Pelo que vejo, o problema que você está descrevendo é o resultado do plano próximo da câmera cruzando o plano definido pelo portal. Enquanto essa interseção ocorre, você pode ver atrás do muro o portal.

Isso é semelhante a um problema enfrentado em outros jogos quando o jogador está apenas fazendo a transição da superfície da água para a água. Se a câmera estiver logo acima da água, nenhum efeito de pós-processamento será aplicado para ofuscar a visualização dos jogadores (torne-a escura, borrada e azul). Portanto, se o fundo do avião próximo estiver logo abaixo da água, o jogador poderá ver claramente debaixo d'água.

Se estiver correto, você pode confirmá-lo alterando a posição deste plano ao definir a matriz de projeção. À medida que a distância da origem da câmera até o plano próximo aumenta, o problema também deve ocorrer.

A Solução Fácil

Fazer o plano próximo muito próximo da câmera quase erradicar esse problema. Esta solução não é completa, mas produzirá um resultado suficientemente bom na grande maioria dos casos e é eficiente.

A Solução Completa

Se apenas aproximar o plano próximo da câmera não for satisfatório, você poderá criar uma "máscara" para misturar as imagens geradas renderizando a cena da perspectiva do player e do portal.

Supondo que você permita apenas a aplicação de portais em superfícies planas, é possível calcular a linha de interseção entre o plano próximo da câmera e o plano definido pelo portal (ou a parede em que se encontra). Essa linha dividirá a tela em duas partes. A determinação de qual lado da linha está o pixel da tela permitirá saber qual imagem de renderização usar, a imagem do portal ou a imagem da câmera do player.

Lembre-se de que, se esse problema estiver ocorrendo, o centro de visão da câmera deve estar completamente dentro do portal, para que a linha de interseção sempre corte completamente de uma borda da tela para outra.

Este link deve ajudar com a matemática a encontrar a linha. O código abaixo deve estar aproximadamente correto.

A linha de interseção é definida usando um ponto na linha e a direção da linha. Abaixo da direção da interseção, é calculado usando o produto cruzado do portal normal e a direção da visualização da câmera (próximo do plano normal). Um ponto na linha é dado lançando um raio de um ponto no plano próximo diretamente em direção ao plano do portal (ao longo do portal normal) e encontrando o ponto de interseção.

Vector3 intersectionDir = Vector3.cross(portalNorm, viewDir);
Ray ray = new Ray(camPos + viewDir * camNearPlaneDist, portalNorm);
Vector3 intersectionPos = ray.intersects(new Plane(portalVert1, portalVert2, portalVert3);

Verifique se o viewDir é um vetor de unidade. portalVert1, 2 e 3 são apenas 3 dos 4 vértices usados ​​para o decalque do portal ou a superfície em que está. Existem outras maneiras de definir o plano no qual o portal se encontra, mas presumo que essa seja a informação mais prontamente disponível.

Depois de ter esses dois vetores para definir a linha de interseção, multiplique cada um pela vista e depois matrizes de projeção para obtê-las no espaço da tela.

Você pode usar um sombreador de pós-processo para misturar essas imagens. Você seleciona qual imagem usar em cada pixel, determinando em qual lado da linha divisória o pixel atual se encontra. Isso é feito pegando a posição do pixel (que também é a posição que você usa para procurar o texel de destino da renderização) e fazendo;

float d = (pixelX - intersectionPos.X) * intersectionDir.Y - (pixelY - intersectionPos.Y) * intersectionDir.X;

O lado é dado pelo fato de d ser maior ou menor que 0. Se for exatamente 0, você estará na linha.

Para referência na matemática acima, veja isso .

Esse método também pode ser usado ao criar um buffer de máscara / estêncil de profundidade para uso antes da renderização da perspectiva do portal. Você pode criar um quad em tela cheia e usar a linha para cortá-lo.

OriginalDaemon
fonte
O plano de clip próximo foi uma boa ideia, mas não exatamente o que estou procurando. Essa segunda parte é uma abordagem interessante. Atualmente, estou usando um sombreador de máscara de profundidade em tudo o que está por trás do plano do portal de saída e, em seguida, definindo as sinalizações claras da câmera que sai apenas para a profundidade. Isso faz com que qualquer parte da câmera que sai do portal seja desenhada na tela e a câmera que entra atraia a máscara de profundidade, criando uma imagem misturando as partes de cada câmera que está saindo do portal respectivo portal. O único problema é que eu estou recebendo alguns pequenos problemas de recorte e como
Timothy Williams
leve empurrão enquanto o jogador viaja. Essa idéia que você criou parece bastante promissora. Então, basicamente, o que eu preciso fazer é calcular a linha ao longo da tela na qual a câmera próxima ao plano e o plano do portal estão cruzando, a direção me dá em qual direção a linha está indo e point é os vários pontos da linha. Como, então, determinaria em um sombreador / script em que lado da linha divisória um pixel é colocado?
Timothy Williams
Atualizei a resposta um pouco para fornecer um código básico. Tente mudar a vista perto da distância do plano de recorte para confirmar o problema. Tornar isso o menor possível também pode ser suficiente. Lembre-se de fazê-lo funcionar, fazê-lo funcionar direito e, em seguida, fazê-lo funcionar rapidamente.
OriginalDaemon
Eu testei a alteração da distância do plano de recorte próximo, o problema foi um pouco melhor, mas como o artigo publicado por Mell afirma que não corrige o problema ao atravessar. Ainda sinto que a linha de interseção pode funcionar, então vou tentar. Também examinarei um pouco mais o artigo que Mell postou. No final ele virá para baixo se uma máscara de profundidade é mais rápido ou mais esta linha de intersecção é mais rápido
Timothy Williams
3

As respostas sugeridas foram muito boas, mas acabei optando por uma técnica diferente usando uma máscara de profundidade.

O que você faz é pegar ESTE script e sombreador, colocar o script em todos os objetos com um renderizador em sua cena e definir a fila de renderização para 3020 (postarei um script para facilitar isso mais tarde).

Em seguida, você cria uma caixa de aviões (todos voltados para dentro, na imagem você não pode ver o lado da caixa mais próximo de você, mas quando você está dentro da caixa, tudo o que deve ver é cinza) atrás de AMBOS seus portais da seguinte maneira: insira a descrição da imagem aqui e coloque-os em uma camada especial (eu escolhi "DepthMask" para o meu), e então adicione um material com o shader acima. insira a descrição da imagem aqui

Você pega a câmera principal e desmarca sua camada especial da máscara de abate (desmarquei a camada DepthMask) e define a profundidade para 0. insira a descrição da imagem aqui

Então, quando você estiver se teletransportando e clonando a câmera, defina os sinalizadores claros da outra câmera para "Somente profundidade" e a profundidade para 1. insira a descrição da imagem aqui

Você então obtém uma tela perfeita entre as duas visualizações da câmera.

Timothy Williams
fonte