2017-11-08 2 views
0

私はWebGLモデルの階層を学習しており、胴に接続された独立した可動アームセグメントを持つロボットを描画するプログラムを作成しました。私はこれを達成することができました。スライダを介して操作するまで、右上腕と下腕がレンダリングされないという副作用がありました。ロボットの右側が操作されるまでレンダリングされませんWebGL

物事は私が試してみました:

は、左右の腕、効果なしの両方のために別々の変数を宣言します。 スタックからプッシュ/ポップする代わりにmodelViewMatrixのコピーを作成します。効果はありません。 drawrobot関数を無効にして、レンダリング関数内で独立した階層(腕)を直接描画します。効果はありません。 チェックしてください。何も見つかりませんでした。

私は本当に私の問題を突き止めようとしています。ヘルプ/感謝のアイデアは、コードは以下の通りです:

<html> 
 

 
<script id="vertex-shader" type="x-shader/x-vertex"> 
 
attribute vec4 vPosition; 
 
attribute vec4 vColor; 
 
varying vec4 fColor; 
 

 
uniform mat4 modelViewMatrix; 
 
uniform mat4 projectionMatrix; 
 

 
void main() 
 
{ 
 
    fColor = vColor; 
 
    gl_Position = projectionMatrix * modelViewMatrix * vPosition; 
 
} 
 
</script> 
 

 
<script id="fragment-shader" type="x-shader/x-fragment"> 
 

 
precision mediump float; 
 

 
varying vec4 fColor; 
 

 
void main() 
 
{ 
 
    gl_FragColor = fColor; 
 
} 
 
</script> 
 

 
<script type="text/javascript" src="../Common/webgl-utils.js"></script> 
 
<script type="text/javascript" src="../Common/initShaders.js"></script> 
 
<script type="text/javascript" src="../Common/MV.js"></script> 
 
<script type="text/javascript" src="myrobotArm.js"></script> 
 

 
<div id="slider1"> 
 
body angle -180 <input id="slide" type="range" 
 
min="-180" max="180" step="10" value="0" 
 
    /> 
 
180 
 
</div><br/> 
 

 
<div id="slider2"> 
 
lower leftarm angle -180 <input id="slide" type="range" 
 
min="-180" max="180" step="10" value="0" 
 
    /> 
 
180 
 
</div><br/> 
 

 
<div id="slider3"> 
 
upper leftarm angle -180 <input id="slide" type="range" 
 
min="-180" max="180" step="10" value="0" 
 
    /> 
 
180 
 
</div><br/> 
 

 
<div id="slider4"> 
 
lower rightarm angle -180 <input id="slide" type="range" 
 
min="-180" max="180" step="10" value="0" 
 
    /> 
 
180 
 
</div><br/> 
 

 
<div id="slider5"> 
 
upper rightarm angle -180 <input id="slide" type="range" 
 
min="-180" max="180" step="10" value="0" 
 
    /> 
 
180 
 
</div><br/> 
 

 
<body> 
 
<canvas id="gl-canvas" width="512"" height="512" 
 
Oops ... your browser doesn't support the HTML5 canvas element 
 
</canvas> 
 
</body> 
 
</html>

var NumVertices = 36; //(6 faces)(2 triangles/face)(3 vertices/triangle) 
 

 
var points = []; 
 
var colors = []; 
 
var myStack = []; 
 

 

 
var vertices = [ 
 
    vec4(-0.5, -0.5, 0.5, 1.0), 
 
    vec4(-0.5, 0.5, 0.5, 1.0), 
 
    vec4( 0.5, 0.5, 0.5, 1.0), 
 
    vec4( 0.5, -0.5, 0.5, 1.0), 
 
    vec4(-0.5, -0.5, -0.5, 1.0), 
 
    vec4(-0.5, 0.5, -0.5, 1.0), 
 
    vec4( 0.5, 0.5, -0.5, 1.0), 
 
    vec4( 0.5, -0.5, -0.5, 1.0) 
 
]; 
 

 
// RGBA colors 
 
var vertexColors = [ 
 
    vec4(0.0, 0.0, 0.0, 1.0), // black 
 
    vec4(1.0, 0.0, 0.0, 1.0), // red 
 
    vec4(1.0, 1.0, 0.0, 1.0), // yellow 
 
    vec4(0.0, 1.0, 0.0, 1.0), // green 
 
    vec4(0.0, 0.0, 1.0, 1.0), // blue 
 
    vec4(1.0, 0.0, 1.0, 1.0), // magenta 
 
    vec4(1.0, 1.0, 1.0, 1.0), // white 
 
    vec4(0.0, 1.0, 1.0, 1.0) // cyan 
 
]; 
 

 

 
// Parameters controlling the size of the Robot's arm 
 

 
var BASE_HEIGHT  = 5.0; 
 
var BASE_WIDTH  = 2.0; 
 
var LOWER_ARM_HEIGHT = 0.5; 
 
var LOWER_ARM_WIDTH = 2.0; 
 
var UPPER_ARM_HEIGHT = 0.5; 
 
var UPPER_ARM_WIDTH = 2.0; 
 

 
var LOWERR_ARM_HEIGHT = 0.5; 
 
var LOWERR_ARM_WIDTH = 2.0; 
 
var UPPERR_ARM_HEIGHT = 0.5; 
 
var UPPERR_ARM_WIDTH = 2.0; 
 

 
// Shader transformation matrices 
 

 
var modelViewMatrix, projectionMatrix; 
 

 
// Array of rotation angles (in degrees) for each rotation axis 
 

 
var Base = 0; 
 
var LowerArmL = 1; 
 
var UpperArmL = 2; 
 
var LowerArmR = 3; 
 
var UpperArmR = 4; 
 

 
var theta= [ 0, 0, 0]; 
 

 
var angle = 0; 
 

 
var modelViewMatrixLoc; 
 

 
var vBuffer, cBuffer; 
 

 
//---------------------------------------------------------------------------- 
 

 
function quad( a, b, c, d) { 
 
    colors.push(vertexColors[a]); 
 
    points.push(vertices[a]); 
 
    colors.push(vertexColors[a]); 
 
    points.push(vertices[b]); 
 
    colors.push(vertexColors[a]); 
 
    points.push(vertices[c]); 
 
    colors.push(vertexColors[a]); 
 
    points.push(vertices[a]); 
 
    colors.push(vertexColors[a]); 
 
    points.push(vertices[c]); 
 
    colors.push(vertexColors[a]); 
 
    points.push(vertices[d]); 
 
} 
 

 

 
function colorCube() { 
 
    quad(1, 0, 3, 2); 
 
    quad(2, 3, 7, 6); 
 
    quad(3, 0, 4, 7); 
 
    quad(6, 5, 1, 2); 
 
    quad(4, 5, 6, 7); 
 
    quad(5, 4, 0, 1); 
 
} 
 

 
//____________________________________________ 
 

 
// Remmove when scale in MV.js supports scale matrices 
 

 
function scale4(a, b, c) { 
 
    var result = mat4(); 
 
    result[0][0] = a; 
 
    result[1][1] = b; 
 
    result[2][2] = c; 
 
    return result; 
 
} 
 

 

 
//-------------------------------------------------- 
 

 

 
window.onload = function init() { 
 

 
    canvas = document.getElementById("gl-canvas"); 
 
    
 
    gl = WebGLUtils.setupWebGL(canvas); 
 
    if (!gl) { alert("WebGL isn't available"); } 
 
    
 
    gl.viewport(0, 0, canvas.width, canvas.height); 
 
    
 
    gl.clearColor(1.0, 1.0, 1.0, 1.0); 
 
    gl.enable(gl.DEPTH_TEST); 
 
    
 
    // 
 
    // Load shaders and initialize attribute buffers 
 
    // 
 
    program = initShaders(gl, "vertex-shader", "fragment-shader"); 
 
    
 
    gl.useProgram(program); 
 

 
    colorCube(); 
 
    
 
    // Load shaders and use the resulting shader program 
 
    
 
    program = initShaders(gl, "vertex-shader", "fragment-shader");  
 
    gl.useProgram(program); 
 

 
    // Create and initialize buffer objects 
 
    
 
    vBuffer = gl.createBuffer(); 
 
    gl.bindBuffer(gl.ARRAY_BUFFER, vBuffer); 
 
    gl.bufferData(gl.ARRAY_BUFFER, flatten(points), gl.STATIC_DRAW); 
 
    
 
    var vPosition = gl.getAttribLocation(program, "vPosition"); 
 
    gl.vertexAttribPointer(vPosition, 4, gl.FLOAT, false, 0, 0); 
 
    gl.enableVertexAttribArray(vPosition); 
 

 
    cBuffer = gl.createBuffer(); 
 
    gl.bindBuffer(gl.ARRAY_BUFFER, cBuffer); 
 
    gl.bufferData(gl.ARRAY_BUFFER, flatten(colors), gl.STATIC_DRAW); 
 

 
    var vColor = gl.getAttribLocation(program, "vColor"); 
 
    gl.vertexAttribPointer(vColor, 4, gl.FLOAT, false, 0, 0); 
 
    gl.enableVertexAttribArray(vColor); 
 

 
    document.getElementById("slider1").onchange = function(event) { 
 
     theta[0] = event.target.value/2; 
 
    }; 
 
    document.getElementById("slider2").onchange = function(event) { 
 
     theta[1] = event.target.value/2; 
 
    }; 
 
    document.getElementById("slider3").onchange = function(event) { 
 
     theta[2] = event.target.value/2; 
 
    }; 
 
    document.getElementById("slider4").onchange = function(event) { 
 
     theta[3] = event.target.value/2; 
 
    }; 
 
    document.getElementById("slider5").onchange = function(event) { 
 
     theta[4] = event.target.value/2; 
 
    }; 
 

 
    modelViewMatrixLoc = gl.getUniformLocation(program, "modelViewMatrix"); 
 

 
    projectionMatrix = ortho(-10, 10, -10, 10, -10, 10); 
 
    gl.uniformMatrix4fv(gl.getUniformLocation(program, "projectionMatrix"), false, flatten(projectionMatrix)); 
 
    
 
    render(); 
 
} 
 

 
//---------------------------------------------------------------------------- 
 

 

 
function base() { 
 
    var s = scale4(BASE_WIDTH, BASE_HEIGHT, BASE_WIDTH); 
 
    var instanceMatrix = mult(translate(0.0, 0.5 * BASE_HEIGHT, 0.0), s); 
 
    var t = mult(modelViewMatrix, instanceMatrix); 
 
    gl.uniformMatrix4fv(modelViewMatrixLoc, false, flatten(t)); 
 
    gl.drawArrays(gl.TRIANGLES, 0, NumVertices); 
 
} 
 

 
//---------------------------------------------------------------------------- 
 

 

 
function upperArmL() { 
 
    var s = scale4(UPPER_ARM_WIDTH, UPPER_ARM_HEIGHT, UPPER_ARM_WIDTH); 
 
    var instanceMatrix = mult(translate(-0.5 * UPPER_ARM_WIDTH, 0.0, 0.0),s);  
 
    var t = mult(modelViewMatrix, instanceMatrix); 
 
    gl.uniformMatrix4fv(modelViewMatrixLoc, false, flatten(t)); 
 
    gl.drawArrays(gl.TRIANGLES, 0, NumVertices); 
 
} 
 

 
//---------------------------------------------------------------------------- 
 

 

 
function lowerArmL() 
 
{ 
 
    var s = scale4(LOWER_ARM_WIDTH, LOWER_ARM_HEIGHT, LOWER_ARM_WIDTH); 
 
    var instanceMatrix = mult(translate(-0.5 * LOWER_ARM_WIDTH, 0.0, 0.0),s); 
 
    var t = mult(modelViewMatrix, instanceMatrix); 
 
    gl.uniformMatrix4fv(modelViewMatrixLoc, false, flatten(t)); 
 
    gl.drawArrays(gl.TRIANGLES, 0, NumVertices); 
 
} 
 

 
function upperArmR() { 
 
    var s = scale4(UPPERR_ARM_WIDTH, UPPERR_ARM_HEIGHT, UPPERR_ARM_WIDTH); 
 
    var instanceMatrix = mult(translate(0.5 * UPPERR_ARM_WIDTH, 0.0, 0.0),s);  
 
    var t = mult(modelViewMatrix, instanceMatrix); 
 
    gl.uniformMatrix4fv(modelViewMatrixLoc, false, flatten(t)); 
 
    gl.drawArrays(gl.TRIANGLES, 0, NumVertices); 
 
} 
 

 
//---------------------------------------------------------------------------- 
 

 

 
function lowerArmR() 
 
{ 
 
    var s = scale4(LOWERR_ARM_WIDTH, LOWERR_ARM_HEIGHT, LOWERR_ARM_WIDTH); 
 
    var instanceMatrix = mult(translate(0.5 * LOWERR_ARM_WIDTH, 0.0, 0.0),s); 
 
    var t = mult(modelViewMatrix, instanceMatrix); 
 
    gl.uniformMatrix4fv(modelViewMatrixLoc, false, flatten(t)); 
 
    gl.drawArrays(gl.TRIANGLES, 0, NumVertices); 
 
} 
 
//---------------------------------------------------------------------------- 
 

 
function drawRobot() 
 
{ 
 
    modelViewMatrix = rotate(theta[Base], 0, 1, 0); 
 
    var myMVM = modelViewMatrix; 
 
    // myStack.push(modelViewMatrix); 
 
    base(); 
 
    
 
    // modelViewMatrix = myStack.pop(); 
 
    // modelViewMatrix = myMVM; 
 
    // myStack.push(modelViewMatrix); 
 
    modelViewMatrix = mult(modelViewMatrix, translate(-0.5 * BASE_WIDTH, BASE_HEIGHT - 0.5 * UPPER_ARM_HEIGHT, 0.0)); //POSITION OF RECT 
 
    modelViewMatrix = mult(modelViewMatrix, rotate(theta[UpperArmL], 0, 0, 1)); //ROTATE AROUND Z AXIS BY UPPERARML Degrees 
 
    upperArmL(); 
 

 
    modelViewMatrix = mult(modelViewMatrix, translate(-UPPER_ARM_WIDTH, 0.0, 0.0)); 
 
    modelViewMatrix = mult(modelViewMatrix, rotate(theta[LowerArmL], 0, 0, 1)); 
 
    lowerArmL(); 
 

 
    // modelViewMatrix = myStack.pop(); 
 
    modelViewMatrix = myMVM; 
 
    modelViewMatrix = mult(modelViewMatrix, translate(0.5 * BASE_WIDTH, BASE_HEIGHT - 0.5 * UPPERR_ARM_HEIGHT, 0.0)); 
 
    modelViewMatrix = mult(modelViewMatrix, rotate(theta[UpperArmR], 0, 0, 1)); 
 
    upperArmR(); 
 

 
    modelViewMatrix = mult(modelViewMatrix, translate(UPPERR_ARM_WIDTH, 0.0, 0.0)); 
 
    modelViewMatrix = mult(modelViewMatrix, rotate(theta[LowerArmR], 0, 0, 1)); 
 
    lowerArmR(); 
 
} 
 

 
var render = function() { 
 

 
    gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT); 
 
    drawRobot(); 
 
    requestAnimFrame(render); 
 
}

+0

最初の段落の情報は無関係なので削除しました。 *あなたが投稿したコードに関して、コードがエラーなく実行され、意図したとおりに動作する*より多くの詳細を提供すれば、おそらくもっと速く答えを得るのに役立ちます。 –

+0

@Cos 'var myMVM = new ...'、 'myMVM.copy(modelViewMatrix)'のように、 'var myMVM = modelViewMatrix;'、 'myMVM'と' modelViewMatrix'の後ろに同じオブジェクト。 – Rabbid76

+0

私は応答を感謝します。私の本で使われているメソッドでは、スタックに親として使用したい行列をプッシュし、各子ブランチ変換を行う前にポップ/プッシュバックして、継承された各子の最初のmodelViewMatrix(胴体)変換を保持しますつかいます。これにより、腕全体が描かれた後でpop/pushを呼び出すだけで腕のセグメントを追加することができます。私はこのアプローチを試みました。それは私の現在の "varを作成し、それを保存したい行列に設定する"と同じ結果を与えます。それで、それは適切に通過しています。 – Cos

答えて

0

私がコメントを追加することはできません、それがないので、私のanswereはおそらくrejectectされますあなたの問題を直接解決することができますが、多くの人があなたとまったく同じ理由であなたと同様の問題を抱えているため、私が思うことを言う:オブジェクト変換階層管理の適応力のないアプローチ。

あなたが気づいたように、どこから問題が発生しているのか正確に知るのは難しいですが、スライダを操作する(データを強制的に更新する)ことで状況が「表示される」と言うので、初期状態では間違った値に関連しています。とにかく、あなたのプログラムが変換行列を管理する方法は、デバッグと制御を容易にしません。それを調整するのは難しいでしょう。これは、良いアプローチを使用しないためです。

残念なことに、書籍や教科書はほとんど変換階層を管理する正しい方法を提供しません。代わりに、これは命令的なプログラミングスタイルに適応しているため、この古いポップ/プッシュマトリックスアプローチを使用した例を示しています。良いアプローチは、章全体を再作成するでしょう。

変換階層の原理は非常に単純です。各オブジェクトの「最終マトリックス」は、すべての親の累積変換とそれ自身の変換の結果です。変換階層を管理する適切な方法は、階層構造の論理構造をプログラム構造に反映させることです。つまり、オブジェクトを扱うことによって、つまりオブジェクト指向プログラムのパラダイムで考えることです。

これを適切に管理するには、各ノードに親と子があるノードを持つGraphを作成する必要があります。つまり、a Sceneの構造です。ここでは、実装する必要がある基本的なオブジェクトは、次のとおりです。

function Node() { 
    this.parent = null; 
    this.childs = new Array(); 
    this.matrix = new Float32Array(16); 
    this.worldMatrix = new Float32Array(16); 

    setIdentity(this.matrix); 
    setIdentity(this.worldMatrix); 
} 

MyNode.prototype = { 

    setParent(parent) { 
    // very simple parenting management 
    this.parent = parent; 
    parent.childs.psuh(this); 
    }, 

    updateMatrix() { 
    // recursive matrix update (other methods are possible) 
    if(this.parent) { 
     this.parent.updateMatrix(); 
     this.worldMatrix = multiply(this.matrix, this.parent.worldMatrix); 
    } else { 
     this.worldMatrix = this.matrix; 
    } 
    }, 
} 

そして、ここではこれを使用する方法です。

let torso = new Node(); 

let upperArmR = new Node(); 
upperArmR.setParent(torso); 

let lowerArmR = new Node(); 
lowerArmR.setParent(upperArmR); 

let upperArmL = new Node(); 
upperArmL.setParent(torso); 

let lowerArmL = new Node(); 
lowerArmL.setParent(upperArmL); 

あなたがこれを持っていたら、各オブジェクトが持っているので、あなたが探検することができ、階層構造を持っています特定された親、および子供。あなたは、そのローカル行列で、各オブジェクトのローカル変換を制御する全ての階層を更新し、このように、描画するために、最終的な世界行列を使用することができます。

// this is pseudocode.. 
rotate(upperArmR.matrix, upperArmRRotation); 
rotate(lowerArmR.matrix, lowerArmRRotation); 

upperArmR.updateMatrix(); 
lowerArmR.updateMatrix(); 

gl.uniformMatrix4fv(modelViewMatrixLoc, false, upperArmR.worldMatrix); 
// draw 
gl.uniformMatrix4fv(modelViewMatrixLoc, false, lowerArmR.worldMatrix); 
// draw 

さて、あなたはシーン階層および変換の微調整を持っています、それぞれのマトリックスを独立してデバッグして間違った変換をキャッチすることができ、簡単にこのすべてをアニメーション化することができます。

私の例では、再帰関数を使用して階層ツリー全体のすべての行列を常に再計算することに注意してください。この場合、各子行列更新に対して親行列が再計算されるため再び。それを防ぐには、いくつかの解決策があります。 1つはノードにフラグを追加して、マトリックスが最新であることを伝え、次の一般的な更新まで再計算する必要はありません。別の方法は、再帰呼び出しを使わずにグラフを深く調べることです。最初に、各ノードを適切な階層順に更新します。私はあなたがこれを達成するための方法を見つけるためのキーワードとして「Depth-First Traversal」または「Depth-First Search」を使ってGoogleを探検させました。

+0

非常に有益なポストをありがとう。私は教科書に記載されているツリーベースのアプローチを知っていました。しかし、私のインストラクターはクラスのスタックバージョンだけをカバーしていました。だから私は自分のコードを開発したときに、私はその方法を試みた。私はなぜそれが機能していないのか尋ねたところ、基本マトリックスのコピーを作って各バージョンのアームを使用してバージョンを動作させる必要があると私に言いました。今週末には時間があるので、ツリーアプローチで再構築し、私のバグを見つけることができるかどうかを確認します。 – Cos

+0

変換階層用の行列のスタックを実際のプロジェクトで実行することは実用的ではありませんが、すぐに地獄になります。わずか3〜4つのオブジェクトでも、プッシュとポップの間でこれを管理するのが難しくなります。スマートツリー構造の作成にはしばらく時間がかかりますが、完了すると自由にシーンを複雑にすることができます。 – dest1

関連する問題