2014-05-17 7 views
0

아래는 내 Value Noise 구현이며, 지형 생성에 사용하고 있습니다. 지형의 길이 (Y 크기)가 너비 (X 크기)보다 길면 이상한 아티팩트가 생성되지만 그렇지 않은 경우에는 이상한 아티팩트가 생성됩니다.다른 모든 행을 고정하는 것은 값 소음 알고리즘 구현에서 옮겨 놓습니다.

나는 몇 시간 동안 이것을보고있었습니다. 이 문제의 원인은 무엇입니까?

합니다 (demo에서 스크린 샷 당신이 할 수있는 브라우저 콘솔에서 코드를 엉망 아래 코드 뒤에 THREE.Terrain.Value = ValueNoise; rebuild();으로 바꾸어 결과를 즉시 참조하십시오.).

1 : 1 화면 비율 :

1:1 Aspect Ratio

1 : 1.1 종횡비 :

1:1.1 Aspect Ratio

/** 
* Generate a heightmap using white noise. 
* 
* @param {Vector3[]} g The terrain vertices. 
* @param {Object} options Settings 
* @param {Number} scale The resolution of the resulting heightmap. 
* @param {Number} segments The width of the target heightmap. 
* @param {Number} range The altitude of the noise. 
* @param {Number[]} data The target heightmap. 
*/ 
function WhiteNoise(g, options, scale, segments, range, data) { 
    if (scale > segments) return; 
    var i = 0, 
     j = 0, 
     xl = segments, 
     yl = segments, 
     inc = Math.floor(segments/scale), 
     k; 
    // Walk over the target. For a target of size W and a resolution of N, 
    // set every W/N points (in both directions). 
    for (i = 0; i <= xl; i += inc) { 
     for (j = 0; j <= yl; j += inc) { 
      k = j * xl + i; 
      data[k] = Math.random() * range; 
      /* c b * 
      * l t */ 
      var t = data[k], 
       l = data[ j  * xl + (i-inc)] || t, // left 
       b = data[(j-inc) * xl + i  ] || t, // bottom 
       c = data[(j-inc) * xl + (i-inc)] || t; // corner 
      // Interpolate between adjacent points to set the height of 
      // higher-resolution target data. 
      for (var lastX = i-inc, x = lastX; x < i; x++) { 
       for (var lastY = j-inc, y = lastY; y < j; y++) { 
        if (x === lastX && y === lastY) continue; 
        var px = ((x-lastX)/inc), 
         py = ((y-lastY)/inc), 
         r1 = px * b + (1-px) * c, 
         r2 = px * t + (1-px) * l; 
        data[y * xl + x] = py * r2 + (1-py) * r1; 
       } 
      } 
     } 
    } 
    // Assign the temporary data back to the actual terrain heightmap. 
    // Accumulate additively across multiple calls to WhiteNoise. 
    for (i = 0, xl = options.xSegments + 1; i < xl; i++) { 
     for (j = 0, yl = options.ySegments + 1; j < yl; j++) { 
      k = j * xl + i; 
      g[k].z += data[k] || 0; 
     } 
    } 
} 

/** 
* Generate random terrain using value noise. 
* 
* The basic approach of value noise is to generate white noise at a 
* smaller octave than the target and then interpolate to get a higher- 
* resolution result. This is then repeated at different resolutions. 
* 
* @param {Vector3[]} g The terrain vertices. 
* @param {Object} options Settings 
*/ 
ValueNoise = function(g, options) { 
    // Set the segment length to the smallest power of 2 that is greater 
    // than the number of vertices in either dimension of the plane 
    var segments = Math.max(options.xSegments, options.ySegments) + 1, n; 
    for (n = 1; Math.pow(2, n) < segments; n++) {} 
    segments = Math.pow(2, n); 

    // Store the array of white noise outside of the WhiteNoise function to 
    // avoid allocating a bunch of unnecessary arrays; we can just 
    // overwrite old data each time WhiteNoise() is called. 
    var data = new Array(segments*(segments+1)); 

    // Layer white noise at different resolutions. 
    var range = options.maxHeight - options.minHeight; 
    for (var i = 2; i < 7; i++) { 
     WhiteNoise(g, options, Math.pow(2, i), segments, range * Math.pow(2, 2.4-i*1.2), data); 
    } 

    // Clamp and stretch the results 
    THREE.Terrain.Clamp(g, { 
     maxHeight: options.maxHeight, 
     minHeight: options.minHeight, 
     stretch: true, 
    }); 
}; 

답변

2

임시 data 필드의 높이 변경을 할당하면 두 개의 서로 다른지도 크기 (원본지도와 다음지도의 임시지도가 2 개이므로 두 개의 다른 색인이 실제로 할당됩니다.) :

for (i = 0, xl = options.xSegments + 1; i < xl; i++) { 
    for (j = 0, yl = options.ySegments + 1; j < yl; j++) { 
     var kg = j * xl + i; 
     var kd = j * segments + i; 

     g[kg] += data[kd]; 
    } 
} 

data 색인에 하나씩 잘못된 내용이있을 수 있습니다. data의 크기는 (segments + 1) * (segments + 1)이어야합니다. 두 셀 모두 외부 셀이 필요하고 xlylsegments + 1이어야합니다.

+0

나는 인터넷을 사랑합니다. [Committed] (https://github.com/IceCreamYou/THREE.Terrain/commit/eef8f9002e51e3d419c83f7ac03142f6ed82e029), 감사합니다. 나는 fencepost 오류에 대해 잘 모르겠지만 내가 잠시를 조사 할 것입니다. – IceCreamYou

+0

나는 또한 fencepost에 대해 100 % 확신하지는 않지만 조금 좋아 보인다. 예를 들어, 보조 행렬의 크기가 64 인 경우 인덱스 0과 64에서 두 경계를 모두 사용합니다. 즉, 양방향으로 65 개의 배열이 필요하며 평면 인덱스를 계산할 때 65를 사용해야합니다. 지표는 두 번째 이미지에서 고독한 스파이크가 될 수 있습니다.이 스파이크는 가까운 가장자리에서 이상한 랩 어라운드처럼 보입니다. –

+0

아무리 노력해도 fencepost 오류를 얻을 수 없었습니다. 그런데'data'에'Float32Array'를 사용하고 유물을 얻었으므로 여러분이 제안한 크기로 만들었고 다시 작동하기 시작했습니다. 그래서 두 번 감사드립니다. :-) ([commit] (https://github.com/IceCreamYou/THREE.Terrain/commit/0e8ca7903507f4a7d08898fa925425c3373cd983)) – IceCreamYou