不知道错哪了

来源:6-3 透视投影

小小奥

2022-12-14

{
  function initShader(gl: WebGLRenderingContext, VERTEX_SHADER_SOURCE, FRAGMENT_SHADER_SOURCE) {
    // 创建着色器
    const vertexShader = gl.createShader(gl.VERTEX_SHADER)!
    // 创建片元着色器
    const fragmentShader = gl.createShader(gl.FRAGMENT_SHADER)!

    gl.shaderSource(vertexShader, VERTEX_SHADER_SOURCE) // 指定 着色器的源码
    gl.shaderSource(fragmentShader, FRAGMENT_SHADER_SOURCE) // 指定 片元着色器的源码

    // 编译着色器
    gl.compileShader(vertexShader)
    gl.compileShader(fragmentShader)

    // 创建一个程序对象
    const program = gl.createProgram()!

    // 指定 着色器
    gl.attachShader(program, vertexShader)
    gl.attachShader(program, fragmentShader)

    gl.linkProgram(program)

    gl.useProgram(program)
    return program
  }

  const ctx = document.getElementById('canvas') as HTMLCanvasElement

  const gl = ctx.getContext('webgl')!
  
  /** 顶点着色器 */
  const VERTEX_SHADER_SOURCE = `
    attribute vec4 aColor;
    varying vec4 vColor;
    attribute vec4 aPosition;
    uniform mat4 mat;
    void main() {
      gl_Position = mat * aPosition;
      vColor = aColor;
    }
  `

  /* 片元着色器 */
  const FRAGMENT_SHADER_SOURCE = `
    precision lowp float;
    varying vec4 vColor;

    void main() {
      // vec4() => 将 vec3 的数据 转换为 vec4
      gl_FragColor = vColor;
    }
  `

  const program = initShader(gl, VERTEX_SHADER_SOURCE, FRAGMENT_SHADER_SOURCE)
  
  const aPosition = gl.getAttribLocation(program, 'aPosition')
  const aColor = gl.getAttribLocation(program, 'aColor')
  const mat = gl.getUniformLocation(program, 'mat')

  function getTranslateMatrix(x = 0, y = 0, z = 0) {
    return new Float32Array([
      1.0, 0.0, 0.0, 0.0,
      0.0, 1.0, 0.0, 0.0,
      0.0, 0.0, 1.0, 0.0,
      x, y, z, 1
    ])
  }

  // 创建顶点数据
  // 给 attribute vec4 aPosition 变量赋值
  const points = new Float32Array([
    0.75, 1.0, 0.6,  1.0, 0.0, 0.0,
    0.25, -1.0, 0.6,  1.0, 0.0, 0.0,
    1.0, -1.0, 0.6,  1.0, 0.0, 0.0,

    0.75, 1.0, 0.5,  0.0, 1.0, 0.0,
    0.25, -1.0, 0.5,  0.0, 1.0, 0.0,
    1.0, -1.0, 0.5,  0.0, 1.0, 0.0,
    
    0.75, 1.0, 0.4,  0.0, 0.0, 1.0,
    0.25, -1.0, 0.4,  0.0, 0.0, 1.0,
    1.0, -1.0, 0.4,  0.0, 0.0, 1.0,

    -0.75, 1.0, 0.6,  1.0, 0.0, 0.0,
    -0.25, -1.0, 0.6,  1.0, 0.0, 0.0,
    -1.0, -1.0, 0.6,  1.0, 0.0, 0.0,

    -0.75, 1.0, 0.5,  0.0, 1.0, 0.0,
    -0.25, -1.0, 0.5,  0.0, 1.0, 0.0,
    -1.0, -1.0, 0.5,  0.0, 1.0, 0.0,
    
    -0.75, 1.0, 0.4,  0.0, 0.0, 1.0,
    -0.25, -1.0, 0.4,  0.0, 0.0, 1.0,
    -1.0, -1.0, 0.4,  0.0, 0.0, 1.0,
  ])

  // 创建缓冲区 对象
  
  const buffer = gl.createBuffer()

  const BYTES = points.BYTES_PER_ELEMENT

  // 绑定缓冲区 对象
  gl.bindBuffer(gl.ARRAY_BUFFER, buffer)
  gl.bufferData(gl.ARRAY_BUFFER, points, gl.STATIC_DRAW)

  gl.vertexAttribPointer(aPosition, 3, gl.FLOAT, false, BYTES * 6, 0)
  gl.enableVertexAttribArray(aPosition)

  gl.vertexAttribPointer(aColor, 3, gl.FLOAT, false, BYTES * 6, BYTES * 3)
  gl.enableVertexAttribArray(aColor)

  gl.drawArrays(gl.TRIANGLES, 0, 3 * 6)


  /** 创建 透视投影矩阵 */
  // fov 视角
  // aspect 宽高比
  // far 块
  function getPerspective(fov, aspect, far, near) {
    fov = fov * Math.PI / 100
    return new Float32Array([
      1/(aspect*Math.tan(fov/2)), 0, 0, 0,
      0, 1/(Math.tan(fov/2)), 0, 0,
      0, 0, -(far + near)/(far - near), -(2*far*near)/(far-near),
      0, 0, -1, 0
    ])
  }


  let eyex = 0.0
  let eyey = -0.1
  let eyez = 0.2
  function draw() {
    const vm = getViewMatrix(eyex, eyey, eyez, 0.0, 0.0, 0.0, 0.0, 0.6, 0.0)
    console.log('vm', vm)
    const perspective = getPerspective(150, ctx.width / ctx.height, 100, 1)
    console.log('perspective', perspective)
    gl.uniformMatrix4fv(mat, false, maxMatrix(vm, perspective))
    gl.drawArrays(gl.TRIANGLES, 0, 3 * 6)
    // requestAnimationFrame(draw) 
  }
  draw()

  document.onkeydown = function (e) {
    switch(e.keyCode) {
      case 37:
        eyex += 0.01
        break
      case 38:
        eyex -= 0.01
        break
      case 39:
        eyey += 0.01
        break
      case 40:
        eyey -= 0.01
        break
    }
    draw()
  }

  // 归一化 函数
  function normalized(arr: Float32Array) {
    let sum = 0

    for (let i = 0; i < arr.length; i++) {
      sum += arr[i] * arr[i]
    }
      // 返回 目标数字的 平方根 => 4 -> 2 9 -> 3
    const middle = Math.sqrt(sum)

    for (let i = 0; i < arr.length; i++) {
      arr[i] = arr[i] / middle
    }
  }

  // 叉积函数, 获取法向量
  function cross(a, b) {
    return new Float32Array([
      a[1] * b[2] - a[2] * b[1],
      a[2] * b[0] - a[0] * b[2],
      a[0] * b[1] - a[1] * b[0]
    ])
  }

  // 实现点积 函数, 获取 投影长度
  function dot(a, b) {
    return a[0] * b[0] + a[1] * b[1] + a[2] * b[2]
  }

  // 向量差
  function minus(a, b) {
    return new Float32Array([
      a[0] - b[0],
      a[1] - b[1],
      a[2] - b[2]
    ])
  }

  // 视图 矩阵获取
  function getViewMatrix(eyex, eyey, eyez, lookAtx, lookAty, lookAtz, upx, upy, upz) {
    // 视点
    const eye = new Float32Array([eyex, eyey, eyez])
    // 目标点
    const lookAt = new Float32Array([lookAtx, lookAty, lookAtz])
    // 上方向
    const up = new Float32Array([upx, upy, upz])

    // z 轴的向量差 通过 视点 和 目标点 确定
    const z = minus(eye, lookAt)

    normalized(z)
    normalized(up)

    // 确定 x 轴
    const x = cross(z, up)

    normalized(x)

    // 确定 y 轴
    const y = cross(x, z)

    return new Float32Array([
      x[0], y[0], z[0], 0,
      x[1], y[1], z[1], 0,
      x[2], y[2], z[2], 0,
      -dot(x, eye), -dot(y, eye), -dot(z, eye), 1
    ])
  }

  // 获取 正射投影矩阵
  function getOrtho(l, r, t, b, n, f) {
    return  new Float32Array([
      2 / (r - l), 0, 0, 0,
      0, 2 / (t - b), 0, 0,
      0, 0, -2 / (f - n), 0,
      - (r + l) / (r - l), -(t + b) / (t - b), -(f + n)/(f - n), 1
    ])
  }

  function maxMatrix(A, B) {
    const result = new Float32Array(16)
    for (let i = 0; i < 4; i++) {
      result[i] = A[i] * B[0] + A[i + 4] * B[1] + A[i + 8] * B[2] + A[i + 12] * B[3]
      result[i + 4] = A[i] * B[4] + A[i + 4] * B[5] + A[i + 8] * B[6] + A[i + 12] * B[7]
      result[i + 8] = A[i] * B[8] + A[i + 4] * B[9] + A[i + 8] * B[10] + A[i + 12] * B[11]
      result[i + 12] = A[i] * B[12] + A[i + 4] * B[13] + A[i + 8] * B[14] + A[i + 12] * B[15]
    }
    return result
  }
}

6个三角形 没有渲染出来, 不知道错哪了
老师你能不能把最新的代码 提交一下, 我看着视频对比 代码 有点难受

写回答

2回答

yancy

2022-12-15

points里的坐标出现了问题,z坐标是负的就可以看到图形了。像这种

,,-, ,,,
,-,-, ,,,
, -,-, ,,,

,,-, ,,,
,-,-, ,,,
, -,-, ,,,

,,-, ,,,
,-,-, ,,,
, -,-, ,,,

-,,-, ,,,
-,-,-, ,,,
-, -,-, ,,,

-,,-, ,,,
-,-,-, ,,,
-, -,-, ,,,

-,,-, ,,,
-,-,-, ,,,
-, -,-, ,,,

-0.6, -0.5,-0.4

代码已经上传上去了,可以在代码库里重新拉一下

0
2
小小奥
好了, 非常感谢!
2022-12-15
共2条回复

yancy

2022-12-14

好的,我传下代码。过会儿我看下问题出在哪儿了

0
0

WebGL+Three.js 入门与实战,系统学习 Web3D 技术

前端的技术蓝海,涨薪好选择

1081 学习 · 294 问题

查看课程