使用 THREE.JS 构建基础HLSL环境

139 阅读1分钟

安装THREE

  1. 需要安装好node (个人目前使用 node 版本为 22.14.0)
  2. npm init -y
  3. npm install three vite
  4. 新建 index.html
    <!DOCTYPE html>
     <html lang="en">
     <head>
         <meta charset="UTF-8">
         <meta name="viewport" content="width=device-width, initial-scale=1.0">
         <title>First Three.js</title>
         <style>
             *{
                 margin: 0;
             }
             body{
                 background-color: black;
             }
         </style>
     </head>
     <body>
             <!-- <h1>Soon the be Three.js website</h1> -->
             <script type="module" src="./index.js"></script>
     </body>
     </html>
    
    
  5. 新建index.js 并引入 three.js
        import * as THREE from "three/webgpu";
        import {
           color,
           convertColorSpace,
           Fn,
           If,
           positionLocal,
           texture,
           abs,
           rotateUV,
           time,
           vec2,
         } from "three/tsl";
         import { OrbitControls } from "three/addons/controls/OrbitControls.js";
         const scene = new THREE.Scene();
    
         const camera = new THREE.PerspectiveCamera(
           75,
           window.innerWidth / window.innerHeight,
           0.1,
           10
         );
         camera.position.z = 1;
    
         const renderer = new THREE.WebGPURenderer({ antialias: true });
         renderer.setSize(window.innerWidth, window.innerHeight);
         document.body.appendChild(renderer.domElement);
         renderer.setAnimationLoop(animate);
         window.addEventListener("resize", function () {
           camera.aspect = window.innerHeight / window.innerHeight;
           camera.updateProjectionMatrix();
           renderer.setSize(this.window.innerWidth, this.window.innerHeight);
         });
         const controls = new OrbitControls(camera, renderer.domElement);
         controls.enableDamping = true;
         const material = new THREE.NodeMaterial();
         material.fragmentNode = positionLocal;
         const mesh = new THREE.Mesh(new THREE.PlaneGeometry(), material);
         scene.add(mesh);
         function animate() {
           controls.update();
           renderer.render(scene, camera);
         }
    
  6. 新建 vite.config.js 并修改 package.json 输入npm run dev
    import { defineConfig } from 'vite';
     export default defineConfig({
         server: {
             port: 3000,
             open: true,
         },
         build: {
             outDir: 'dist',
         },
         plugins: [],
     });
    
    package.json
    javascript
     "scripts": {
       "dev": "vite",
       "build": "vite build"
     },
     
    
  7. 浏览器输入http://localhost:3000/ 查看效果
    1. 添加的是一个 PlaneGeometry 平面几何体 材质 material.fragmentNode 为 positionLocal
    2. 其中 positionLocal 是通过 three/tsl 暴露出来的
    3. 在三维空间中, positionLocal 是一个三维向量(x,y,z),表示物体在布局坐标系中的位置,即几何体 xy -0.5 ~ 0.5 将 坐标分量直接赋值给材质的颜色(rgb)通道 颜色会根据坐标值自动映射

image.png 9. 现在我们 新建一个Fn方法

 const main = Fn(()=>{
     // 假如 p点 x的绝对值 小于 0.1 则将p点 z轴值变成1 通过rgb映射变成蓝色 
      If(abs(p.x).lessThan(0.1), () => {
        p.z = 1;
      });
      return p
 })
 // 同时将 material的fragment 进行替换
 material.fragmentNode = main();
 //会得到 

image.png

  1. 同理 添加对 y 轴的判断
    const main = Fn(() => {
      const p = positionLocal.toVar();
      If(abs(p.x).lessThan(0.1), () => {
        p.z = 1;
      });
      If(abs(p.y).lessThan(0.1), () => {
        p.z = 1;
      });
      return p;
    });
    
    // 我们会得到一个十字架 
    

image.png 11. 添加 time 让 十字架动起来

        const main = Fn(() => {
          const p = positionLocal.toVar();
            p.assign(rotateUV(p.xy, time, vec2()));
            console.log('time',time)
          If(abs(p.x).lessThan(0.1), () => {
            p.z = 1;
          });
          If(abs(p.y).lessThan(0.1), () => {
            p.z = 1;
          });
          return p;
        });

image.png

  1. 可以将 planegeometry 替换成别的几何体

image.png