2017-04-14 68 views
1

我需要使用Android中的Opengl ES 2.0爲每個三角面(不是每個頂點)計算法線。但我無法直接在片段着色器中傳遞屬性。Android OpenGL ES 2.0,爲每個三角形計算正常值

實測值的一個解決方案:重複頂點每個三角,並通過三角面法線爲頂點着色器一個屬性。

但我不想重複頂點。我使用頂點索引繪製三角形。

那麼,一個頂點是由多個三角形共享的,那麼我該如何計算三角面法師。

p.s.我是opengl的新手。

+0

你已經是解釋自己。如果這些頂點相同,則只能共享頂點。因此,如果2個頂點具有相同的位置,但法線不同,則它們不能表示相同的頂點。你可以使用一個幾何着色器,但是更方便的是不共享這樣的頂點。 – Vallentin

+0

幾何着色器在Opengl ES 2.0中不可用。 我需要根據它們的方向對三角形進行着色(這就是爲什麼我需要表面法線,並且不能重複頂點),如此圖像中所示。 https://raw.githubusercontent.com/Jam3/jam3-lesson-webgl-shader-threejs/master/images/3.png – Ashish

+0

沒有注意到它是OpenGL ES。然而,這並沒有改變我原先所說的話。不要共享明顯不能共享的頂點。 – Vallentin

回答

1

最簡單的解決方案就是複製頂點。頂點着色器很少是瓶頸。我不知道你的具體需求,但是,複製頂點不是一個好的解決方案。例如,如果網格被剝皮和動畫化,這意味着頂點着色器中會發生大量計算。另一種情況是,網格在頂點着色器中以某種奇怪的方式動畫,並且必須重新計算法線。顯然,你不能計算頂點着色器中的每個面法線。你可以在幾何着色器中做到這一點,但我們在OpenGL ES 2.0中沒有。但是,有一個簡單的解決方案 - 在片段着色器中計算法線!所以,如果頂點的重複不會爲你工作,這裏是解決方案:

  1. 我們需要一個OpenGL擴展 - standard_derivatives,它被廣泛的支持,但你仍然需要檢查它是否支持該設備在運行代碼之前。要啓用擴展,你必須將下列行添加到片段着色器它的代碼之前:

    #extension GL_OES_standard_derivatives : enable 
    
  2. 我們需要一個不同的變量在世界座標的頂點位置。它應該在頂點着色器中計算,並且它如何完成取決於你的着色器。它用於很多需求,所以你可能已經在頂點着色器中計算了它。因此,讓我們假設,我們有這條線在片段着色器:

    varying vec3 positionWorld; 
    
  3. 我們需要相機的視圖矩陣。你可能已經傳遞了一個片段着色器。讓我們假設我們在片段着色器有這樣的統一:

    uniform mat4 viewMatrix; 
    
  4. 現在,我們要計算正常。首先,我們計算一個正常的視圖空間,然後轉換到世界空間。爲了計算正常在viewspace,我們使用導函數:

    vec3 normalViewSpace = normalize(cross(dFdx(positionWorldSpace), dFdy(positionWorldSpace))); 
    

    這裏的位置的衍生物被取相對於x和y在屏幕空間座標。這意味着我們有兩個向量位於平面上。爲了獲得正常的表面,我們做了一個交叉產品。當然,結果不是單位矢量,所以我們也需要對它進行標準化。

  5. 最後一步是計算世界空間中的法線。視圖矩陣應用從世界空間到視圖空間的轉換。有人可能會認爲我們需要計算它的逆矩陣,因爲我們需要從視圖空間到世界空間,但由於視圖矩陣是正交矩陣,矩陣的轉置也是其逆矩陣,因此代碼將爲:

    vec3 normalWorldSpace = (vec4(normalViewSpace, 0.0) * viewMatrix).xyz; 
    
  6. 爲了使生活更輕鬆,我們可以換到的一切功能:

    vec3 ReconstructNormal(vec3 positionWorldSpace) 
    { 
        vec3 normalViewSpace = normalize(cross(dFdx(positionWorldSpace), dFdy(positionWorldSpace))); 
        vec3 normalWorldSpace = (vec4(normalViewSpace, 0.0) * viewMatrix).xyz; 
        return normalWorldSpace; 
    } 
    

現在我們在世界空間重建正常。下面只是一個簡單的例子,爲什麼這可能非常有用。請注意,由於它使用WebGL,它也與OpenGL ES 2.0兼容。

var container; 
 
var camera, scene, renderer; 
 
var mesh; 
 
var uniforms; 
 

 
var clock = new THREE.Clock(); 
 

 
init(); 
 
animate(); 
 

 
function init() { 
 
    container = document.getElementById('container'); 
 

 
    camera = new THREE.PerspectiveCamera(40, window.innerWidth/window.innerHeight, 0.1, 100); 
 
    camera.position.z = 0.6; 
 
    camera.position.y = 0.2; 
 
    camera.rotation.x = -0.45; 
 

 
    scene = new THREE.Scene(); 
 

 
    var boxGeometry = new THREE.PlaneGeometry(0.75, 0.75, 32, 32); 
 
     
 
    var heightMap = THREE.ImageUtils.loadTexture("data:image/png;base64,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"); 
 
      
 
    heightMap.wrapT = heightMap.wrapS = THREE.RepeatWrapping; 
 

 
    uniforms = {u_time: {type: "f", value: 0.0 }, u_heightMap: {type: "t",value:heightMap} }; 
 

 
    var material = new THREE.ShaderMaterial({ 
 
    uniforms: uniforms, 
 
     side: THREE.DoubleSide, 
 
     wireframe: false, 
 
     vertexShader: document.getElementById('vertexShader').textContent, 
 
     fragmentShader: document.getElementById('fragment_shader').textContent 
 
    }); 
 

 

 
    mesh = new THREE.Mesh(boxGeometry, material); 
 
    mesh.rotation.x = 3.14/2.0; 
 
    scene.add(mesh); 
 

 
    renderer = new THREE.WebGLRenderer(); 
 
    renderer.setClearColor(0x000000, 1); 
 
    container.appendChild(renderer.domElement); 
 

 
    onWindowResize(); 
 

 
    window.addEventListener('resize', onWindowResize, false); 
 
} 
 

 
function onWindowResize(event) { 
 
    camera.aspect = window.innerWidth/window.innerHeight; 
 
    camera.updateProjectionMatrix(); 
 
    renderer.setSize(window.innerWidth, window.innerHeight); 
 
} 
 

 
function animate() { 
 
    requestAnimationFrame(animate); 
 
    render(); 
 
} 
 

 
function render() { 
 
    var delta = clock.getDelta(); 
 
    uniforms.u_time.value += delta; 
 
    //mesh.rotation.z += delta * 0.5; 
 
    renderer.render(scene, camera); 
 
}
body { margin: 0px; overflow: hidden; }
<script src="https://threejs.org/build/three.min.js"></script> 
 
<div id="container"></div> 
 

 
<script id="fragment_shader" type="x-shader/x-fragment"> 
 
    #extension GL_OES_standard_derivatives : enable 
 
    
 
    varying vec3 positionWorld; // position of vertex in world coordinates 
 
    
 
    vec3 ReconstructNormal(vec3 positionWorldSpace) 
 
    { 
 
     vec3 normalViewSpace = normalize(cross(dFdx(positionWorldSpace), dFdy(positionWorldSpace))); 
 
     vec3 normalWorldSpace = (vec4(normalViewSpace, 0.0) * viewMatrix).xyz; 
 
     return normalWorldSpace; 
 
    } 
 

 
    // Just some example of using a normal. Here we do a really simple shading 
 
    void main(void) 
 
    { 
 
     vec3 lightDir = normalize(vec3(1.0, 1.0, 1.0)); 
 
     vec3 normal = ReconstructNormal(positionWorld); 
 
     float diffuse = max(dot(lightDir, normal), 0.0); 
 
     vec3 albedo = vec3(0.2, 0.4, 0.7); 
 
     gl_FragColor = vec4(albedo * diffuse, 1.0);  
 
    } 
 
</script> 
 

 
<script id="vertexShader" type="x-shader/x-vertex"> 
 
    uniform lowp sampler2D u_heightMap; 
 
    uniform float u_time; 
 
    
 
    varying vec3 positionWorld; 
 
       
 
    // Example of vertex shader that moves vertices 
 
    void main() 
 
    { 
 
     vec3 pos = position; 
 
     vec2 offset1 = vec2(1.0, 0.5) * u_time * 0.01; 
 
     vec2 offset2 = vec2(0.5, 1.0) * u_time * 0.01; 
 
     float hight1 = texture2D(u_heightMap, uv + offset1).r * 0.02; 
 
     float hight2 = texture2D(u_heightMap, uv + offset2).r * 0.02; 
 
     pos.z += hight1 + hight2; 
 
     vec4 mvPosition = modelViewMatrix * vec4(pos, 1.0); 
 
     positionWorld = mvPosition.xyz; 
 
     gl_Position = projectionMatrix * mvPosition; 
 
    } 
 
</script>

+0

「在片段着色器中計算法線」是我想要的。我想渲染三角形並旋轉觸摸事件,並且他們應該根據計算的法線改變顏色。 – Ashish