2014-09-30 15 views
7

Ich erstelle ein Geomip-Map-Terrain. Bis jetzt funktioniert es ziemlich gut. Die Terrain-Tessellation in der Nähe der Kamera ist sehr hoch und wird weniger, je weiter die Geometrie entfernt ist. Die Geometrie des Geländes folgt im Wesentlichen der Kamera und tastet eine Höhenmap-Textur basierend auf der Position der Scheitelpunkte ab. Da die Geometrie-Tessellation sehr hoch ist, können Sie manchmal bei der Abtastung jedes Pixel in der Textur sehen. Es erzeugt offensichtliche Pixelunebenheiten. Ich dachte, ich könnte das umgehen, indem ich das Sampling der Heightmap glätte. Ich habe jedoch ein seltsames Problem mit einem bilinearen Sampling-Code. Ich rendere das Terrain, indem ich jeden Scheitel entsprechend einer Heightmap-Textur verschiebe. Um die Höhe eines Scheitels zu einem bestimmten UV-Koordinate erhalten kann ich verwenden:GLSL Vertex-Shader Bilineare Sampling-Höhenmap

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 
} 

Welche dies (beachten Sie, wie Sie die einzelnen Pixel sehen) produziert:

enter image description here

Hier ist ein Drahtmodell:

enter image description here

ich wollte das Gelände Abtasten glatter. Also dachte ich, ich könnte ein paar bilineare Sampling anstelle der Standardtextur-2D-Funktion verwenden. So, hier ist meine bilinear Sampling-Funktion:

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

Die texelSize als 1/heightmap Größe berechnet wird:

vec2 texel = vec2(1.0/tHeightSize); 

und textureSize ist die Breite und Höhe des heightmap. Allerdings, wenn ich diese Funktion verwenden, erhalte ich dieses Ergebnis:?

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

enter image description here

die jetzt schlimmer :(Irgendwelche Ideen scheint, was ich tun könnte falsch Oder wie kann ich eine glattere Gelände Probenahme bekommen

EDIT

Hier ist eine vertikale Screenshot im Gelände nach unten. Sie können sehen, die Schichten gut funktionieren. Hinweis jedoch, dass die äußeren Schichten, die weniger Triangulation haben und sehen glatter aus, während diejenigen mit höherer Tesselation jedes Pixel zeigen. Ich versuche einen Weg zu finden, die Textur Sampling zu glätten.

enter image description here enter image description here

+0

Warum verwenden Sie in erster Linie eine benutzerdefinierte bilineare Interpolation? Wenn jeder Eckpunkt ein Pixel in der Höhenkarte hat, sollten Sie einen Gauß-Weichzeichner auf der Textur verwenden, um ihn "glatt" zu machen. Wenn Sie mehr Stützpunkte als Pixel haben, würde die eingebaute Texturinterpolation die Arbeit erledigen. – dari

+0

Hallo Dari, ich werde meine Frage zur Klärung bearbeiten müssen. Der Grund ist, weil ich eine Geoclipmapping-Technik verwende. Das Gelände in der Nähe der Kamera ist eine sehr hohe Tessellation. Da die Tesselation so hoch ist, gibt es mehr Dreiecke als Pixel. Es ist also kein 1 zu 1 Verhältnis. Die Abtastung muss feiner werden oder vielmehr zwischen Pixelwerten interpolieren. – Mat

+0

Und warum verwenden Sie nicht die integrierte Interpolation? https: //www.opengl.org/wiki/Sampler_Object # Sampling_parameters – dari

Antwort

3

Ich war in der Lage, eine Technik zu finden und zu implementieren, die catmulrom Interpolation verwendet. Code ist unten.

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

Es ist nützlich! Vielen Dank. Könnten Sie das Ergebnis (Bild) teilen? – Nolesh