Eu tenho uma superfície de terreno com um normal para cada ponto no terreno.
Eu tenho um segundo mapa normal de detalhes a ser aplicado ao terreno.
Essas normais estão em 3 espaços.
O valor Y de ambos os normais é sempre positivo.
Os valores X, Z de ambos os normais podem ser positivos / negativos / zero.
O primeiro vetor normal (azul) pelo qual estamos girando o segundo vetor (laranja) pode ser quase horizontal.
Eu estou bem com uma solução aproximada, se torna mais fácil / rápido calcular.
Na imagem acima, você vê a superfície azul normal (no 1º mapa normal), o mapa normal laranja (no segundo mapa normal) e o resultado desejado verde normal.
A quantidade em que o vetor laranja é rotacionado deve ser aproximadamente (ou se possível) exatamente igual ao ângulo que o vetor normal azul forma com o plano XZ (onde Y está ativo, como o sistema de coordenadas do DirectX).
Aqui está um segundo cenário:
Na imagem acima, a superfície azul normal é quase horizontal; portanto, o 2º mapa normal está sendo aplicado a uma superfície quase vertical, assim o vetor laranja normal do mapa é girado ainda mais.
A rotação está sendo implementada em um shader HLSL.
Como eu giro a 1ª normal de laranja com base na direção da 2ª normal de azul?
Edit: Talvez eu precise de uma tangente e bitangente, bem como o normal?
Aqui está como eu obtenho o normal:
float4 ComputeNormals(VS_OUTPUT input) : COLOR
{
float2 uv = input.TexCoord;
// top left, left, bottom left, top, bottom, top right, right, bottom right
float tl = abs(tex2D(HeightSampler, uv + TexelSize * float2(-1, -1)).x);
float l = abs(tex2D(HeightSampler, uv + TexelSize * float2(-1, 0)).x);
float bl = abs(tex2D(HeightSampler, uv + TexelSize * float2(-1, 1)).x);
float t = abs(tex2D(HeightSampler, uv + TexelSize * float2( 0, -1)).x);
float b = abs(tex2D(HeightSampler, uv + TexelSize * float2( 0, 1)).x);
float tr = abs(tex2D(HeightSampler, uv + TexelSize * float2( 1, -1)).x);
float r = abs(tex2D(HeightSampler, uv + TexelSize * float2( 1, 0)).x);
float br = abs(tex2D(HeightSampler, uv + TexelSize * float2( 1, 1)).x);
// Compute dx using Sobel filter.
// -1 0 1
// -2 0 2
// -1 0 1
float dX = tr + 2*r + br - tl - 2*l - bl;
// Compute dy using Sobel filter.
// -1 -2 -1
// 0 0 0
// 1 2 1
float dY = bl + 2*b + br - tl - 2*t - tr;
// Compute cross-product and renormalize
float3 N = normalize(float3(-dX, NormalStrength, -dY));
// Map [-1.0 , 1.0] to [0.0 , 1.0];
return float4(N * 0.5f + 0.5f, 1.0f);
}
Como posso obter os vetores tangente e bitangente?
É suficiente pegar o produto cruzado do normal com o vetor unitário do eixo Z para encontrar o vetor tangente? (Como o normal.Y é sempre positivo, onde Y está ativo e Z está apontando na tela).
E então pegue esse vetor tangente e cruze-o com o normal para obter o bitangente?
E então pegue o normal, tangente e bitangente juntos para formar uma matriz de rotação para girar o vetor de mapa normal laranja?
Mesmo que isso funcione, parece muita computação para um pixel shader. Isso funciona e existe uma maneira mais eficiente?
Editar:
Esta imagem pode ajudá-lo a entender o que estou tentando fazer:
Se você sabe o que é o mapeamento normal, acho que isso deve ser direto.
Estou tentando pegar o mapa normal, que contém vários normais, e aplicá-los a uma superfície. A superfície tem seus próprios normais. O mapa normal conterá muito mais normais do que a superfície; portanto, vários normais normais do mapa são amostrados em uma única parte da superfície que possui apenas um único normal.
fonte
Respostas:
Acho que recebi sua pergunta, embora o título e as 2 primeiras fotos sejam confusos.
O problema é que existe um mapa normal para ser mapeado em um plano xz (o vetor laranja). Agora, o plano real descrito pelo normal azul não está necessariamente no plano xz; portanto, é necessário encontrar uma rotação do plano xz para o plano real, a fim de girar o vetor laranja para mapeá-lo no plano real.
Agora, como podemos fazer isso? Bacialmente, devemos encontrar a rotação, que gira o plano xz para o plano descrito pela normal azul.
Encontre o eixo de rotação usando o produto cruzado do normal azul e do normal no plano xz {0, 1, 0}, o vetor laranja deve ser rotacionado em torno desse eixo.
Encontre o ângulo de rotação tomando arccosina do produto escalar das duas normais
Agora crie uma matriz de rotação a partir desses valores e transforme o normal laranja com essa matriz.
fonte
Eu acredito que você acabou pensando no seu problema.
Para voltar ao mapeamento normal padrão, você normalmente possui 3 vetores: a superfície normal, um vetor tangente perpendicular a esse e um cotangente perpendicular a ambos. Juntos, eles formam o espaço tangente no qual o mapa normal descreve uma direção. Com essa configuração, basta multiplicar a leitura de cada componente do mapa normal pelo respectivo eixo do espaço tangente e somar os resultados.
Então você tem um terreno e um mapa normal que gostaria de aplicar a ele. Você já descobriu como obter a altura delta e gerar uma superfície normal. Agora você está procurando a tangente e cotangente.
Então, o que é uma tangente? Bem, a partir da descrição acima, na verdade, é a direção 3D descrita por um dos eixos UV no seu mapeamento de texturas. Afinal, é para isso que é usado, certo? Então, como você encontra essa direção? Bem, dada uma malha arbitrária, é um pouco complicado; mas, dado um terreno de grade regular, é evidente: se você tem uma grade regular com UVs regulares, as direções tangente e cotangente são apenas as duas arestas alinhadas pelo eixo, deixando seu vértice.
Então, você sabe quais são as alturas de pontos ao seu redor. Você pode passar a que distância esses pontos estão no avião. Subtraia-os do ponto em que você está, normalize e pronto: espaço tangente instantâneo.
fonte
Se você também tiver a tangente, poderá usar esta função para gerar a normalidade que você procura. Caso contrário, sinta-se livre para plagiar no futuro!
fonte
Você pode usar a função LERP, que irá interpolar linearmente entre os dois vetores. Dando-lhe um bom normal "média".
http://msdn.microsoft.com/en-us/library/bb509618(VS.85).aspx
(É claro que isso não é realmente rotativo, mas, considerando o vetor laranja e azul, você obterá o vetor verde)
fonte