kokomi.js: un poderoso asistente para la creación web en 3D

prefacio

Hola a todos, este es el mago de CSS y WebGL - alphardex. En este artículo, conoceremos a un nuevo amigo: kokomi.js , que puede brindarte una increíble experiencia de creación en 3D~

kokomi.js Kosuke

Creé muchos trabajos relacionados con three.js antes , pero luego descubrí que hay muy pocas cosas que se pueden reutilizar, y la estructura del proyecto también es caótica. Para resolver estos dos problemas, el autor decidió escribir una rueda para encapsular algunas de las funciones más utilizadas de three.js y aclarar la estructura del proyecto, por lo que existe kokomi.js

Origen de su nombre: Sangonomiya Kokomi

logo.jpg

Su dirección de Github: github.com/alphardex/k…

Listo para trabajar

En este artículo usaremos la plataforma codesandbox para hacer todo el trabajo de codificación. La cuenta se puede registrar directamente con la cuenta de Github

Dirección de la plataforma: codesandbox.io

escena básica

Crear plantilla ts

Primero, hacemos clic en la esquina superior derecha, Create Sandboxlo buscamos en la lista Vanilla Typescripty creamos la plantilla ts más simple

qGpOfJ.png

La dirección de este paso: codesandbox.io/s/typescript…

Anso kokomi.js

DependenciesEn el cuadro de entrada inferior a la izquierda , kokomi.jsingréselo para instalar kokomi.js

qG9Bh4.png

Dado que kokomi.js depende de three.js, también debemos instalarlo y su tipo: threey@types/three

Construcción de escena

En index.ts, modifique la identificación de nuestro contenedor de lienzo #sketche introduzca una createSketchfunción (implementada a continuación)

índice.ts

import "./styles.css";

import createSketch from "./app";

document.getElementById("app").innerHTML = `
<div id="sketch"></div>`;

createSketch();
复制代码

在style.css中,给容器设置一定的样式,使其铺满屏幕

style.css

body {
  margin: 0;
}

#sketch {
  width: 100vw;
  height: 100vh;
  overflow: hidden;
  background: black;
}
复制代码

新建文件app.ts,在里面输入如下代码

app.ts

import * as kokomi from "kokomi.js";

class Sketch extends kokomi.Base {
  create() {}
}

const createSketch = () => {
  const sketch = new Sketch();
  sketch.create();
  return sketch;
};

export default createSketch;
复制代码

右边画面会报错,提示我们先要配置下babel

新建.babalrc文件,在里面拷贝如下代码

.babalrc

{
  "presets": [
    "env"
  ],
  "plugins": [
    "transform-runtime",
    "@babel/plugin-proposal-class-properties"
  ],
  "parserOpts": {
    "plugins": [
      "dynamicImport"
    ]
  }
}
复制代码

这时我们能看到一片黑屏,表明kokomi.js已经被顺利引入了

接下来让我们创建一个3D世界的Hello World——一个可爱的白色方块

class Sketch extends kokomi.Base {
  create() {
    const box = new kokomi.Box(this);
    box.addExisting();
  }
}
复制代码

可以看到屏幕中心已经出现了一个白色的方块

qGCQDx.png

接下来让我们添加轨道视角

class Sketch extends kokomi.Base {
  create() {
    const box = new kokomi.Box(this);
    box.addExisting();

    new kokomi.OrbitControls(this);
  }
}
复制代码

这样我们就能自由地拖拽画面了

qGC8UO.gif

让方块旋转起来吧

class Sketch extends kokomi.Base {
  create() {
    const box = new kokomi.Box(this);
    box.addExisting();

    new kokomi.OrbitControls(this);

    this.update((time: number) => {
      box.spin(time);
    });
  }
}
复制代码

qGCt8H.gif

恭喜,此刻你已经完成了最基础的3D场景的搭建

该步骤地址:codesandbox.io/s/kokomi-js…

素材管理

kokomi.js提供了AssetManager类,用来统一管理素材的加载

定义素材

首先,创建一个resources.ts文件,里面定义好素材列表

素材列表对象有3个字段:

  • name:素材名
  • type:素材类型,目前支持texture(2D贴图)、cubeTexture(3D贴图)、gltfModel(模型)、font(字体)
  • path:素材路径

resources.ts

import type * as kokomi from "kokomi.js";

import foxModel from "/public/models/Fox/glTF/Fox.gltf";

const resourceList: kokomi.ResourceItem[] = [
  {
    name: "foxModel",
    type: "gltfModel",
    path: foxModel
  }
];

export default resourceList;
复制代码

我们引入了一个神子,啊不狐狸的模型,这个模型是从gltf样例模型中取出来的,也可以替换成自己喜爱的其他模型

加载素材

实例化AssetManager类,并将素材resourceList作为参数传入

监听emitterready事件(素材加载完毕事件),读取items里的foxModel,将其加入场景中,即完成了素材的加载

app.ts

import * as THREE from "three";
import * as kokomi from "kokomi.js";
import resourceList from "./resources";

class Sketch extends kokomi.Base {
  create() {
    new kokomi.OrbitControls(this);

    this.camera.position.copy(new THREE.Vector3(6, 4, 3));

    const ambientLight = new THREE.AmbientLight(0xffffff, 0.5);
    this.scene.add(ambientLight);

    const dirLight = new THREE.DirectionalLight(0xffffff, 0.6);
    dirLight.position.copy(new THREE.Vector3(1, 2, 3));
    this.scene.add(dirLight);

    const assetManager = new kokomi.AssetManager(this, resourceList);
    assetManager.emitter.on("ready", () => {
      const foxModel = assetManager.items.foxModel;
      foxModel.scene.scale.set(0.02, 0.02, 0.02);
      this.scene.add(foxModel.scene);
    });
  }
}
复制代码

qGmJmQ.gif

该步骤地址:codesandbox.io/s/kokomi-js…

这里有个优化点:可以将Fox模型抽成一个class组件,这样可以维护一个属于自己的组件逻辑

组件化

新建文件夹 components,新建 fox.ts,编写狐狸的模型组件

La idea básica de escribir componentes: heredar la Componentclase, escribir la lógica de estado del componente en ella, la addExistingfunción es responsable de agregar el componente a la escena, la updatefunción es el cuadro de animación y se sincronizará con el animación global de la escena

zorro.ts

import * as THREE from "three";
import * as kokomi from "kokomi.js";
import type * as STDLIB from "three-stdlib";

type ActionName = "idle" | "walk" | "run";

class Fox extends kokomi.Component {
  gltf: STDLIB.GLTF;
  mixer: THREE.AnimationMixer;
  actions: Record<string, THREE.AnimationAction>;
  constructor(base: kokomi.Base, gltf: STDLIB.GLTF) {
    super(base);

    this.gltf = gltf;

    const mixer = new THREE.AnimationMixer(this.gltf.scene);
    this.mixer = mixer;

    this.actions = {};
    this.setActions();
  }
  addExisting(): void {
    this.gltf.scene.scale.set(0.02, 0.02, 0.02);
    this.base.scene.add(this.gltf.scene);
  }
  update(time: number): void {
    const delta = this.base.clock.getDelta();
    this.mixer.update(delta);
  }
  setActions() {
    this.actions.idle = this.mixer.clipAction(this.gltf.animations[0]);
    this.actions.walk = this.mixer.clipAction(this.gltf.animations[1]);
    this.actions.run = this.mixer.clipAction(this.gltf.animations[2]);
  }
  playAction(name: ActionName = "idle") {
    const prevAction = this.actions.current;
    const nextAction = this.actions[name];

    nextAction.reset();
    nextAction.play();
    if (prevAction) {
      nextAction.crossFadeFrom(prevAction, 1, true);
    }

    this.actions.current = nextAction;
  }
}

export default Fox;
复制代码

Aplicar el componente a la escena principal.

aplicación.ts

import Fox from "./components/fox";

class Sketch extends kokomi.Base {
   ...
  create() {
    ...
    this.assetManager.emitter.on("ready", () => {
      const fox = new Fox(this, this.assetManager.items.foxModel);
      fox.addExisting();
      fox.playAction("idle");
    });
  }
}
复制代码

qGc80S.gif

La instancia de fox aquí tiene su propia función y estado, de modo que cuando creamos otras class, no habrá conflictos duplicados en la funcionalidad.

La dirección de este paso: codesandbox.io/s/kokomi-js…

creación de efectos especiales

Cree una nueva carpeta de sombreado y cree un nuevo fragment.glslfragmento de sombreado en ella, copie el siguiente código dentro

void mainImage(out vec4 fragColor,in vec2 fragCoord){
    vec2 p=fragCoord/iResolution.xy;
    vec3 color=vec3(p,0.);
    fragColor=vec4(color,1.);
}
复制代码

En la escena principal, crea una instancia de la ScreenQuadclase, ábrela shadertoyModee introduce el fragment shader

aplicación.ts

import fragmentShader from "./shaders/fragment.glsl";

class Sketch extends kokomi.Base {
  create() {
    const screenQuad = new kokomi.ScreenQuad(this, {
      shadertoyMode: true,
      fragmentShader
    });
    screenQuad.addExisting();
  }
}
复制代码

qGMUDU.png

Puede ver que se muestra el plano uv y podemos crear Shader en él.

La dirección de este paso: codesandbox.io/s/kokomi-js…

Por ejemplo, el Raymarching más común en Shadertoy

qG3PMt.png

La dirección de demostración: codesandbox.io/s/raymarchi…

finalmente

Este artículo lo lleva a una comprensión preliminar de kokomi.js. El autor continuará mejorándola en el futuro, así que estad atentos.

Supongo que te gusta

Origin juejin.im/post/7078578317053394975
Recomendado
Clasificación