Como colocaria lado a lado uma seção de uma textura no espaço da tela?
-
11-12-2019 - |
Pergunta
Perdoe-me se isso já foi perguntado antes, estive procurando a resposta para isso o dia todo e tudo que consegui é ajuda com jogos 2D baseados em blocos.x~x
Estou tentando criar uma GUI personalizável no Direct3D 9, usando um arquivo XML que possui posições para cada elemento e uma opção para esticá-los ou colocá-los lado a lado.O alongamento é um procedimento bastante simples, mas não consegui descobrir uma maneira de colocar lado a lado uma pequena seção de uma textura.Tradicionalmente, para colocar uma textura lado a lado, eu apenas definiria as coordenadas UV como > 1,0, mas as coordenadas da textura de origem serão apenas um pequeno subconjunto de toda a textura, como 0,4 a 0,5.
Tenho a sensação de que perdi algo realmente óbvio, mas como eu faria para simplesmente colocar lado a lado em vez de esticar?Meu melhor palpite é que tem algo a ver com ter mais de um conjunto de coordenadas de textura, mas a partir daí não tenho certeza para onde ir.
O projeto atualmente usa o pipeline de função fixa, então eu preferiria uma resposta usando isso, se possível, mas não recusaria uma resposta que usa um shader se essa for a única maneira.
Solução
Entendo que você deseja colocar lado a lado apenas um subconjunto da textura, certo?Então as coisas ficam complicadas.
Suponha que queremos colocar a coordenada u entre os valores u1 e u2, u1 <u2.
Então precisamos de uma função f(u), tal que
f(0.0) = u1
f(0.5) = (u1+u2)/2
f(0.9999) = u2
f(1.0) = u1
f(1.5) = (u1+u2)/2
f(1.9999) = u2
f(2.0) = u1
and so on...
Uma função apropriada é f(u) = frac(u) * (u2-u1) + u1
O mesmo vale para v-coord, f(v) = frac(v) * (v2-v1) + v1
Observe que está lado a lado sem espelhamento.Se você precisar de espelhamento, então a função deverá ser uma função de onda triangular, que é t(x) = arcsin(sin(pi*(x-0.5)))/pi+0.5
e f(u) = t(u) * (u2-u1) + u1
.Usar funções trigonométricas pode ser caro.
Não sei se é possível com pipeline fixo, mas você pode fazer isso facilmente no pixel shader (código HLSL):
// float2 tex_coord -> (u,v) from vertex shader, in [0,n] range,
// n - number of repetitions
// float2 tex1, tex2 -> constants, subrange of [0,1] coords that will be tiled
// no mirroring
float4 color = tex2D(sampler, frac(tex_coord) * (tex2-tex1) + tex1);
ou
// mirroring, t(x) = arcsin(sin(pi*(x-0.5)))/pi+0.5
float4 color = tex2D(sampler, t(tex_coord) * (tex2-tex1) + tex1);
EDITAR:uma maneira melhor de calcular a função de onda triangular: t1(x) = abs(2(0.5x-floor(0.5x+0.5)))
ou t2(x) = abs(2(frac(0.5x+0.5))-1)
(não exatamente igual a t1, mas correto para números não negativos).