模拟楼宇扫光效果(three.js实战12)

1. demo效果

2. 实现要点

2.1 创建shader材质

这一步中主要是为了实现楼宇从下到上的扫光,而定制的着色器材质,在着色器材质中书写顶点着色器和片元着色器,具体如下

    let buildingSweepingLightShader = {
      uniforms: {
        "boxH": {
          type: "f",
          value: -10.0
        }
      },
      vertexShader: `
      varying vec3 vColor;
      varying float v_pz;
      void main(){
        v_pz = position.y;
        vColor = color;
        gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
      }
    `,
      fragmentShader: `
      uniform float boxH;
      varying vec3 vColor;
      varying float v_pz;
      float plot(float pct){
        return smoothstep(pct-8.0,pct,v_pz) - smoothstep(pct,pct+0.02,v_pz);
      }
      void main(){
        float f1 = plot(boxH);
        vec4 b1 = mix(vec4(0.9,0.2,1.0,0.1),vec4(f1,f1,f1,1.0),0.1);

        gl_FragColor = mix(vec4(vColor,1.0),b1,f1);
        gl_FragColor = vec4(vec3(gl_FragColor),0.9);

      }
    `
    };

    const material = new THREE.ShaderMaterial({
      uniforms: buildingSweepingLightShader.uniforms,
      vertexShader: buildingSweepingLightShader.vertexShader,
      fragmentShader: buildingSweepingLightShader.fragmentShader,
      vertexColors: buildingSweepingLightShader
    })
    material.needsUpdate = true

2.2 创建模拟楼宇Mesh

这里主要使用上一步创建的着色器材质和使用BoxBufferGeometry创建的几何体创建Mesh对象,并随机生成高度模拟楼宇

        function initModel() {
      //创建60个立方体模拟楼宇
      for (let i = 0; i < 60; i++) {
        const height = Math.random() * 10 + 2
        const width = 3
        const cubeGeom = new THREE.BoxBufferGeometry(width, height, width)
        cubeGeom.setAttribute('color', new THREE.BufferAttribute(new Float32Array(24 * 3), 3))
        const colors = cubeGeom.attributes.color
        let r = Math.random() * 0.2,
          g = Math.random() * 0.1,
          b = Math.random() * 0.8
        //设置立方体六个面24个顶点的颜色  
        for (let i = 0; i < 24; i++) {
          colors.setXYZ(i, r, g, 0.6)
        }
        //重置立方体顶部四边形的四个顶点的颜色
        const k = 2
        colors.setXYZ(k * 4 + 0, .0, g, 1.0)
        colors.setXYZ(k * 4 + 1, .0, g, 1.0)
        colors.setXYZ(k * 4 + 2, .0, g, 1.0)
        colors.setXYZ(k * 4 + 3, .0, g, 1.0)
        const cube = new THREE.Mesh(cubeGeom, material)
        cube.position.set(Math.random() * 100 - 50, height / 2, Math.random() * 100 - 50)
        scene.add(cube)

        //绘制边框线
        const lineGeom = new THREE.EdgesGeometry(cubeGeom)
        const lineMaterial = new THREE.LineBasicMaterial({
          color: 0x018BF5,
          linewidth: 1,
          linecap: 'round',
          linejoin: 'round'
        })
        const line = new THREE.LineSegments(lineGeom, lineMaterial)
        line.scale.copy(cube.scale)
        line.rotation.copy(cube.rotation)
        line.position.copy(cube.position)
        scene.add(line)
      }
    }

2.3 render中更新uniform变量

这一步主要是通过着色器材质中的uniform变量boxH向着色器中传值楼宇中扫光的高度,具体如下

buildingSweepingLightShader.uniforms.boxH.value += 0.1
if (buildingSweepingLightShader.uniforms.boxH.value > 10) {
    buildingSweepingLightShader.uniforms.boxH.value = -10
}

3. demo代码

<!DOCTYPE html>

<html>

<head>
  <title>Example 12 - buildingSweepingLight</title>
  <script type="text/javascript" src="../three/build/three.js"></script>
  <script type="text/javascript" src="../three/examples/js/controls/OrbitControls.js"></script>
  <script type="text/javascript" src="../three/examples/js/libs/stats.min.js"></script>


  <style>
    body {
      margin: 0;
      overflow: hidden;
    }
  </style>
</head>

<body>

  <div id="Stats-output"></div>
  <div id="WebGL-output"></div>

  <script type="text/javascript">
    let stats, controls;
    let camera, scene, renderer;
    let buildingSweepingLightShader = {
      uniforms: {
        "boxH": {
          type: "f",
          value: -10.0
        }
      },
      vertexShader: `
      varying vec3 vColor;
      varying float v_pz;
      void main(){
        v_pz = position.y;
        vColor = color;
        gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
      }
    `,
      fragmentShader: `
      uniform float boxH;
      varying vec3 vColor;
      varying float v_pz;
      float plot(float pct){
        return smoothstep(pct-8.0,pct,v_pz) - smoothstep(pct,pct+0.02,v_pz);
      }
      void main(){
        float f1 = plot(boxH);
        vec4 b1 = mix(vec4(0.9,0.2,1.0,0.1),vec4(f1,f1,f1,1.0),0.1);

        gl_FragColor = mix(vec4(vColor,1.0),b1,f1);
        gl_FragColor = vec4(vec3(gl_FragColor),0.9);

      }
    `
    };

    const material = new THREE.ShaderMaterial({
      uniforms: buildingSweepingLightShader.uniforms,
      vertexShader: buildingSweepingLightShader.vertexShader,
      fragmentShader: buildingSweepingLightShader.fragmentShader,
      vertexColors: buildingSweepingLightShader
    })
    material.needsUpdate = true

    function initScene() {
      scene = new THREE.Scene();
    }

    function initCamera() {
      camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 0.1, 1000);
      camera.position.set(30, 40, 80)
      camera.lookAt(new THREE.Vector3(0, 0, 0));
    }

    function initLight() {
      //添加环境光
      var ambientLight = new THREE.AmbientLight(0xffffff);
      scene.add(ambientLight);

      var spotLight = new THREE.SpotLight(0xffffff);
      spotLight.position.set(5, 10, 20);
      spotLight.castShadow = true;
      scene.add(spotLight);
    }


    function initModel() {
      //创建60个立方体模拟楼宇
      for (let i = 0; i < 60; i++) {
        const height = Math.random() * 10 + 2
        const width = 3
        const cubeGeom = new THREE.BoxBufferGeometry(width, height, width)
        cubeGeom.setAttribute('color', new THREE.BufferAttribute(new Float32Array(24 * 3), 3))
        const colors = cubeGeom.attributes.color
        let r = Math.random() * 0.2,
          g = Math.random() * 0.1,
          b = Math.random() * 0.8
        //设置立方体六个面24个顶点的颜色  
        for (let i = 0; i < 24; i++) {
          colors.setXYZ(i, r, g, 0.6)
        }
        //重置立方体顶部四边形的四个顶点的颜色
        const k = 2
        colors.setXYZ(k * 4 + 0, .0, g, 1.0)
        colors.setXYZ(k * 4 + 1, .0, g, 1.0)
        colors.setXYZ(k * 4 + 2, .0, g, 1.0)
        colors.setXYZ(k * 4 + 3, .0, g, 1.0)
        const cube = new THREE.Mesh(cubeGeom, material)
        cube.position.set(Math.random() * 100 - 50, height / 2, Math.random() * 100 - 50)
        scene.add(cube)

        //绘制边框线
        const lineGeom = new THREE.EdgesGeometry(cubeGeom)
        const lineMaterial = new THREE.LineBasicMaterial({
          color: 0x018BF5,
          linewidth: 1,
          linecap: 'round',
          linejoin: 'round'
        })
        const line = new THREE.LineSegments(lineGeom, lineMaterial)
        line.scale.copy(cube.scale)
        line.rotation.copy(cube.rotation)
        line.position.copy(cube.position)
        scene.add(line)
      }
    }

    function initRender() {

      renderer = new THREE.WebGLRenderer({
        antialias: true,
        alpha: true
      })
      renderer.setPixelRatio(window.devicePixelRatio);
      renderer.setSize(window.innerWidth, window.innerHeight);
      renderer.setClearColor(0x0f2d48, 1) // 设置背景颜色
      renderer.toneMapping = THREE.ACESFilmicToneMapping;
      document.getElementById("WebGL-output").appendChild(renderer.domElement);
    }

    //初始化轨道控制器
    function initControls() {
      clock = new THREE.Clock() // 创建THREE.Clock对象,用于计算上次调用经过的时间
      controls = new THREE.OrbitControls(camera, renderer.domElement)
    }

    function init() {
      initScene();
      initCamera();
      initLight();
      initRender();
      initStats();
      initControls();
      initModel();
      render();
    }

    function updateFun() {
      stats.update();
      const delta = clock.getDelta() // 获取自上次调用的时间差
      controls.update(delta) // 相机更新

      buildingSweepingLightShader.uniforms.boxH.value += 0.1
      if (buildingSweepingLightShader.uniforms.boxH.value > 10) {
        buildingSweepingLightShader.uniforms.boxH.value = -10
      }
    }

    function render() {

      updateFun()
      requestAnimationFrame(render);
      renderer.render(scene, camera);
    }

    function initStats() {
      stats = new Stats();
      stats.setMode(0); // 0: fps, 1: ms

      document.getElementById("Stats-output").appendChild(stats.domElement);
    }

    window.onload = init;
  </script>
</body>

</html>

### 如何配置 Ollama 环境变量 #### 在 macOS 中配置 Ollama 环境变量 当 Ollama 作为 macOS 应用程序运行时,应使用 `launchctl` 来设置环境变量。具体操作如下: ```bash launchctl setenv OLLAMA_KEEP_ALIVE "value" ``` 此命令会将指定的值赋给 `OLLAMA_KEEP_ALIVE` 这一环境变量[^1]。 #### Windows 上配置 Ollama 环境变量 对于 Windows 用户来说,在系统属性中可以完成这一工作;也可以通过 PowerShell 或者命令提示符来临时设定这些参数。为了更改模型保持加载的时间长度,则需调整名为 `OLLAMA_KEEP_ALIVE` 的环境变量。关于该变量的具体数值代表的是秒数,即想要让模型持续处于内存中的时间长短[^2]。 另外,如果希望永久保存所作改动,建议按照以下路径进行设置:控制面板 -> 系统和安全 -> 系统 -> 高级系统设置 -> 环境变量... 此外还可以直接编辑注册表现相同效果,不过这种方式风险较大,除非非常熟悉此项操作否则不推荐尝试[^3]。 #### 设置特定于 Ollama 的其他重要环境变量 除了上述提到用于维持模型在线状态的关键项之外,还有几个常用的可自定义选项可以帮助更好地管理和优化 Ollama 的性能表现: - **修改默认下载目录**: 如果不想把所有文件都放在默认位置 (`%LOCALAPPDATA%\Programs\Ollama`) ,那么就可以创建一个新的字符串类型的用户级别或系统级别的环境变量叫 `OLLAMA_MODELS` 并指向期望的目标地址。 - **改变监听接口**: 若要使服务能够接受来自外部网络连接请求而非仅限本地访问的话,就需要新增另一个名称叫做 `OLLAMA_HOST` 的全局变量并将它的值设为 `0.0.0.0`. 最后记得重启应用程序以便新加入的信息生效.
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值