2017-04-14 10 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

最も簡単な解決策は、頂点を複製することです。頂点シェーダは、めったにボトルネックではありません。あなたの具体的なニーズはわかりませんが、頂点を複製することは良い解決策ではありません。たとえば、メッシュがスキンでアニメーション化されている場合は、頂点シェーダで多くの計算が行われます。もう1つのケースは、メッシュが頂点シェーダで変わった形でアニメーション化され、法線を再計算する必要がある場合です。明らかに、頂点シェーダで面の法線ごとに計算することはできません。あなたはジオメトリシェーダでそれを行うことができますが、OpenGL ES 2.0にはありません。しかし、フラグメントシェーダで法線を計算するという簡単な解決策があります。頂点の重複があなたのために動作しないのであれば、ここでのソリューションです:私たちは、OpenGLの拡張が必要になります

  1. - 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は画面空間の座標。つまり、平面上にある2つのベクトルがあります。表面に垂直になるように、私たちはクロスプロダクトを行います。確かに、結果は単位ベクトルではないので、正規化する必要もあります。

  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

関連する問題