Finalmente descobri uma solução - na verdade, algumas soluções diferentes. Eu não descobri a causa real do artefato de uma perspectiva de programação gráfica - mas encontrei algumas soluções.
Como afirmei anteriormente na minha pergunta, parecia que o artefato estava ocorrendo apenas nos volumes de sombra pré-calculados da geometria estática do mundo do peão (que é basicamente a geometria que o mecanismo sabe que nunca se moverá, portanto, calcula antecipadamente) - os volumes de sombra e outras coisas com um comando digitado no console chamado "dmap"). Não descobri por que isso estava apenas nas sombras da geometria estática do mundo dos peões e não em nenhum dos modelos ASE ou LWO.
Agora, o que notei foi que, na verdade, há uma infinidade de parâmetros que podem ser usados com o comando dmap - um desses parâmetros é chamado "shadowOpt" - que deve representar o nível de otimização de sombra. Este parâmetro define uma enumeração - parece haver alguns níveis diferentes de otimização de sombra:
typedef enum {
SO_NONE, // 0 // NOTE: I haven't tried this one yet - should test this one.
SO_MERGE_SURFACES, // 1 // NOTE: this was the original default one - it causes some artifacts - the ones I have been trying to fix.
SO_CULL_OCCLUDED, // 2 // NOTE: this one works the best - takes a bit longer - but it has alot of unnecessary print statements that could probably be removed.
SO_CLIP_OCCLUDERS, // 3 // NOTE: I haven't tried this one yet - but it is not used anywhere.
SO_CLIP_SILS, // 4 // NOTE: I haven't tried this one yet - should test this one.
SO_SIL_OPTIMIZE // 5 // NOTE: this one doesn't seem to work well at all - and it takes an extrememly long amount of time - was probably an expirimental version.
} shadowOptLevel_t;
Eu tive sucesso com a opção 2 - "SO_CULL_OCCLUDED". Ele corrige todos os artefatos - demora um pouco mais para ser executado - mas acredito que muito desse tempo é gasto imprimindo grandes quantidades de informações no console - essas impressões provavelmente poderiam ser reduzidas ou eliminadas.
Um dos lugares que me deu algumas pistas foi o comentário aqui em tr_stencilshadow.cpp:
// if we are running from dmap, perform the (very) expensive shadow optimizations
// to remove internal sil edges and optimize the caps
if ( callOptimizer ) {
Agora, o problema de realizar apenas essa otimização de sombra "extra" durante o "dmap" é que, se alguma dessas luzes for movida (o que sempre é possível, dependendo do tipo de projeto que você está fazendo) - ela retornará ao padrão processo de criação de volume de sombra em tempo real "não otimizado" (para a luz movida) e os artefatos reaparecerão para essa luz. Portanto, a única maneira de garantir que esses artefatos não apareçam é sempre executar o processo de otimização muito caro para essas sombras estáticas de worldspawn. Na verdade, é muito caro, portanto este seria um último recurso absoluto se você não conseguir encontrar uma solução gráfica adequada. (se o fizer, certifique-se de postar sua solução aqui.)
Eu recomendaria para quem criar mapas grandes para o mecanismo Doom 3 de baunilha - e usar a geometria worldspawn - que eles criem um cvar que eles possam mudar dependendo de suas necessidades para a criação em tempo real dos volumes de sombra otimizados. Liguei para minhas cvar r_useExpensiveShadowOptimizations - que parece ser um oxímoro. Por exemplo:
// if we are running from dmap, perform the (very) expensive shadow optimizations
// to remove internal sil edges and optimize the caps
if ( callOptimizer || r_useExpensiveShadowOptimizations.GetBool() ) {
Também recomendo que, dependendo do tamanho dos seus mapas (e supondo que as luzes não se movam), você aumente o nível de otimização do volume de sombra estática com o parâmetro "shadowOpt" do dmap.
Então, basicamente, todas as coisas que você precisa para ter um mapa grande e não possuir artefatos de sombra estão lá para você, basta decidir quais você precisará usar. Fazer isso em tempo real é extremamente caro e só deve ser feito como último recurso se você não encontrar uma solução gráfica adequada. Fazê-lo no DMAP faz todo o sentido, pois resolve o problema e leva apenas mais alguns segundos para que o mapa seja compilado.