dibujar una pokebola con raymarching

Estoy participando en el evento de experiencia Nuggets sobre el código, detalles: muestra tus bloques de código creativo

prefacio

Hola a todos, este es el mago de CSS y WebGL - alphardex. En este artículo, usemos el componente raymarching de kokomi.js para dibujar una pokebola~

¡Salpica a Mo y lucha contra un ladrón en Tuo!

comienza la pintura

Primero bifurcar esta plantilla

codesandbox.io/s/kokomi-js…

Vea el bloque "Comencemos aquí ~", comenzaremos allí

material

Las pokebolas vienen en 3 colores: negro, blanco y rojo.

Primero define el material de 3 colores.

// 材质
const BLACK_MAT = "1.0";
const WHITE_MAT = "2.0";
const RED_MAT = "3.0";

const mat = new marcher.SDFMaterial();
mat.addColorMaterial(BLACK_MAT, 0, 0, 0);
mat.addColorMaterial(WHITE_MAT, 255, 255, 255);
mat.addColorMaterial(RED_MAT, 255, 0, 0);
mar.setMaterial(mat);
复制代码

en la esfera

El interior de la Poké Ball es una pequeña bola negra.

const sphere = new marcher.SphereSDF({
  sdfVarName: "d1",
  materialId: BLACK_MAT,
});
layer.addPrimitive(sphere);
复制代码

LK4vIP.png

botón

Hay un botón blanco en el medio, que en realidad es un cilindro.

const button = new marcher.CylinderSDF({
  sdfVarName: "d2",
  materialId: WHITE_MAT,
  radius: 0.1,
  height: 0.54,
});
button.rotate(90, "x");
layer.addPrimitive(button);
复制代码

LK5GIx.png

Capa esférica superior e inferior

En raymarching, solo se puede crear la esfera completa, ¿y qué si solo quieres la mitad de la esfera?

Cree un bloque temporal, muévalo a la mitad de la esfera y luego haga una intersección con la esfera para obtener la mitad de la esfera.

// 球壳(上)
const shellUpper = new marcher.SphereSDF({
  sdfVarName: "d3",
  materialId: "3",
  radius: 0.55,
});

const clipBoxUpper = new marcher.BoxSDF({
  sdfVarName: "d4",
  width: 0.55,
  height: 0.55,
  depth: 0.55,
});
clipBoxUpper.hide();
clipBoxUpper.translate(0, -0.6, 0);

layer.addPrimitive(clipBoxUpper);
layer.addPrimitive(shellUpper);

shellUpper.intersect(clipBoxUpper);

// 球壳(下)
const shellLower = new marcher.SphereSDF({
  sdfVarName: "d6",
  materialId: WHITE_MAT,
  radius: 0.55,
});

const clipBoxLower = new marcher.BoxSDF({
  sdfVarName: "d5",
  width: 0.55,
  height: 0.55,
  depth: 0.55,
});
clipBoxLower.hide();
clipBoxLower.translate(0, 0.6, 0);

layer.addPrimitive(clipBoxLower);
layer.addPrimitive(shellLower);

shellLower.intersect(clipBoxLower);
复制代码

LKI0pT.png

El botón en el medio de lo normal todavía está bloqueado por la capa esférica, por lo que debemos ahuecar la parte bloqueada.

hueco medio

Cree 2 cilindros (similar al botón anterior), aumente ligeramente el radio y la altura, y utilícelos para deducir las capas esféricas superior e inferior respectivamente para tener el efecto de ahuecar el medio

// 球壳(上):挖除中间镂空部分后
const clipCylinderCenter1 = new marcher.CylinderSDF({
  sdfVarName: "d7",
  radius: 0.15,
  height: 0.6,
  materialId: RED_MAT,
});
clipCylinderCenter1.rotate(90, "x");

layer.addPrimitive(clipCylinderCenter1);

clipCylinderCenter1.subtract(shellUpper);

shellUpper.hide();

// 球壳下:挖除中间镂空部分后
const clipCylinderCenter2 = new marcher.CylinderSDF({
  sdfVarName: "d8",
  radius: 0.15,
  height: 0.6,
  materialId: WHITE_MAT,
});
clipCylinderCenter2.rotate(90, "x");

layer.addPrimitive(clipCylinderCenter2);

clipCylinderCenter2.subtract(shellLower);

shellLower.hide();
复制代码

LKoECV.png

embellecer

Aquí puede jugar libremente, ya sea la iluminación, el ángulo de la cámara o el material, y se pueden optimizar otros factores.

Los resultados optimizados del autor son los siguientes

LKobMF.gif

dirección del proyecto

Supongo que te gusta

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