2016-08-11 7 views
0

私はThreejsでタイルシステムを実行しようとしています。シェイダーの断片が失われました

私はPlaneBufferGeometryでシェーダーを使用しています。ここで

は、私がこれまで持っているものです。

関連するコード:

  • JS:変数chunkと機能DoPlaneStuff()(両方とも冒頭)
  • HTML:頂点とフラグメントシェーダ

var chunk = { 
 
    // number of width and height segments for PlaneBuffer 
 
    segments: 32, 
 
    // Heightmap: 0 = water, 1 = ground 
 
    heightmap: [ 
 
    [1, 0, 0], 
 
    [1, 1, 0], 
 
    [1, 0, 1], 
 
    ], 
 
    // size of the plane 
 
    size: 40 
 
}; 
 

 
function DoPlaneStuff() { 
 
    var uniforms = { 
 
    heightmap: { 
 
     type: "iv1", 
 
     // transform the 2d Array to a simple array 
 
     value: chunk.heightmap.reduce((p, c) => p.concat(c), []) 
 
    }, 
 
    hmsize: { 
 
     type: "f", 
 
     value: chunk.heightmap[0].length 
 
    }, 
 
    coord: { 
 
     type: "v2", 
 
     value: new THREE.Vector2(-chunk.size/2, -chunk.size/2) 
 
    }, 
 
    size: { 
 
     type: "f", 
 
     value: chunk.size 
 
    } 
 
    }; 
 
    console.info("UNIFORMS GIVEN :", uniforms); 
 
    var shaderMaterial = new THREE.ShaderMaterial({ 
 
    uniforms: uniforms, 
 
    vertexShader: document.getElementById("v_shader").textContent, 
 
    fragmentShader: document.getElementById("f_shader").textContent 
 
    }); 
 
    var plane = new THREE.Mesh(
 
    new THREE.PlaneBufferGeometry(chunk.size, chunk.size, chunk.segments, chunk.segments), 
 
    shaderMaterial 
 
); 
 
    plane.rotation.x = -Math.PI/2; 
 
    scene.add(plane); 
 
} 
 

 

 
// --------------------- END OF RELEVANT CODE 
 

 

 
window.addEventListener("load", Init); 
 

 
function Init() { 
 
    Init3dSpace(); 
 
    DoPlaneStuff(); 
 
    Render(); 
 
} 
 

 
var camera_config = { 
 
    dist: 50, 
 
    angle: (5/8) * (Math.PI/2) 
 
} 
 
var scene, renderer, camera; 
 
function Init3dSpace() { 
 
    scene = new THREE.Scene(); 
 
    renderer = new THREE.WebGLRenderer({ 
 
    antialias: true, 
 
    logarithmicDepthBuffer: true 
 
    }); 
 
    camera = new THREE.PerspectiveCamera(
 
    50, 
 
    window.innerWidth/window.innerHeight, 
 
    0.1, 
 
    1000 
 
); 
 
    this.camera.position.y = camera_config.dist * Math.sin(camera_config.angle); 
 
    this.camera.position.x = 0; 
 
    this.camera.position.z = 0 + camera_config.dist * Math.cos(camera_config.angle); 
 
    this.camera.rotation.x = -camera_config.angle; 
 
    var light = new THREE.HemisphereLight(0xffffff, 10); 
 
    light.position.set(0, 50, 0); 
 
    scene.add(light); 
 
    renderer.setSize(window.innerWidth, window.innerHeight); 
 
    document.body.appendChild(renderer.domElement); 
 
} 
 

 
function Render() { 
 
    renderer.render(scene, camera); 
 
}
body { 
 
    overflow: hidden; 
 
    margin: 0; 
 
}
<script src="//cdnjs.cloudflare.com/ajax/libs/three.js/r70/three.min.js"></script> 
 
<!-- VERTEX SHADER --> 
 
<script id="v_shader" type="x-shader/x-vertex"> 
 
    // size of the plane 
 
    uniform float size; 
 
    // coordinates of the geometry 
 
    uniform vec2 coord; 
 
    // heightmap size (=width and height of the heightmap) 
 
    uniform float hmsize; 
 
    uniform int heightmap[9]; 
 
    varying float colorValue; 
 
    
 
    void main() { 
 
    int xIndex = int(floor( 
 
     (position.x - coord.x)/(size/hmsize) 
 
    )); 
 
    int yIndex = int(floor(
 
     (-1.0 * position.y - coord.y)/(size/hmsize) 
 
    )); 
 
    // Get the index of the corresponding tile in the array 
 
    int index = xIndex + int(hmsize) * yIndex; 
 
    // get the value of the tile 
 
    colorValue = float(heightmap[index]); 
 
    
 
    gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0); 
 
    } 
 
</script> 
 
<!-- FRAGMENT SHADER --> 
 
<script id="f_shader" type="x-shader/x-fragment"> 
 
    varying float colorValue; 
 
    
 
    void main() { 
 
    // default color is something is not expected: RED 
 
    gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0); 
 
    // IF WATER 
 
    if (colorValue == 0.0) { 
 
     // BLUE 
 
     gl_FragColor = vec4(0.0, 0.0, 1.0, 1.0); 
 
    } 
 
    // IF GROUND 
 
    if (colorValue == 1.0) { 
 
     // GREEN 
 
     gl_FragColor = vec4(0.1, 0.6, 0.0, 1.0); 
 
    } 
 
    } 
 
</script>

あなたはそれがほとんど働いているが、私は緑と青の領域を分割し、これらの赤い線を持っていると私はその理由を把握することはできません見ることができるように。 これらの赤い断片は、いずれのタイルにもマップされていないため、「失われたもの」と呼ばれています。理由は分かりません。

chunk.segments(ジオメトリの高さと幅のセグメント数)の値が大きいほど、赤い線が細くなることがわかりました。

赤の代わりに緑と青のゾーンの間にグラデーションの塗りつぶしをする方法を知りたいと思います。

答えて

1

赤い線は、いくつかの頂点が地面タイルにあり、他の頂点が水タイルにある三角形によって形成されます。その後、GPUは三角形に沿ってcolorValueを補間して、予想通りの鋭いステップではなく、0から1までの値を持つ滑らかなグラデーションを生成します。

これにはいくつかの解決策があります。中間点に基づいて色を選択するためにシェーダの状態を変更することができます。colorValue < 0.5の場合は青色、そうでない場合は緑色を出力します。あなたがより多くのタイルタイプを後でしたいと思うなら、それはうまくいきません。より良い解決策は、すべての三角形のすべての頂点が単一のタイルにあるようにジオメトリを生成することです。これには、タイルの境界にある頂点を倍増させる必要があります。 flat補間修飾子をcolorValueに追加することもできますが、使用する頂点の属性を制御するのは難しくなります。

...私はあなたが鋭いステップではなくグラデーションが必要なことに気付きました。それはさらに簡単です。カラーセレクトコードをフラグメントシェーダから頂点シェーダに移動し、結果として得られる補間カラーをフラグメントシェーダに戻す必要があります。

+0

答えをありがとう。 "GPUが三角形に沿ってcolorValueを補間する"それで、私はさまざまなintを持つことができませんでした!しかし、私はあなたの "より良い解決策"の意味を理解していないのですが、いくつかのリソースを持っていますか? – Apolo