2014-09-30 16 views
7

Sto creando un terreno mappato geomip. Finora ho funzionato abbastanza bene. La tassellatura del terreno vicino alla telecamera è molto alta e diminuisce di conseguenza tanto maggiore è la geometria. La geometria del terreno segue essenzialmente la fotocamera e campiona una texture heightmap basata sulla posizione dei vertici. Poiché la tassellazione della geometria è molto alta, a volte è possibile vedere ogni pixel nella trama quando è campionata. Crea evidenti urti di pixel. Ho pensato che avrei potuto aggirare il problema livellando il campionamento della heightmap. Tuttavia, sembra che abbia uno strano problema relativo a un codice di campionamento bilineare. Sto rendendo il terreno spostando ogni vertice in base ad una texture heightmap. Per ottenere l'altezza di un vertice in un dato UV coordinare posso usare:GLSL Vertex shader grafico altezza bilineare

vec2 worldToMapSpace(vec2 worldPosition) { 
    return (worldPosition/worldScale + 0.5); 
} 

float getHeight(vec3 worldPosition) 
{ 
     #ifdef USE_HEIGHTFIELD 
     vec2 heightUv = worldToMapSpace(worldPosition.xz); 
     vec2 tHeightSize = vec2(HEIGHTFIELD_SIZE_WIDTH, HEIGHTFIELD_SIZE_HEIGHT); //both 512 
     vec2 texel = vec2(1.0/tHeightSize); 
     //float coarseHeight = texture2DBilinear(heightfield, heightUv, texel, tHeightSize).r; 
     float coarseHeight = texture2D(heightfield, vUv).r; 
     return altitude * coarseHeight + heightOffset; 
    #else 
     return 0.0; 
    #endif 
} 

che produce questo (notate come si può vedere ogni pixel):

enter image description here

Ecco un wireframe:

enter image description here

ho voluto fare il terreno di campionamento più liscia. Così ho pensato che avrei potuto usare un campionamento bilineare invece della funzione standard texture2D. Quindi, ecco la mia bilineare funzione di campionamento:

vec4 texture2DBilinear(sampler2D textureSampler, vec2 uv, vec2 texelSize, vec2 textureSize) 
{ 
    vec4 tl = texture2D(textureSampler, uv); 
    vec4 tr = texture2D(textureSampler, uv + vec2(texelSize.x, 0.0)); 
    vec4 bl = texture2D(textureSampler, uv + vec2(0.0, texelSize.y)); 
    vec4 br = texture2D(textureSampler, uv + vec2(texelSize.x, texelSize.y)); 
    vec2 f = fract(uv.xy * textureSize); // get the decimal part 
    vec4 tA = mix(tl, tr, f.x); 
    vec4 tB = mix(bl, br, f.x); 
    return mix(tA, tB, f.y); 
} 

Il texelSize è calcolato come dimensioni 1/heightmap:

vec2 texel = vec2(1.0/tHeightSize); 

e textureSize è la larghezza e l'altezza della heightmap. Tuttavia, quando uso questa funzione ottengo questo risultato:??

float coarseHeight = texture2DBilinear(heightfield, heightUv, texel, tHeightSize).r; 

enter image description here

che ora sembra peggio :(Tutte le idee che potrei fare male o come posso ottenere una campionatura del terreno più agevole

EDIT

Ecco uno screenshot verticale guardando il terreno. È possibile vedere gli strati funzionano bene. Nota, tuttavia, che gli strati esterni che hanno meno di triangolazione e appaiono più uniformi mentre quelli con tessellazione più alta mostrano ciascun pixel. Sto cercando di trovare un modo per appianare il campionamento della trama.

enter image description here enter image description here

+0

Perché si utilizza un'interpolazione bilineare personalizzata in primo luogo? Se ogni vertice ha un pixel nella mappa dell'altezza dovresti usare un Gauss-Blur sulla texture per renderlo 'liscio'. Se disponi di più vertici rispetto ai pixel, l'interpolazione texture incorporata farebbe il lavoro. – dari

+0

Salve dari, ho intenzione di modificare la mia domanda per chiarire. Il motivo è perché sto usando una tecnica di geoclipmapping. Il terreno vicino alla fotocamera è una tassellazione molto alta. Poiché la tassellatura è così alta, ci sono più triangoli che pixel. Quindi non è un rapporto 1 a 1. Ad esempio, il campionamento deve essere più preciso, ovvero deve essere interpolato tra i valori dei pixel. – Mat

+0

E perché non stai usando la compilazione in interpolazione? https: //www.opengl.org/wiki/Sampler_Object # Sampling_parameters – dari

risposta

3

sono stato in grado di trovare e implementare una tecnica che utilizza catmulrom interpolazione. Il codice è sotto

// catmull works by specifying 4 control points p0, p1, p2, p3 and a weight. The function is used to calculate a point n between p1 and p2 based 
// on the weight. The weight is normalized, so if it's a value of 0 then the return value will be p1 and if its 1 it will return p2. 
float catmullRom(float p0, float p1, float p2, float p3, float weight) { 
    float weight2 = weight * weight; 
    return 0.5 * (
     p0 * weight * ((2.0 - weight) * weight - 1.0) + 
     p1 * (weight2 * (3.0 * weight - 5.0) + 2.0) + 
     p2 * weight * ((4.0 - 3.0 * weight) * weight + 1.0) + 
     p3 * (weight - 1.0) * weight2); 
} 

// Performs a horizontal catmulrom operation at a given V value. 
float textureCubicU(sampler2D samp, vec2 uv00, float texel, float offsetV, float frac) { 
    return catmullRom(
     texture2DLod(samp, uv00 + vec2(-texel, offsetV), 0.0).r, 
     texture2DLod(samp, uv00 + vec2(0.0, offsetV), 0.0).r, 
     texture2DLod(samp, uv00 + vec2(texel, offsetV), 0.0).r, 
     texture2DLod(samp, uv00 + vec2(texel * 2.0, offsetV), 0.0).r, 
    frac); 
} 

// Samples a texture using a bicubic sampling algorithm. This essentially queries neighbouring 
// pixels to get an average value. 
float textureBicubic(sampler2D samp, vec2 uv00, vec2 texel, vec2 frac) { 
    return catmullRom(
     textureCubicU(samp, uv00, texel.x, -texel.y, frac.x), 
     textureCubicU(samp, uv00, texel.x, 0.0, frac.x), 
     textureCubicU(samp, uv00, texel.x, texel.y, frac.x), 
     textureCubicU(samp, uv00, texel.x, texel.y * 2.0, frac.x), 
    frac.y); 
} 

    // Gets the UV coordinates based on the world X Z position 
    vec2 worldToMapSpace(vec2 worldPosition) { 
     return (worldPosition/worldScale + 0.5); 
    } 


// Gets the height at a location p (world space) 
float getHeight(vec3 worldPosition) 
{ 
    #ifdef USE_HEIGHTFIELD 

     vec2 heightUv = worldToMapSpace(worldPosition.xz); 
     vec2 tHeightSize = vec2(HEIGHTFIELD_WIDTH, HEIGHTFIELD_HEIGHT); 

     // If we increase the smoothness factor, the terrain becomes a lot smoother. 
     // This is because it has the effect of shrinking the texture size and increaing 
     // the texel size. Which means when we do sampling the samples are from farther away - making 
     // it smoother. However this means the terrain looks less like the original heightmap and so 
     // terrain picking goes a bit off. 
     float smoothness = 1.1; 
     tHeightSize /= smoothness; 

     // The size of each texel 
     vec2 texel = vec2(1.0/tHeightSize); 

     // Find the top-left texel we need to sample. 
     vec2 heightUv00 = (floor(heightUv * tHeightSize))/tHeightSize; 

     // Determine the fraction across the 4-texel quad we need to compute. 
     vec2 frac = vec2(heightUv - heightUv00) * tHeightSize; 

     float coarseHeight = textureBicubic(heightfield, heightUv00, texel, frac); 
     return altitude * coarseHeight + heightOffset; 
    #else 
     return 0.0; 
    #endif 
} 
+0

È utile! Grazie. Potresti condividere il risultato (immagine)? – Nolesh