Loading [MathJax]/jax/output/CommonHTML/config.js
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
社区首页 >问答首页 >这些顶点是如何在剪辑坐标(-1,1)中结束的?

这些顶点是如何在剪辑坐标(-1,1)中结束的?
EN

Stack Overflow用户
提问于 2019-02-14 00:37:25
回答 1查看 165关注 0票数 0

大家好,这几天我一直在学习webGl,并且在webGl2上读了这本教科书。

下面是本书中的一个例子。

代码语言:javascript
运行
AI代码解释
复制
'use strict';

// A set of utility functions for /common operations across our application
const utils = {

  // Find and return a DOM element given an ID
  getCanvas(id) {
    const canvas = document.getElementById(id);

    if (!canvas) {
      console.error(`There is no canvas with id ${id} on this page.`);
      return null;
    }

    return canvas;
  },

  // Given a canvas element, return the WebGL2 context
  getGLContext(canvas) {
    return canvas.getContext('webgl2') || console.error('WebGL2 is not available in your browser.');
  },

  // Given a canvas element, expand it to the size of the window
  // and ensure that it automatically resizes as the window changes
  autoResizeCanvas(canvas) {
    const expandFullScreen = () => {
      canvas.width = window.innerWidth;
      canvas.height = window.innerHeight;
    };
    expandFullScreen();
    // Resize screen when the browser has triggered the resize event
    window.addEventListener('resize', expandFullScreen);
  },

  // Given a WebGL context and an id for a shader script,
  // return a compiled shader
  getShader(gl, id) {
    const script = document.getElementById(id);
    if (!script) {
      return null;
    }

    const shaderString = script.text.trim();

    let shader;
    if (script.type === 'x-shader/x-vertex') {
      shader = gl.createShader(gl.VERTEX_SHADER);
    } else if (script.type === 'x-shader/x-fragment') {
      shader = gl.createShader(gl.FRAGMENT_SHADER);
    } else {
      return null;
    }

    gl.shaderSource(shader, shaderString);
    gl.compileShader(shader);

    if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {
      console.error(gl.getShaderInfoLog(shader));
      return null;
    }

    return shader;
  },

  // Normalize colors from 0-255 to 0-1
  normalizeColor(color) {
    return color.map(c => c / 255);
  },

  // De-normalize colors from 0-1 to 0-255
  denormalizeColor(color) {
    return color.map(c => c * 255);
  },

  // Returns computed normals for provided vertices.
  // Note: Indices have to be completely defined--NO TRIANGLE_STRIP only TRIANGLES.
  calculateNormals(vs, ind) {
    const
      x = 0,
      y = 1,
      z = 2,
      ns = [];

    // For each vertex, initialize normal x, normal y, normal z
    for (let i = 0; i < vs.length; i += 3) {
      ns[i + x] = 0.0;
      ns[i + y] = 0.0;
      ns[i + z] = 0.0;
    }

    // We work on triads of vertices to calculate
    for (let i = 0; i < ind.length; i += 3) {
      // Normals so i = i+3 (i = indices index)
      const v1 = [],
        v2 = [],
        normal = [];

      // p2 - p1
      v1[x] = vs[3 * ind[i + 2] + x] - vs[3 * ind[i + 1] + x];
      v1[y] = vs[3 * ind[i + 2] + y] - vs[3 * ind[i + 1] + y];
      v1[z] = vs[3 * ind[i + 2] + z] - vs[3 * ind[i + 1] + z];

      // p0 - p1
      v2[x] = vs[3 * ind[i] + x] - vs[3 * ind[i + 1] + x];
      v2[y] = vs[3 * ind[i] + y] - vs[3 * ind[i + 1] + y];
      v2[z] = vs[3 * ind[i] + z] - vs[3 * ind[i + 1] + z];

      // Cross product by Sarrus Rule
      normal[x] = v1[y] * v2[z] - v1[z] * v2[y];
      normal[y] = v1[z] * v2[x] - v1[x] * v2[z];
      normal[z] = v1[x] * v2[y] - v1[y] * v2[x];

      // Update the normals of that triangle: sum of vectors
      for (let j = 0; j < 3; j++) {
        ns[3 * ind[i + j] + x] = ns[3 * ind[i + j] + x] + normal[x];
        ns[3 * ind[i + j] + y] = ns[3 * ind[i + j] + y] + normal[y];
        ns[3 * ind[i + j] + z] = ns[3 * ind[i + j] + z] + normal[z];
      }
    }

    // Normalize the result.
    // The increment here is because each vertex occurs.
    for (let i = 0; i < vs.length; i += 3) {
      // With an offset of 3 in the array (due to x, y, z contiguous values)
      const nn = [];
      nn[x] = ns[i + x];
      nn[y] = ns[i + y];
      nn[z] = ns[i + z];

      let len = Math.sqrt((nn[x] * nn[x]) + (nn[y] * nn[y]) + (nn[z] * nn[z]));
      if (len === 0) len = 1.0;

      nn[x] = nn[x] / len;
      nn[y] = nn[y] / len;
      nn[z] = nn[z] / len;

      ns[i + x] = nn[x];
      ns[i + y] = nn[y];
      ns[i + z] = nn[z];
    }

    return ns;
  },

  // A simpler API on top of the dat.GUI API, specifically
  // designed for this book for a simpler codebase
  configureControls(settings, options = {
    width: 300
  }) {
    // Check if a gui instance is passed in or create one by default
    const gui = options.gui || new dat.GUI(options);
    const state = {};

    const isAction = v => typeof v === 'function';

    const isFolder = v =>
      !isAction(v) &&
      typeof v === 'object' &&
      (v.value === null || v.value === undefined);

    const isColor = v =>
      (typeof v === 'string' && ~v.indexOf('#')) ||
      (Array.isArray(v) && v.length >= 3);

    Object.keys(settings).forEach(key => {
      const settingValue = settings[key];

      if (isAction(settingValue)) {
        state[key] = settingValue;
        return gui.add(state, key);
      }
      if (isFolder(settingValue)) {
        // If it's a folder, recursively call with folder as root settings element
        return utils.configureControls(settingValue, {
          gui: gui.addFolder(key)
        });
      }

      const {
        value,
        min,
        max,
        step,
        options,
        onChange = () => null,
      } = settingValue;

      // set state
      state[key] = value;

      let controller;

      // There are many other values we can set on top of the dat.GUI
      // API, but we'll only need a few for our purposes
      if (options) {
        controller = gui.add(state, key, options);
      } else if (isColor(value)) {
        controller = gui.addColor(state, key)
      } else {
        controller = gui.add(state, key, min, max, step)
      }

      controller.onChange(v => onChange(v, state))
    });
  },

  // Calculate tangets for a given set of vertices
  calculateTangents(vs, tc, ind) {
    const tangents = [];

    for (let i = 0; i < vs.length / 3; i++) {
      tangents[i] = [0, 0, 0];
    }

    let
      a = [0, 0, 0],
      b = [0, 0, 0],
      triTangent = [0, 0, 0];

    for (let i = 0; i < ind.length; i += 3) {
      const i0 = ind[i];
      const i1 = ind[i + 1];
      const i2 = ind[i + 2];

      const pos0 = [vs[i0 * 3], vs[i0 * 3 + 1], vs[i0 * 3 + 2]];
      const pos1 = [vs[i1 * 3], vs[i1 * 3 + 1], vs[i1 * 3 + 2]];
      const pos2 = [vs[i2 * 3], vs[i2 * 3 + 1], vs[i2 * 3 + 2]];

      const tex0 = [tc[i0 * 2], tc[i0 * 2 + 1]];
      const tex1 = [tc[i1 * 2], tc[i1 * 2 + 1]];
      const tex2 = [tc[i2 * 2], tc[i2 * 2 + 1]];

      vec3.subtract(a, pos1, pos0);
      vec3.subtract(b, pos2, pos0);

      const c2c1b = tex1[1] - tex0[1];
      const c3c1b = tex2[0] - tex0[1];

      triTangent = [c3c1b * a[0] - c2c1b * b[0], c3c1b * a[1] - c2c1b * b[1], c3c1b * a[2] - c2c1b * b[2]];

      vec3.add(triTangent, tangents[i0], triTangent);
      vec3.add(triTangent, tangents[i1], triTangent);
      vec3.add(triTangent, tangents[i2], triTangent);
    }

    // Normalize tangents
    const ts = [];
    tangents.forEach(tan => {
      vec3.normalize(tan, tan);
      ts.push(tan[0]);
      ts.push(tan[1]);
      ts.push(tan[2]);
    });

    return ts;
  }

};


'use strict';

let
  gl,
  program,
  vao,
  indices,
  indicesBuffer,
  modelViewMatrix = mat4.create(),
  projectionMatrix = mat4.create(),
  normalMatrix = mat4.create();

function initProgram() {
  // Configure `canvas`
  const canvas = utils.getCanvas('webgl-canvas');
  utils.autoResizeCanvas(canvas);

  // Configure `gl`
  gl = utils.getGLContext(canvas);
  gl.clearColor(0.9, 0.9, 0.9, 1);
  gl.clearDepth(100);
  gl.enable(gl.DEPTH_TEST);
  gl.depthFunc(gl.LEQUAL);

  // Shader source
  const vertexShader = utils.getShader(gl, 'vertex-shader');
  const fragmentShader = utils.getShader(gl, 'fragment-shader');

  // Configure `program`
  program = gl.createProgram();
  gl.attachShader(program, vertexShader);
  gl.attachShader(program, fragmentShader);
  gl.linkProgram(program);

  if (!gl.getProgramParameter(program, gl.LINK_STATUS)) {
    console.error('Could not initialize shaders');
  }

  gl.useProgram(program);

  // Set locations onto `program` instance
  program.aVertexPosition = gl.getAttribLocation(program, 'aVertexPosition');
  program.aVertexNormal = gl.getAttribLocation(program, 'aVertexNormal');
  program.uProjectionMatrix = gl.getUniformLocation(program, 'uProjectionMatrix');
  program.uModelViewMatrix = gl.getUniformLocation(program, 'uModelViewMatrix');
  program.uNormalMatrix = gl.getUniformLocation(program, 'uNormalMatrix');
  program.uLightDirection = gl.getUniformLocation(program, 'uLightDirection');
  program.uLightAmbient = gl.getUniformLocation(program, 'uLightAmbient');
  program.uLightDiffuse = gl.getUniformLocation(program, 'uLightDiffuse');
  program.uMaterialDiffuse = gl.getUniformLocation(program, 'uMaterialDiffuse');
}

// Configure lights
function initLights() {
  gl.uniform3fv(program.uLightDirection, [0, 0, -1]);
  gl.uniform4fv(program.uLightAmbient, [0.01, 0.01, 0.01, 1]);
  gl.uniform4fv(program.uLightDiffuse, [0.5, 0.5, 0.5, 1]);
  gl.uniform4f(program.uMaterialDiffuse, 0.1, 0.5, 0.8, 1);
}

/**
 * This function generates the example data and create the buffers
 *
 *           4          5             6         7
 *           +----------+-------------+---------+
 *           |          |             |         |
 *           |          |             |         |
 *           |          |             |         |
 *           |          |             |         |
 *           |          |             |         |
 *           +----------+-------------+---------+
 *           0          1             2         3
 *
 */
function initBuffers() {
  const vertices = [-20, -8, 20, // 0
    -10, -8, 0, // 1
    10, -8, 0, // 2
    20, -8, 20, // 3
    -20, 8, 20, // 4
    -10, 8, 0, // 5
    10, 8, 0, // 6
    20, 8, 20 // 7
  ];

  indices = [
    0, 5, 4,
    1, 5, 0,
    1, 6, 5,
    2, 6, 1,
    2, 7, 6,
    3, 7, 2
  ];

  // Create VAO
  vao = gl.createVertexArray();

  // Bind Vao
  gl.bindVertexArray(vao);

  const normals = utils.calculateNormals(vertices, indices);

  const verticesBuffer = gl.createBuffer();
  gl.bindBuffer(gl.ARRAY_BUFFER, verticesBuffer);
  gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertices), gl.STATIC_DRAW);
  //console.log('vertices', vertices);
  // Configure instructions
  gl.enableVertexAttribArray(program.aVertexPosition);
  gl.vertexAttribPointer(program.aVertexPosition, 3, gl.FLOAT, false, 0, 0);

  const normalsBuffer = gl.createBuffer();
  gl.bindBuffer(gl.ARRAY_BUFFER, normalsBuffer);
  gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(normals), gl.STATIC_DRAW);
  // Configure instructions
  gl.enableVertexAttribArray(program.aVertexNormal);
  gl.vertexAttribPointer(program.aVertexNormal, 3, gl.FLOAT, false, 0, 0);

  indicesBuffer = gl.createBuffer();
  gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, indicesBuffer);
  gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new Uint16Array(indices), gl.STATIC_DRAW);

  // Clean
  gl.bindVertexArray(null);
  gl.bindBuffer(gl.ARRAY_BUFFER, null);
  gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, null);
}

function draw() {
  const {
    width,
    height
  } = gl.canvas;

  gl.viewport(0, 0, width, height);
  gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);

  mat4.perspective(projectionMatrix, 45, width / height, 0.1, 10000);
  mat4.identity(modelViewMatrix);
  mat4.translate(modelViewMatrix, modelViewMatrix, [0, 0, -40]);

  mat4.copy(normalMatrix, modelViewMatrix);
  mat4.invert(normalMatrix, normalMatrix);
  mat4.transpose(normalMatrix, normalMatrix);

  gl.uniformMatrix4fv(program.uModelViewMatrix, false, modelViewMatrix);
  gl.uniformMatrix4fv(program.uProjectionMatrix, false, projectionMatrix);
  gl.uniformMatrix4fv(program.uNormalMatrix, false, normalMatrix);

  // We will start using the `try/catch` to capture any errors from our `draw` calls
  try {
    // Bind
    gl.bindVertexArray(vao);
    gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, indicesBuffer);

    // Draw
    gl.drawElements(gl.TRIANGLES, indices.length, gl.UNSIGNED_SHORT, 0);

    // Clean
    gl.bindVertexArray(null);
    gl.bindBuffer(gl.ARRAY_BUFFER, null);
    gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, null);
  }
  // We catch the `error` and simply output to the screen for testing/debugging purposes
  catch (error) {
    console.error(error);
  }
}

function render() {
  requestAnimationFrame(render);
  draw();
}

function init() {
  initProgram();
  initBuffers();
  initLights();
  render();
}

init();
代码语言:javascript
运行
AI代码解释
复制
    <script src="https://cdnjs.cloudflare.com/ajax/libs/gl-matrix/2.4.0/gl-matrix.js"></script>

  <!-- modules -->

  <!-- vertex Shader -->
  <script id="vertex-shader" type="x-shader/x-vertex">
		#version 300 es
    precision mediump float;

    uniform mat4 uModelViewMatrix;
    uniform mat4 uProjectionMatrix;
    uniform mat4 uNormalMatrix;
    uniform vec3 uLightDirection;
    uniform vec4 uLightAmbient;
    uniform vec4 uLightDiffuse;
    uniform vec4 uMaterialDiffuse;

    in vec3 aVertexPosition;
    in vec3 aVertexNormal;

    out vec4 vVertexColor;

    void main(void) {
      vec3 N = vec3(uNormalMatrix * vec4(aVertexNormal, 1.0));
      vec3 L = normalize(uLightDirection);
      float lambertTerm = dot(N, -L);

      // Ambient
      vec4 Ia = uLightAmbient;
      // Diffuse
      vec4 Id = uMaterialDiffuse * uLightDiffuse * lambertTerm;

      // Set varying to be used inside of fragment shader
      vVertexColor = vec4(vec3(Ia + Id), 1.0);
      gl_Position = uProjectionMatrix * uModelViewMatrix * vec4(aVertexPosition, 1.0);
    }
  </script>

  <!-- fragment Shader -->
  <script id="fragment-shader" type="x-shader/x-fragment">
    #version 300 es
    precision mediump float;

    in vec4 vVertexColor;

    out vec4 fragColor;

    void main(void)  {
      fragColor = vVertexColor;
    }
  </script>
  <canvas id="webgl-canvas"></canvas>

这里的顶点定义为

代码语言:javascript
运行
AI代码解释
复制
const vertices = [
        -20, -8, 20, // 0
        -10, -8, 0,  // 1
        10, -8, 0,   // 2
        20, -8, 20,  // 3
        -20, 8, 20,  // 4
        -10, 8, 0,   // 5
        10, 8, 0,    // 6
        20, 8, 20    // 7
      ];

据我所知,webGl使用clipspace coordinates,它从-1到+1。但是这里这些顶点不在这个范围内。

有人能告诉我把这些顶点转换成clipspace coordinates的代码吗?我已经看了一段时间的代码,但似乎找不到它自己。

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2019-02-14 00:55:58

请考虑在WebGL上阅读这些课程。Here are some that explain clipspace,这是解释how to use matrices to convert from some space to clipspace using matrix math的,这是解释how convert from 3D space to clipspace with matrix math的,解释how to get perspective with matrix math的,这是解释how cameras work with a view matrix

在回答您的问题时,顶点着色器中的这条线

代码语言:javascript
运行
AI代码解释
复制
  gl_Position = uProjectionMatrix * uModelViewMatrix * vec4(aVertexPosition, 1.0);

通过选择要指定uProjectionMatrixuModelViewMatrix的正确矩阵,将这些顶点转化为剪辑空间。uModelViewMatrix在视图空间中定位、缩放和定向模型。然后,uProjectionMatrix使用透视投影将视图空间转换为剪裁空间。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/54681570

复制
相关文章
React 钩子:useState()
React 是一个流行的JavaScript库,用于构建用户界面。在 React 16.8 版本中引入了钩子(Hooks)的概念,它为函数组件提供了状态管理和其他功能。本文将着重介绍最常用的钩子之一:useState()。
网络技术联盟站
2023/07/13
3880
React 钩子:useState()
React技巧之将useState作为对象数组
原文链接:https://bobbyhadz.com/blog/react-typescript-usestate-empty-object
chuckQu
2022/08/19
2.7K0
React技巧之将useState作为对象数组
React技巧之移除状态数组中的对象
原文链接:https://bobbyhadz.com/blog/react-remove-object-from-state-array[1]
chuckQu
2022/08/19
1.4K0
React技巧之移除状态数组中的对象
【react hooks】属性作为useState 初始值,属性改变useState 不改变问题?
发现visible 此时为ture ,界面也重新render了,但是modelVisible 为false。
星宇大前端
2022/03/09
2.1K0
react中的useState源码分析
简单说下为什么React选择函数式组件,主要是class组件比较冗余、生命周期函数写法不友好,骚写法多,functional组件更符合React编程思想等等等。更具体的可以拜读dan大神的blog。其中Function components capture the rendered values这句十分精辟的道出函数式组件的优势。
flyzz177
2022/12/14
5070
useTypescript-React Hooks和TypeScript完全指南
React v16.8 引入了 Hooks,它可以让你在不编写 class 的情况下使用 state 以及其他的 React 特性。这些功能可以在应用程序中的各个组件之间使用,从而易于共享逻辑。Hook 令人兴奋并迅速被采用,React 团队甚至想象它们最终将替换类组件。
前端森林
2020/04/23
8.6K0
useTypescript-React Hooks和TypeScript完全指南
美丽的公主和它的27个React 自定义 Hook
在上一篇git 原理中我们在「前置知识点」中随口提到了Hook。其中,就有我们比较熟悉的React Hook。
前端柒八九
2023/10/25
7880
美丽的公主和它的27个React 自定义 Hook
React常见面试题
动态加载(异步组件)加载时会有延迟,在延迟期间可以将一些内容展示给用户,比如:loading
隔壁老陈
2023/01/12
4.2K0
React常见面试题
10分钟教你手写8个常用的自定义hooks
Hook 是 React 16.8 的新增特性。它可以让你在不编写 class 的情况下使用 state 以及其他的 React 特性。本文是一篇以实战为主的文章,主要讲解实际项目中如何使用hooks以及一些最佳实践,不会一步步再介绍一遍react hooks的由来和基本使用,因为写hooks的文章很多,而且官网对于react hooks的介绍也很详细,所以大家不熟悉的可以看一遍官网。
徐小夕
2020/03/13
3.6K0
React技巧之将useState作为对象
原文链接:https://bobbyhadz.com/blog/react-type-usestate-object[1]
chuckQu
2022/08/19
9680
React 中的 useState() 是什么?
在 React 中,useState() 是一个用于在函数组件中声明状态的 Hook。它是 React 16.8 引入的一种新的状态管理方式。
王小婷
2023/09/15
7350
React报错之Too many re-renders
产生"Too many re-renders. React limits the number of renders to prevent an infinite loop"错误有多方面的原因:
chuckQu
2023/02/13
3.4K0
React报错之Too many re-renders
[译] 对比 React Hooks 和 Vue Composition API
原文:https://dev.to/voluntadpear/comparing-react-hooks-with-vue-composition-api-4b32
江米小枣
2020/06/15
6.7K0
你需要的react面试高频考察点总结
函数式组件(Functional component)根本没有实例instance。类组件(Class component)有实例instance,但是永远也不需要直接创建一个组件的实例,因为React帮我们做了这些。
beifeng1996
2022/11/08
3.6K0
换个角度思考 React Hooks
从 Vue 迁移到 React ,不太习惯 React Hooks 的使用?也许换个角度思考 Hooks 出现的意义会对你有所帮助。 1 什么是 Hooks 简而言之, Hooks 是个函数,通过使用 Hooks 可以让函数组件功能更加丰富。 在某些场景下,使用 Hooks 是一个比使用类组件更好的主意。 1.1 Hooks 出现的背景 在 Hooks 出现之前,函数组件对比类组件(class)形式有很多局限,例如: 不能使用 state、ref 等属性,只能通过函数传参的方式使用 props 没有生命周
用户1097444
2022/06/29
4.8K0
换个角度思考 React Hooks
浅谈Hooks&&生命周期(2019-03-12)
现在流行的前端框架,无论是angular还是React,又或是Angular2以及以上,都由框架自身提供了生命周期(有的叫生命周期钩子)供开发者使用。
贺贺V5
2019/03/20
3.3K0
浅谈Hooks&&生命周期(2019-03-12)
快速了解 React Hooks 原理
我们大部分 React 类组件可以保存状态,而函数组件不能? 并且类组件具有生命周期,而函数组件却不能?
前端小智@大迁世界
2019/08/20
1.4K0
快速了解 React Hooks 原理
React源码中的useState,useReducer
大家都知道hooks是在函数组件的产物。之前class组件为什么没有出现hooks这种东西呢?
goClient1992
2022/12/07
1K0
React Hooks
以前,React API 只有一套,现在有两套:类(class)API 和基于函数的钩子(hooks) API。
Leophen
2021/07/13
2.1K0
搞懂了,React 中原来要这样测试自定义 Hooks
React 中自定义的 Hooks 为开发者提供了重用公共方法的能力。然而,如果你是一个测试新手的话,测试这些钩子可能会很棘手。本文中,我们将探索如何使用 React Testing Library 测试库来测试自定义钩子。
前端修罗场
2023/10/07
4680
搞懂了,React 中原来要这样测试自定义 Hooks

相似问题

React useState钩子-更新对象的状态

227

如何对react中的对象数组使用UseState钩子

12

React useState钩子访问状态

22

React.js状态对象与useState钩子?

20

使用React中的useState钩子将数组插入状态

13
添加站长 进交流群

领取专属 10元无门槛券

AI混元助手 在线答疑

扫码加入开发者社群
关注 腾讯云开发者公众号

洞察 腾讯核心技术

剖析业界实践案例

扫码关注腾讯云开发者公众号
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
查看详情【社区公告】 技术创作特训营有奖征文