2016-08-11 23 views
0

我正在試圖在Threejs中做一個tilesystem:地面爲綠色/水爲藍色。在我的着色器中丟失的碎片

我在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

相關問題