No meu perfilador, encontrar coordenadas barentêntricas é aparentemente um gargalo. Eu estou olhando para torná-lo mais eficiente.
Segue o método em shirley , onde você calcula a área dos triângulos formados incorporando o ponto P dentro do triângulo.
Código:
Vector Triangle::getBarycentricCoordinatesAt( const Vector & P ) const
{
Vector bary ;
// The area of a triangle is
real areaABC = DOT( normal, CROSS( (b - a), (c - a) ) ) ;
real areaPBC = DOT( normal, CROSS( (b - P), (c - P) ) ) ;
real areaPCA = DOT( normal, CROSS( (c - P), (a - P) ) ) ;
bary.x = areaPBC / areaABC ; // alpha
bary.y = areaPCA / areaABC ; // beta
bary.z = 1.0f - bary.x - bary.y ; // gamma
return bary ;
}
Este método funciona, mas estou procurando um mais eficiente!
barycentric-coordinates
bobobobo
fonte
fonte
Respostas:
Transcrito da Detecção de colisão em tempo real de Christer Ericson (que, aliás, é um excelente livro):
Esta é efetivamente a regra de Cramer para resolver um sistema linear. Você não será muito mais eficiente do que isso - se isso ainda for um gargalo (e pode ser: não parece muito diferente em termos de computação que o algoritmo atual), você provavelmente precisará encontrar outro lugar para ganhar uma aceleração.
Observe que um número decente de valores aqui é independente de p - eles podem ser armazenados em cache com o triângulo, se necessário.
fonte
p
para esta função.A regra do Cramer deve ser a melhor maneira de resolvê-la. Eu não sou um cara gráfico, mas queria saber por que, no livro Detecção de colisão em tempo real, eles não fazem a seguinte coisa mais simples:
Isso resolve diretamente o sistema linear 2x2
enquanto o método do livro resolve o sistema
fonte
.z
dimensão () (especificamente, que ela não existe)?Um pouco mais rápido: pré-calcule o denominador e multiplique em vez de dividir. As divisões são muito mais caras que as multiplicações.
Na minha implementação, no entanto, eu armazenei em cache todas as variáveis independentes. Eu pré-calculei o seguinte no construtor:
Portanto, o código final fica assim:
fonte
Eu usaria a solução que John postou, mas usaria o SSS 4.2 ponto intrínseco e o sse rcpss intrínseco para a divisão, supondo que você esteja bem restringindo-se a Nehalem e processos mais recentes e precisão limitada.
Como alternativa, você pode calcular várias coordenadas barricêntricas de uma só vez usando sse ou avx para uma aceleração de 4 ou 8x.
fonte
Você pode converter seu problema 3D em um problema 2D projetando um dos planos alinhados ao eixo e usar o método proposto pelo usuário5302. Isso resultará exatamente nas mesmas coordenadas barricêntricas, desde que você verifique se o triângulo não se projeta em uma linha. O melhor é projetar no plano alinhado ao eixo o mais próximo possível da orientação da triagle. Isso evita problemas de co-linearidade e garante a máxima precisão.
Em segundo lugar, você pode pré-calcular o denominador e armazená-lo para cada triângulo. Isso salva os cálculos posteriormente.
fonte
Tentei copiar o código do @ NielW para C ++, mas não obtive resultados corretos.
Era mais fácil ler https://en.wikipedia.org/wiki/Barycentric_coordinate_system#Barycentric_coordinates_on_triangles e calcular o lambda1 / 2/3 conforme indicado lá (não são necessárias funções vetoriais).
Se p (0..2) são os pontos do triângulo com x / y / z:
Pré-cálculo para triângulo:
então as lambdas para um Point "point" são
fonte
Para um dado ponto N dentro do triângulo ABC, você pode obter o peso barcentric do ponto C dividindo a área do sub-triângulo ABN pela área total do triângulo AB C.
fonte