WebGL全景图和镜面立方体

简介: WebGL全景图和镜面立方体

1.全景图

  • 1)顶点着色器
attribute vec2 aPosition;
      varying vec4 vPosition;
      void main() {
        gl_Position = vec4(aPosition,1.0,1.0);
        vPosition = vec4(aPosition,0.0,1.0);
      }
  • 2)片元着色器
        precision mediump float;
      uniform samplerCube uImage;
      uniform mat4 uMatrix;
      varying vec4 vPosition;
      void main() {
        vec4 t = uMatrix*  vPosition;
        gl_FragColor = textureCube(uImage, normalize(t.xyz / t.w));
      }
  • 3)初始化立方体贴图
//加载立方体贴图
function initCubeTex(gl, texture, target, url) {
   
   
  return new Promise((resolve) => {
   
   
    var image = new Image();
    image.src = url; //必须同域
    image.onload = () => {
   
   
      console.log(target, url);

      gl.texImage2D(target, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, image);
      resolve({
   
    image, texture });
    };
  });
}

async function initCubeTexture(gl, images) {
   
   
  const faceMap = {
   
   
    //前
    f: gl.TEXTURE_CUBE_MAP_POSITIVE_Z,
    //后
    b: gl.TEXTURE_CUBE_MAP_NEGATIVE_Z,
    //上
    u: gl.TEXTURE_CUBE_MAP_POSITIVE_Y,
    //下
    d: gl.TEXTURE_CUBE_MAP_NEGATIVE_Y,
    //左
    l: gl.TEXTURE_CUBE_MAP_NEGATIVE_X,
    //右
    r: gl.TEXTURE_CUBE_MAP_POSITIVE_X
  };
  //创建一个立方体贴图TEXTURE_CUBE_MAP
  var texture = gl.createTexture();
  gl.bindTexture(gl.TEXTURE_CUBE_MAP, texture);
  //给不同立方体不同面加上图片
  for (let k in images) {
   
   
    await initCubeTex(gl, texture, faceMap[k], images[k]);
  }

  gl.generateMipmap(gl.TEXTURE_CUBE_MAP);
  gl.texParameteri(gl.TEXTURE_CUBE_MAP, gl.TEXTURE_MIN_FILTER, gl.LINEAR_MIPMAP_LINEAR);
}


const images = {
   
   
          //前
          f: 'images/cube/f.jpg',
          //后
          b: 'images/cube/b.jpg',
          //上
          u: 'images/cube/u.jpg',
          //下
          d: 'images/cube/d.jpg',
          //左
          l: 'images/cube/l.jpg',
          //右
          r: 'images/cube/r.jpg'
        };

        await initCubeTexture(gl, images);
         gl.activeTexture(gl.TEXTURE0);
        gl.uniform1i(gl.getUniformLocation(gl.program, 'uImage'), 0);
  • 4)参数赋值

        //相机   用于观看全景图
          var cameraMatrix = mat4.create();
          mat4.lookAt(cameraMatrix, [settings.x, settings.y, settings.z], [0, 0, 0], [0, 1, 0]);

          var viewMatrix = mat4.create();
          mat4.invert(viewMatrix, cameraMatrix);

          // 清除移动的部分
          viewMatrix[12] = 0;
          viewMatrix[13] = 0;
          viewMatrix[14] = 0;
          var uMatrix = mat4.create();
          mat4.invert(uMatrix, mat4.multiply(uMatrix, projectionMatrix, viewMatrix));


          gl.uniformMatrix4fv(gl.getUniformLocation(program, 'uMatrix'), false, uMatrix);

注意:samplerCube立方体贴图与sampler2D普通图片贴图是不一样的。

20230513\_102854.gif

2.镜面立方体(环境贴图立方体)

  • 1)顶点着色器
 attribute vec3 aPosition;//物体点
      attribute vec3 aNormal;//法线点

      uniform mat4 uProjectionMatrix;//透视投影
      uniform mat4 uView;//视图矩阵
      uniform mat4 uModelViewMatrix;//模型变换

      varying vec3 vWorldPosition;//世界物体点
      varying vec3 vWorldNormal;//世界物体法线

      void main() {
        vec4 pos=vec4(aPosition,1.0);
        gl_Position = uProjectionMatrix * uView * uModelViewMatrix * pos;
        vWorldPosition = (uModelViewMatrix * pos).xyz;
        vWorldNormal = mat3(uModelViewMatrix) * aNormal;
      }
  • 2)片元着色器

放射方向 = 眼睛看向物体的方向 – 2 ∗ dot(物体表面法线, 眼睛看向物体的方向) ∗ 物体表面法线

precision highp float;

      varying vec3 vWorldPosition;
      varying vec3 vWorldNormal;

      uniform samplerCube uImage;//立方体贴图

      uniform vec3 uCameraPosition;//相机位置

      void main() {
        vec3 worldNormal = normalize(vWorldNormal);
        vec3 eyeToSurfaceDir = normalize(vWorldPosition - uCameraPosition);
        //反射
        vec3 direction = reflect(eyeToSurfaceDir,worldNormal);

        gl_FragColor = textureCube(uImage, direction);
      }
  • 3)立方体环境贴图与全景图立方体贴图代码一致
  • 4)参数赋值
 var cameraPosition = [0, 0, 2];
        var cameraMatrix = mat4.create();
        mat4.lookAt(cameraMatrix, [0, 0, 2], [0, 0, 0], [0, 1, 0]);

         initModelViewMatrix(gl, settings);

          //从相机矩阵创建视图
          var viewMatrix = mat4.create();
          mat4.invert(cameraMatrix, cameraMatrix);

          gl.uniformMatrix4fv(gl.getUniformLocation(program, 'uView'), false, viewMatrix);

          gl.uniform3fv(gl.getUniformLocation(program, 'uCameraPosition'), cameraPosition);

20230513\_102627.gif

3.全景图加上镜面立方体

 function drawCube() {
   
   
 //切换成立方体程序
          gl.program = cubeProgram;
          gl.useProgram(cubeProgram);
          //如果新的深度值小于存储的值,则将通过模具测试
          gl.depthFunc(gl.LESS);
          //……
          }

       function drawEnv() {
   
   
       //切换成全景图程序
          gl.program = envProgram;
          gl.useProgram(envProgram);
          //如果新的深度值小于或等于存储的值,则将通过模具测试。
          gl.depthFunc(gl.LEQUAL);
            //……
          }

   function drawScene() {
   
   
          gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
          //相机位置
          mat4.lookAt(cameraMatrix, [settings.cx, settings.cy, settings.cz], [0, 0, 0], [0, 1, 0]);
          //从相机矩阵创建视图
          mat4.invert(viewMatrix, cameraMatrix);
          //清除移动
          viewMatrix[12] = 0;
          viewMatrix[13] = 0;
          viewMatrix[14] = 0;

          drawCube();
          drawEnv();

          requestAnimationFrame(drawScene);
        }
        drawScene();

注意:画立方体和全景图的深度函数用的是不同模式设置

先初始化立方体和全景图的着色器程序,然后初始化贴图和一些共用的变量值,画场景的时候,buffer等值每次画都得赋值一遍,否则会被清掉,物体不完整

20230513\_114534.gif

  • 将反射的方向设置成这样,就会出现透【明放大镜】的效果
 vec3 direction = eyeToSurfaceDir;

20230513\_120058.gif

  • 将反射的方向设置成这样,就会出现【近视眼透明立方体】的效果
 vec3 direction =eyeToSurfaceDir*worldNormal;

20230513\_122204.gif

github地址

https://github.com/xiaolidan00/my-webgl

参考

  • https://webglfundamentals.org/
  • 《WebGL编程指南》
  • 《webGL 3D开发实战详解 第2版》
相关文章
|
1月前
|
架构师 图形学
图形学基础概念(画布/位图/像素等)
图形学基础概念(画布/位图/像素等)
45 0
cesium加载魔方立方体
【8月更文挑战第16天】
|
3月前
|
存储 算法 C#
Unity3D学习笔记2——绘制一个带纹理的面
Unity3D学习笔记2——绘制一个带纹理的面
32 0
|
3月前
|
缓存 图形学 C++
Unreal学习笔记2-绘制简单三角形
Unreal学习笔记2-绘制简单三角形
33 0
|
前端开发 JavaScript
threejs实战_canvans纹理
threejs加载canvas纹理
159 0
threejs实战_canvans纹理
|
存储 异构计算
threejs实战_3d纹理
threejs加载3d纹理
207 0
threejs实战_3d纹理
从0开发游戏引擎之在3D空间中渲染出三维几何体
这个类里面会使用第9章里的三维体数据来调用OpenGL的接口绘制出来对应的形状。几何体绘制类主要是调试使用的,比如想要更直观的看到一个对象身上的碰撞框。绘制的形状非常多,大家直接看代码吧。
从0开发游戏引擎之使用OpenGL绘制三维球体
绘制球体的难点主要在于 要在遍历循环中 根据经纬度反复的使用Cos、Sin函数算出球面上的XYZ三个顶点坐标,一直反复计算,最终三角面多的形成了一个球的形状。
从0开发游戏引擎之三维几何体数据类
Shape类只是单纯的形状数据,并不能用具真正的绘制,真正的绘制工作是Gizmo类去做的。该类只是作为Gizmo的一个成员去使用的。Shape的函数只是提供了加工数据的,然后把加工后的数据存下来。不多哔哔了,直接贴代码。原理有空了再详细写。
|
前端开发 JavaScript 容器
Three.js入门: 构建一个立方体
Three.js 是一个 JavaScript 库,用于在 Web 浏览器中创建 3D Web 图形。前面介绍过一些基本的知识和实现简单的效果《Three.js 入门指南》和《【Three.js】随着元宇宙开启WEB3D之路》,本文从简单的构建立方体出发,介绍一些基础概念。
207 0