在WebGL中进行层次转换

在WebGL中进行层次转换,webgl,webgl2,Webgl,Webgl2,我正在做太阳系的模拟,它只包含太阳(点光源)、地球和月球,我可以在屏幕上成功地看到这些恒星,而我只对它们进行了平移 下面是示例屏幕 但当我把轨道转换加入到地球上时,我得到了一个奇怪的结果 似乎地球在日落时被太阳卡住了,但至少我能看到月亮不知何故在绕着地球旋转 当我把轨道变换也应用到月球上时,我得到了这个结果 正如你所看到的,地球和月球都被太阳卡住了 下面是我希望如何组织它们的层次结构转换的代码和树 function RenderPerSec(gl, sun, SunModelMatrix,

我正在做太阳系的模拟,它只包含太阳(点光源)、地球和月球,我可以在屏幕上成功地看到这些恒星,而我只对它们进行了平移

下面是示例屏幕

但当我把轨道转换加入到地球上时,我得到了一个奇怪的结果

似乎地球在日落时被太阳卡住了,但至少我能看到月亮不知何故在绕着地球旋转

当我把轨道变换也应用到月球上时,我得到了这个结果

正如你所看到的,地球和月球都被太阳卡住了

下面是我希望如何组织它们的层次结构转换的代码和树

function RenderPerSec(gl, sun, SunModelMatrix, SunNormalMat, 
  earth, EarthModelMatrix, EarthNormalMat,
  moon, MoonModelMatrix, MoonNormalMat, 
  MvpMatrix, loc_uModelMatrix, loc_uNormalMatrix, loc_uMvpMatrix, 
  loc_uSunTrigger, loc_uEarthTrigger, loc_uMoonTrigger,
  w, h)
{
  gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);


  ///Hierarchical Transformation///


  /*
                     P
                     |
                     V
                     |
                 SUN(Fixed)
                     |
                   EARTH
          Translation from the sun                      
           Rotation around the sun 
              /      |        \ 
tilted 23.5 degree  MOON     Rotation itself
 Along the X-axis    |
         Translation from the earth
          Rotation around the earth
              Rotation itself..

*/

  let MVPStack = [];
  MvpMatrix.setIdentity();


  //Projection
  MvpMatrix.setPerspective(60, w/h, 1, 1000);
  //View
  MvpMatrix.lookAt(0, 15, 10, 0, 0, 0, 0, 1, 0);

  //Model Transforms...

  //Sun

  SunModelMatrix.setTranslate(0, 0, 0);

  MvpMatrix.multiply(SunModelMatrix);

  MVPStack.push(new Matrix4(MvpMatrix));


  gl.uniform1i(loc_uSunTrigger, 1);
  gl.uniform1i(loc_uEarthTrigger, 0);
  gl.uniform1i(loc_uMoonTrigger, 0);

  RenderSun(gl, sun, SunModelMatrix, SunNormalMat, MvpMatrix, loc_uModelMatrix, loc_uNormalMatrix, loc_uMvpMatrix);

  //Earth, translation and rotation 23.5 along the X-axis, rotation itself
  EarthModelMatrix.setTranslate(5, 0, 0); //Translation from the sun
  EarthModelMatrix.setRotate(CURRENT_EATHR_REVOLVING_ANGLE, 0, 1, 0); //Revolving around the sun

  MvpMatrix = MVPStack.pop();
  MvpMatrix.multiply(EarthModelMatrix);

  MVPStack.push(new Matrix4(MvpMatrix));

  gl.uniform1i(loc_uSunTrigger, 0);
  gl.uniform1i(loc_uEarthTrigger, 1);
  gl.uniform1i(loc_uMoonTrigger, 0);

  RenderEarth(gl, earth, EarthModelMatrix, EarthNormalMat, MvpMatrix, loc_uModelMatrix, loc_uNormalMatrix, loc_uMvpMatrix);


  //Moon, translation and rotation itself
  MoonModelMatrix.setTranslate(2.5, 0, 0);
  MoonModelMatrix.setRotate(CURRENT_MOON_REVOLVING_ANGLE, 0, 1, 0);

  MvpMatrix = MVPStack.pop();
  MvpMatrix.multiply(MoonModelMatrix, EarthModelMatrix);

  gl.uniform1i(loc_uSunTrigger, 0);
  gl.uniform1i(loc_uEarthTrigger, 0);
  gl.uniform1i(loc_uMoonTrigger, 1);

  RenderMoon(gl, moon, MoonModelMatrix, MoonNormalMat, MvpMatrix, loc_uModelMatrix, loc_uNormalMatrix, loc_uMvpMatrix);
}
如果在此代码中删除setRotate函数,我可以得到第一个结果

这是渲染函数

function RenderSun(gl, sun, SunModelMatrix, SunNormalMat, MvpMatrix, loc_uModelMatrix, loc_uNormalMatrix, loc_uMvpMatrix)
{
  gl.bindVertexArray(sun.vao);


  SunNormalMat.setInverseOf(SunModelMatrix);
  SunNormalMat.transpose();

  // Pass the model matrix to uModelMatrix
  gl.uniformMatrix4fv(loc_uModelMatrix, false, SunModelMatrix.elements);

  // Pass the model view projection matrix to umvpMatrix
  gl.uniformMatrix4fv(loc_uMvpMatrix, false, MvpMatrix.elements);

  // Pass the transformation matrix for normals to uNormalMatrix
  gl.uniformMatrix4fv(loc_uNormalMatrix, false, SunNormalMat.elements);

  gl.drawElements(gl.TRIANGLES, sun.n, sun.type, 0);
}

function RenderEarth(gl, earth, EarthModelMatrix, EarthNormalMat, MvpMatrix, loc_uModelMatrix, loc_uNormalMatrix, loc_uMvpMatrix)
{
  gl.bindVertexArray(earth.vao);

  EarthNormalMat.setInverseOf(EarthModelMatrix);
  EarthNormalMat.transpose();

  gl.uniformMatrix4fv(loc_uModelMatrix, false, EarthModelMatrix.elements);

  gl.uniformMatrix4fv(loc_uMvpMatrix, false, MvpMatrix.elements);

  gl.uniformMatrix4fv(loc_uNormalMatrix, false, EarthNormalMat.elements);

  gl.drawElements(gl.TRIANGLES, earth.n, earth.type, 0);
}

function RenderMoon(gl, moon, MoonModelMatrix, MoonNormalMat, MvpMatrix, loc_uModelMatrix, loc_uNormalMatrix, loc_uMvpMatrix)
{
  gl.bindVertexArray(moon.vao);

  MoonNormalMat.setInverseOf(MoonModelMatrix);
  MoonNormalMat.transpose();

  gl.uniformMatrix4fv(loc_uModelMatrix, false, MoonModelMatrix.elements);

  gl.uniformMatrix4fv(loc_uMvpMatrix, false, MvpMatrix.elements);

  gl.uniformMatrix4fv(loc_uNormalMatrix, false, MoonNormalMat.elements);

  gl.drawElements(gl.TRIANGLES, moon.n, moon.type, 0);
}

我正在使用堆栈来实现分层转换。。。有人能帮我吗?

有一篇关于这个和基于堆栈的文章

一般来说,您需要执行以下操作

push(0,0,0)
  push(sun rotation)
    draw sun
  pop()  // sun rotation
  push(earth orbit rotation)
    push(earth translation)
      push(earth rotation)
        draw earth
      pop() // earth rotation
      push(moon orbit rotation)
        push(moon translation)
          push(moon rotation)
            draw moon
          pop()  // moon rotation
        pop()  // moon translation
      pop()  // moon orbit rotation
    pop()  // earth translation
  pop()  // earth orbit rotation
pop()  // center of solar system
  mathlib.translate(centerOfRotation)  // move 0,0,0 to center of rotation
  mathlib.rotate(orbitRotation)        // rotate space
  mathlib.translate(orbitRadius)       // move some distance from center in rotated space
我不熟悉您的矩阵数学库,但名为
setTranslate
setRotate
的函数听起来不像是合适的函数。它们听起来像是设置了平移或旋转,而不是将现有矩阵乘以平移矩阵或旋转矩阵

在大多数三维数学库中,如果要使球体显示在距旋转中心一定距离的位置,则类似于

push(0,0,0)
  push(sun rotation)
    draw sun
  pop()  // sun rotation
  push(earth orbit rotation)
    push(earth translation)
      push(earth rotation)
        draw earth
      pop() // earth rotation
      push(moon orbit rotation)
        push(moon translation)
          push(moon rotation)
            draw moon
          pop()  // moon rotation
        pop()  // moon translation
      pop()  // moon orbit rotation
    pop()  // earth translation
  pop()  // earth orbit rotation
pop()  // center of solar system
  mathlib.translate(centerOfRotation)  // move 0,0,0 to center of rotation
  mathlib.rotate(orbitRotation)        // rotate space
  mathlib.translate(orbitRadius)       // move some distance from center in rotated space
或者更长的形式

  mat = identity();
  mat = mathlib.multiply(mat, mathlib.translation(centerOfRotation))
  mat = mathlib.multiply(mat, mathlib.rotatation(orbitRotation))
  mat = mathlib.multiply(mat, mathlib.translation(orbitRadius))
如果它是一个自动堆叠库,那么较短的形式应该已经堆叠了3个矩阵

注意,因为您似乎唯一遇到问题的部分是矩阵堆栈部分,这里有一些代码使用矩阵堆栈来计算3个矩阵(太阳、地球、月亮),然后将这些矩阵与2D画布一起使用(您可以忽略)

“严格使用”;
const ctx=document.querySelector('canvas').getContext('2d');
常数m4=twgl.m4;
常量堆栈=[];
const current=()=>stack[stack.length-1];
常量pop=()=>stack.pop();
const identity=()=>stack.push(m4.identity());
consttranslate=(t)=>stack.push(m4.translate(current(),t));
const rotate=(轴,r)=>stack.push(m4.axisRotate(当前(),轴,r));
常量zAxis=[0,0,1];
函数渲染(时间){
时间*=0.001;//转换为秒
twgl.resizeCanvasToDisplaySize(ctx.canvas);
const{width,height}=ctx.canvas;
setTransform(1,0,0,1,0,0);
ctx.clearRect(0,0,宽度,高度);
让阳光普照;
让地球垫;
让月光垫;
身份();
//平移到太阳系中心
平移([width/2,height/2,0]);
旋转(zAxis,时间*4);//太阳旋转
sunMat=当前();
pop();//太阳旋转
旋转(zAxis,时间/2)//推动(地球轨道旋转)
平移([height/4,0,0]);//推(地球平移)
旋转(zAxis,时间*8);//推动(地球旋转)
接地网=电流()//
pop();//地球自转
旋转(zAxis,时间*2);//推(月球轨道旋转)
平移([height/8,0,0]);//推(月亮平移)
旋转(zAxis,时间*16);//推(月亮旋转)
moonMat=current();
pop();//月亮旋转
pop();//月亮翻译
pop();//月球轨道旋转
pop();//地球平移
pop();//地球轨道旋转
pop();//太阳系中心
pop();//标识
drawSquare(sunMat,40,'橙色');
drawSquare(earthMat,20,'蓝色');
drawSquare(月光垫,10,'灰色');
请求动画帧(渲染);
}
请求动画帧(渲染);
功能drawSquare(垫、尺寸、颜色){
ctx.setTransform(mat[0]、mat[1]、mat[4]、mat[5]、mat[12]、mat[13]);
ctx.strokeStyle=颜色;
ctx.strokeRect(-size/2,-size/2,size,size);
}
body{margin:0;}
画布{宽度:100vw;高度:100vh;显示:块;}

有一篇关于这方面的文章,其中一篇是基于堆栈的

一般来说,您需要执行以下操作

push(0,0,0)
  push(sun rotation)
    draw sun
  pop()  // sun rotation
  push(earth orbit rotation)
    push(earth translation)
      push(earth rotation)
        draw earth
      pop() // earth rotation
      push(moon orbit rotation)
        push(moon translation)
          push(moon rotation)
            draw moon
          pop()  // moon rotation
        pop()  // moon translation
      pop()  // moon orbit rotation
    pop()  // earth translation
  pop()  // earth orbit rotation
pop()  // center of solar system
  mathlib.translate(centerOfRotation)  // move 0,0,0 to center of rotation
  mathlib.rotate(orbitRotation)        // rotate space
  mathlib.translate(orbitRadius)       // move some distance from center in rotated space
我不熟悉您的矩阵数学库,但名为
setTranslate
setRotate
的函数听起来不像是合适的函数。它们听起来像是设置了平移或旋转,而不是将现有矩阵乘以平移矩阵或旋转矩阵

在大多数三维数学库中,如果要使球体显示在距旋转中心一定距离的位置,则类似于

push(0,0,0)
  push(sun rotation)
    draw sun
  pop()  // sun rotation
  push(earth orbit rotation)
    push(earth translation)
      push(earth rotation)
        draw earth
      pop() // earth rotation
      push(moon orbit rotation)
        push(moon translation)
          push(moon rotation)
            draw moon
          pop()  // moon rotation
        pop()  // moon translation
      pop()  // moon orbit rotation
    pop()  // earth translation
  pop()  // earth orbit rotation
pop()  // center of solar system
  mathlib.translate(centerOfRotation)  // move 0,0,0 to center of rotation
  mathlib.rotate(orbitRotation)        // rotate space
  mathlib.translate(orbitRadius)       // move some distance from center in rotated space
或者更长的形式

  mat = identity();
  mat = mathlib.multiply(mat, mathlib.translation(centerOfRotation))
  mat = mathlib.multiply(mat, mathlib.rotatation(orbitRotation))
  mat = mathlib.multiply(mat, mathlib.translation(orbitRadius))
如果它是一个自动堆叠库,那么较短的形式应该已经堆叠了3个矩阵

注意,因为您似乎唯一遇到问题的部分是矩阵堆栈部分,这里有一些代码使用矩阵堆栈来计算3个矩阵(太阳、地球、月亮),然后将这些矩阵与2D画布一起使用(您可以忽略)

“严格使用”;
const ctx=document.querySelector('canvas').getContext('2d');
常数m4=twgl.m4;
常量堆栈=[];
const current=()=>stack[stack.length-1];
常量pop=()=>stack.pop();
const identity=()=>stack.push(m4.identity());
consttranslate=(t)=>stack.push(m4.translate(current(),t));
const rotate=(轴,r)=>stack.push(m4.axisRotate(当前(),轴,r));
常量zAxis=[0,0,1];
函数渲染(时间){
时间*=0.001;//转换为秒
twgl.resizeCanvasToDisplaySize(ctx.canvas);
const{width,height}=ctx.canvas;
setTransform(1,0,0,1,0,0);
ctx.clearRect(0,0,宽度,高度);
让阳光普照;
让地球垫;
让月光垫;
身份();
//平移到太阳系中心
平移([width/2,height/2,0]);
旋转(zAxis,时间*4);//太阳旋转
sunMat=当前();
pop();//太阳旋转
旋转(zAxis,时间/2)//推动(地球轨道旋转)
平移([height/4,0,0])