2017-11-08 4 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

답변을 주셔서 감사합니다. 내 책에서 사용 된 방법은 스택으로 부모로 사용하고자하는 행렬을 밀어 넣은 다음 각 자식 분기 변환을 수행하기 전에 다시 pop/push하여 각 상속 된 자식에 대한 초기 modelViewMatrix (몸통) 변환을 보존합니다. 용도. 팔 전체가 그려진 후에 pop/push를 호출하여 팔 세그먼트를 추가 할 수 있습니다.이 팔 세그먼트는 자연스러운 조인트 이동을 위해 서로 연결됩니다. 이 방법을 시도해 보니 현재의 "var를 만들어서 보존하고자하는 행렬로 설정"하는 것과 같은 결과를 얻을 수 있습니다. 그래서 제대로 전달됩니다. – Cos

답변

0

내가 주석을 추가 할 수 없습니다, 내 answere은 아마하지 않기 때문에 rejectect됩니다 감사 도움말/아이디어, 코드는 다음과 같습니다 많은 사람들이 당신과 똑같은 이유로 똑같은 문제를 가지고 있기 때문에 내가 생각하는 바를 말합니다 : 객체 변형 계층 관리의 부적절한 접근.

자신이 알아 차렸으므로 어디에서 문제가 발생했는지 정확하게 알기는 어렵지만 슬라이더를 조작하면 데이터를 강제 업데이트하면 문제가 "표시"됩니다. 문제가 발생했을 가능성이 큽니다. 초기 상태에서 잘못된 값과 관련이있다. 어쨌든 프로그램이 변환 행렬을 관리하는 방식으로 디버그하고 제어하기가 쉽지는 않습니다. 좋은 방법을 사용하지 않기 때문에 조정하기가 어렵습니다.

불행히도 책이나 학습법이 거의 없기 때문에 변환 계층 구조를 올바르게 관리 할 수 ​​있습니다. 그 대신, 이러한 명령은 이전의 팝/푸시 매트릭스 방식을 사용하는 예제를 제공합니다. 이는 이것이 명령형 프로그래밍 스타일에 맞게 조정되고 빠르게 작성되기 때문입니다. 좋은 접근 방식은 전체 장을 다시 채울 것입니다.

변환 계층 원리는 매우 간단합니다. 각 개체의 "최종 행렬"은 모든 부모의 누적 변환과 자체 변환의 결과입니다. 변환 계층 구조를 관리하는 적절한 방법은 프로그램 구조에서 계층 구조의 논리적 구조를 반영하는 것입니다. 즉, 객체로 작업함으로써 객체 지향 프로그래밍 패러다임에서 생각하는 것입니다.

제대로 관리하려면 각 노드에 부모와 자식이있는 노드가있는 그래프를 만들어야합니다. 즉, a 장면 구조. 다음은 구현해야하는 기본 객체입니다

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 

지금, 당신은 당신의 장면 계층 구조와 변화에 잘 제어 할 수 있습니다, 각각의 행렬을 독립적으로 디버그하여 잘못된 변환을 잡아낼 수 있으며 모든 것을 쉽게 애니메이션으로 만들 수 있습니다.

그러나 필자는 필자가 전체 계층 트리의 모든 행렬을 항상 재 계산하기 위해 재귀 함수를 사용합니다.이 경우 계산 손실이 발생합니다.이 경우 각 자식 행렬 업데이트에 대해 부모 행렬이 다시 계산되므로 다시. 이를 방지하기 위해 몇 가지 해결책이 있습니다. 하나는 노드에 플래그를 추가하여 행렬이 최신 상태이고 다음 일반 업데이트까지 다시 계산할 필요가 없다는 것을 알려주는 것입니다. 또 하나의 방법은 재귀 호출을 사용하지 않고 깊이있는 그래프를 탐색하여 각 노드를 올바른 계층 구조 순서로 업데이트하는 것입니다. 나는 이것을 달성하기위한 방법을 발견하기 위해 "깊이 우선 탐색"또는 "깊이 우선 탐색"을 키워드로 사용하여 Google을 탐색 할 수있게했습니다.

+0

매우 유익한 게시물을 보내 주셔서 감사합니다. 내 교과서에서 다룬대로 트리 기반 접근 방식을 알고있었습니다. 그러나 강사는 수업 중 스택 버전 만 다루었습니다. 그래서 내 코드를 개발할 때, 나는 그 방법을 시도했다. 왜 그것이 작동하지 않는지 물었을 때, 그는 기본 매트릭스의 사본을 만들어야하고, 각 팔을 위해 자신의 버전을 작동하도록 설정해야한다고 말했습니다. 그래서 나는 대신 그 방법을 시도했습니다. 이번 주말에 시간이 좀있어서 트리 접근 방식으로 다시 빌드하고 버그를 찾을 수 있는지 보겠습니다. – Cos

+0

변환 계층 구조에 대한 행렬의 스택을 실제 프로젝트에서는 실용적이지 못합니다. 이것은 지옥이됩니다. 단 3 ~ 4 개의 개체로도 푸시와 팝 사이에서 관리하기가 어려워집니다. 스마트 트리 구조를 만드는 데는 시간이 걸리지 만 일단 완료되면 자유롭게 원하는대로 장면을 복잡하게 만들 수 있습니다. – dest1

관련 문제