2014-09-30 18 views
7

Tworzę geomip odwzorowany terenu. Do tej pory mam to działa dość dobrze. Tesselacja terenu w pobliżu kamery jest bardzo wysoka i zmniejsza się, więc dalsza geometria jest. Geometria terenu zasadniczo podąża za kamerą i pobiera teksturę wysokości mapy na podstawie położenia wierzchołków. Ponieważ tesselacja geometrii jest bardzo wysoka, możesz czasami zobaczyć każdy piksel w fakturze, gdy jest próbkowany. Tworzy oczywiste uderzenia piksela. Pomyślałem, że mógłbym to obejść, wygładzając próbkowanie mapy wysokości. Jednak wydaje mi się, że mam dziwny problem związany z pewnym bileterowym kodem do pobierania próbek. Odwzorowuję teren, przesuwając każdy wierzchołek zgodnie z teksturą wysokości mapy. Aby uzyskać wysokość wierzchołka w danym UV koordynować mogę użyć:GLSL Vertex Shader dwuliniowe próbkowanie wysokość mapa

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 
} 

która produkuje ten (zauważ, jak widać każdy piksel):

enter image description here

Oto szkielet:

enter image description here

chciałem zrobić próbkowanie teren gładsza. Pomyślałem więc, że zamiast standardowej funkcji texture2D mogę użyć próbkowania bilinearnego. Więc tutaj jest moja funkcja próbkowania bilinear:

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); 
} 

texelSize oblicza się jako wielkości 1/heightmap:

vec2 texel = vec2(1.0/tHeightSize); 

i textureSize jest szerokość i wysokość mapy wysokości. Jednak, kiedy korzystać z tej funkcji uzyskać ten wynik:?

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

enter image description here

który wydaje się teraz gorzej :(Jakieś pomysły co mogę robić źle Albo jak mogę uzyskać gładszą próbkowanie terenu

EDIT

Oto pionowe ekranu patrzy na terenie. można zobaczyć warstwy działać prawidłowo. Odnotuj jednak, że zewnętrzne warstwy, które mają mniej triangulacji i wyglądają gładko, podczas gdy te z wyższą tesselacją pokazują każdy piksel. Próbuję znaleźć sposób na wygładzenie próbkowania tekstur.

enter image description here enter image description here

+0

Dlaczego używasz niestandardowej interpolacji dwuliniowej? Jeśli każdy wierzchołek ma jeden piksel na mapie wysokości, powinieneś użyć tekstury Gauss-Blur na fakturze, aby uczynić ją "gładką". Jeśli masz więcej punktów niż pikseli, wbudowana interpolacja tekstur wykonałaby pracę. – dari

+0

Cześć, będę musiała edytować moje pytanie, aby wyjaśnić. Powodem jest to, że używam techniki geoklipowania. Teren w pobliżu kamery to bardzo wysoka tesselacja. Ponieważ teselacja jest tak duża, jest więcej trójkątów niż pikseli. Więc nie jest to stosunek 1 do 1. tj. próbkowanie musi być dokładniejsze, lub raczej musi interpolować między wartościami pikseli. – Mat

+0

A dlaczego nie używasz interpolacji kompilacji? https: //www.opengl.org/wiki/Sampler_Object # Sampling_parameters – dari

Odpowiedz

3

udało mi się znaleźć i wdrożyć techniki, który używa interpolacji catmulrom. Kod znajduje się poniżej.

// 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

Jest to przydatne! Dzięki. Czy możesz udostępnić wynik (zdjęcie)? – Nolesh

Powiązane problemy