Estou desenvolvendo um jogo com um terreno semelhante ao Minecraft feito de blocos. Como a renderização básica e o carregamento de blocos estão concluídos agora, quero implementar a seleção de blocos.
Portanto, preciso descobrir qual bloco a câmera da primeira pessoa está enfrentando. Eu já ouvi falar de não projetar a cena inteira, mas decidi contra isso porque parece hacky e não é preciso. Talvez eu pudesse de alguma forma lançar um raio na direção da vista, mas não sei como verificar a colisão com um bloco nos meus dados voxel. É claro que esses cálculos devem ser feitos na CPU, pois preciso dos resultados para realizar operações de lógica do jogo.
Então, como eu poderia descobrir qual bloco está na frente da câmera? Se for preferível, como eu poderia lançar um raio e verificar colisões?
fonte
Respostas:
Quando tive esse problema enquanto trabalhava em meus cubos , encontrei o artigo "Um algoritmo transversal voxel rápido para rastreamento de raios", de John Amanatides e Andrew Woo, 1987, que descreve um algoritmo que pode ser aplicado a esta tarefa; é preciso e precisa de apenas uma iteração de loop por voxel cruzada.
Eu escrevi uma implementação das partes relevantes do algoritmo do artigo em JavaScript. Minha implementação adiciona dois recursos: permite especificar um limite na distância do raycast (útil para evitar problemas de desempenho e definir um 'alcance' limitado) e também calcula qual face de cada voxel o raio digitou.
O
origin
vetor de entrada deve ser dimensionado de forma que o comprimento lateral de um voxel seja 1. O comprimento dodirection
vetor não é significativo, mas pode afetar a precisão numérica do algoritmo.O algoritmo opera usando uma representação parametrizada do raio
origin + t * direction
,. Para cada eixo de coordenadas, nós acompanhar ot
valor que teria se demos um passo suficiente para atravessar uma fronteira voxel ao longo desse eixo (ou seja, alterar a parte inteira da coordenada) nas variáveistMaxX
,tMaxY
etMaxZ
. Em seguida, damos um passo (usando as variáveisstep
etDelta
) ao longo de qualquer eixo que tenha menostMax
- ou seja, o limite de voxel mais próximo.Link permanente para esta versão da fonte no GitHub .
fonte
function intbounds(s,ds) { return (ds > 0? Math.ceil(s)-s: s-Math.floor(s)) / Math.abs(ds); }
. ComoInfinity
é maior que todos os números, também não acho que você precise se proteger contra ds.1/ds
fazendo com que um dos outros eixos seja incrementado. A correção é escreverintfloor
para verificar se ambosds
são negativos e ses
é um valor inteiro (mod retorna 0) e, nesse caso, retorna 0,0.Talvez veja o algoritmo de linha de Bresenham , principalmente se você estiver trabalhando com blocos de unidades (como a maioria dos jogos minecraft).
Basicamente, isso leva dois pontos e traça uma linha ininterrupta entre eles. Se você lançar um vetor do jogador para a distância máxima de escolha, poderá usá-lo e as posições dos jogadores como pontos.
Eu tenho uma implementação 3D em python aqui: bresenham3d.py .
fonte
Para encontrar o primeiro bloco na frente da câmera, crie um loop for que faça um loop de 0 a uma distância máxima. Em seguida, multiplique o vetor avançado da câmera pelo contador e verifique se o bloco nessa posição é sólido. Se estiver, armazene a posição do bloco para uso posterior e pare o loop.
Se você também deseja colocar blocos, escolher o rosto não é mais difícil. Basta voltar do bloco e encontrar o primeiro bloco vazio.
fonte
Fiz um post no Reddit com minha implementação , que usa o Algoritmo de Linha de Bresenham. Aqui está um exemplo de como você o usaria:
Aqui está a própria implementação:
fonte