2014-09-30 20 views
7

Tôi đang tạo địa hình được lập bản đồ địa hình. Cho đến nay tôi có nó hoạt động khá tốt. Tessellation địa hình gần máy ảnh là rất cao và được ít hơn để tiếp tục ra hình học. Hình dạng của địa hình chủ yếu theo sau camera và lấy mẫu một kết cấu độ cao dựa trên vị trí của các đỉnh. Bởi vì tessellation hình học là rất cao, đôi khi bạn có thể nhìn thấy mỗi điểm ảnh trong kết cấu khi lấy mẫu của nó. Nó tạo ra các điểm ảnh rõ ràng. Tôi nghĩ rằng tôi có thể làm được điều này bằng cách làm mịn lấy mẫu của bản đồ chiều cao. Tuy nhiên tôi dường như có một vấn đề lạ liên quan đến một số mã lấy mẫu bilinear. Tôi đang vẽ địa hình bằng cách di chuyển từng đỉnh theo kết cấu độ cao. Để có được chiều cao của một đỉnh tại một UV được phối hợp tôi có thể sử dụng:GLSL Vertex shader bilinear lấy mẫu chiều cao lấy mẫu

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 
} 

nào sản xuất này (chú ý làm thế nào bạn có thể thấy mỗi pixel):

enter image description here

Đây là một wireframe:

enter image description here

Tôi muốn lấy mẫu địa hình mượt mà hơn. Vì vậy, tôi figured tôi có thể sử dụng một số lấy mẫu bilinear thay vì các tiêu chuẩn texture2D chức năng. Vì vậy, đây là chức năng lấy mẫu Bilinear tôi:

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

Các texelSize được tính như kích thước 1/heightmap:

vec2 texel = vec2(1.0/tHeightSize); 

và textureSize là chiều rộng và chiều cao của heightmap. Tuy nhiên, khi tôi sử dụng chức năng này tôi nhận được kết quả này:?

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

enter image description here

Đó bây giờ có vẻ tồi tệ hơn :(Bất kỳ ý tưởng những gì tôi có thể làm sai Hoặc làm thế nào tôi có thể nhận được một mẫu địa hình mượt mà

EDIT

đây là một ảnh chụp màn hình thẳng đứng nhìn xuống địa hình. Bạn có thể thấy các lớp hoạt động tốt. Chú ý tuy nhiên đó các lớp bên ngoài có ít triangulation và trông mượt mà hơn trong khi những người có tessellation cao hơn hiển thị từng pixel. Tôi đang cố gắng tìm cách để làm mịn mẫu lấy mẫu.

enter image description here enter image description here

+0

Tại sao bạn sử dụng nội suy tuyến tính tùy chỉnh ở vị trí đầu tiên? Nếu mỗi đỉnh có một pixel trong bản đồ chiều cao, bạn nên sử dụng Gauss-Blur trên texture để làm cho nó 'mượt mà'. Nếu bạn có nhiều đỉnh hơn pixel, nội suy kết cấu dựng sẵn sẽ thực hiện công việc. – dari

+0

Hi dari, Im sẽ phải chỉnh sửa câu hỏi của tôi để làm rõ. Lý do là bởi vì tôi đang sử dụng một kỹ thuật geoclipmapping. Địa hình gần camera là một cái nhìn rất cao. Bởi vì tessellation quá cao, có nhiều hình tam giác hơn có pixel. Vì vậy, nó không phải là một tỷ lệ 1-1. tức là việc lấy mẫu cần phải tốt hơn, hoặc đúng hơn là cần phải nội suy giữa các giá trị pixel. – Mat

+0

Và tại sao bạn không sử dụng bản dựng trong nội suy? https: //www.opengl.org/wiki/Sampler_Object # Lấy mẫu_parameters – dari

Trả lời

3

tôi đã có thể tìm và thực hiện một kỹ thuật sử dụng catmulrom suy. Mã dưới đây.

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

Nó rất hữu ích! Cảm ơn. Bạn có thể chia sẻ kết quả (hình ảnh) không? – Nolesh