7.6 Example codes (51~60)
Click the Open Sandbox button. Then, you can run all the examples on this page by changing the value of the variable example in App.jsx.
import React, { useEffect, useRef, useState } from "react";
import {
loadAudios,
TextSprite,
useFrame,
useLoader,
useRefEffect,
useThree,
} from "threefy";
import { randomHSLColor, randomMatrix } from "./ThreeUtils";
import { Model } from "./ThreeModels";
import { Sky, SkyDome, Terrain } from "./ThreeNatures";
import { fitCameraToObject, randomCoords, randomHexColor } from "./ThreeUtils";
import * as THREE from "three";
import { FontLoader } from "three/examples/jsm/loaders/FontLoader";
import { DotScreenShader } from "three/examples/jsm/shaders/DotScreenShader";
import { RGBShiftShader } from "three/examples/jsm/shaders/RGBShiftShader";
import { FXAAShader } from "three/examples/jsm/shaders/FXAAShader";
import { GTAOPass } from "three/examples/jsm/postprocessing/GTAOPass";
import brickWall_diffuse_jpg from "../public/images/brickWall/diffuse.jpg";
import brickWall_normal_jpg from "../public/images/brickWall/normal.jpg";
import bathroom_diffuse_jpg from "../public/images/bathroom/diffuse.jpg";
import bathroom_normal_jpg from "../public/images/bathroom/normal.jpg";
import hdr_overcast_soil_puresky_2k_hdr from "../public/images/hdr/overcast_soil_puresky_2k.hdr";
import raymarch_abstract1_jpg from "../public/images/raymarch/abstract1.jpg";
import raymarch_pebbles_jpg from "../public/images/raymarch/pebbles.jpg";
import moss_diffuse_jpg from "../public/images/moss/diffuse.jpg";
import moss_normal_jpg from "../public/images/moss/normal.jpg";
import rockMossy_ao_jpg from "../public/images/rockMossy/ao.jpg";
import rockMossy_aoRoughMetal_jpg from "../public/images/rockMossy/aoRoughMetal.jpg";
import rockMossy_diffuse_jpg from "../public/images/rockMossy/diffuse.jpg";
import rockMossy_normal_jpg from "../public/images/rockMossy/normal.jpg";
import cloud_nx_png from "../public/images/background/cloud/nx.png";
import cloud_ny_png from "../public/images/background/cloud/ny.png";
import cloud_nz_png from "../public/images/background/cloud/nz.png";
import cloud_px_png from "../public/images/background/cloud/px.png";
import cloud_py_png from "../public/images/background/cloud/py.png";
import cloud_pz_png from "../public/images/background/cloud/pz.png";
import decal_diffuse_png from "../public/images/decal/diffuse.png";
import decal_normal_jpg from "../public/images/decal/normal.jpg";
import ratamahatta_md2_zip from "../public/models/ratamahatta_md2.zip";
import LeePerrySmith_glb from "../public/models/LeePerrySmith.glb";
import wild_town_zip from "../public/models/wild_town.zip";
import suzanne_glb from "../public/models/suzanne.glb";
import sample_mp3 from "../public/sounds/sample.mp3";
const DemoFog = () => {
const { set } = useThree();
set("camera.position.z", 300);
const example = 2;
if (example === 1) {
const fogColor = 0xcccccc;
const near = 1;
const far = 1024;
return (
<>
<Sky />
<Terrain position-y={-200} />
<fog args={[fogColor, near, far]} />
</>
);
}
if (example === 2) {
const fogColor = 0xcccccc;
const fogDensity = 0.002;
return (
<>
<Sky />
<Terrain position-y={-200} />
<fogExp2 args={[fogColor, fogDensity]} />
</>
);
}
};
const DemoPostProcessing = () => {
const example = 7;
if (example === 1) {
return (
<>
<SkyDome />
<Terrain position-y={-200} />
<shaderPass args={[DotScreenShader]} uniforms-scale-value={3} />
<shaderPass args={[RGBShiftShader]} uniforms-amount-value={0.0015} />
</>
);
}
if (example === 2) {
const { get } = useThree();
const [width, height] = get("width", "height");
const pixelRatio = get("renderer.getPixelRatio")();
const x = 1 / (width * pixelRatio);
const y = 1 / (height * pixelRatio);
return (
<>
<SkyDome />
<Terrain position-y={-200} />
<shaderPass
args={[FXAAShader]}
material-uniforms-resolution-value-x={x}
material-uniforms-resolution-value-y={y}
/>
</>
);
}
if (example === 3) {
return (
<>
<Sky />
<Terrain position-y={-200} />
<glitchPass />
</>
);
}
if (example === 4) {
const ref = useRef(null);
const { get } = useThree();
const scene = get("scene");
const camera = get("camera");
const [width, height] = get("width", "height");
const onLoad = (model) => {
// fitCameraToObject( model );
if (model.animations) {
const animator = get("animator");
animator.playAction(model, model.animations[0]);
}
};
return (
<>
<Model url={wild_town_zip} onLoad={onLoad} scale={0.05} />
<gTAOPass
ref={ref}
args={[scene, camera, width, height]}
output={GTAOPass.OUTPUT.Denoise} // GTAOPass.OUTPUT.(Default|Diffuse|AO|Denoise|Depth|Normal)
updateGtaoMaterial={{
// aoParameters
radius: 0.25,
distanceExponent: 1.2,
thickness: 2,
scale: 3,
samples: 16,
distanceFallOff: 1,
screenSpaceRadius: false,
}}
updatePdMaterial={{
// pdParameters
lumaPhi: 10,
depthPhi: 2,
normalPhi: 3,
radius: 4,
radiusExponent: 1,
rings: 2,
samples: 16,
}}
/>
</>
);
}
if (example === 5) {
const { get } = useThree();
const scene = get("scene");
const camera = get("camera");
const [width, height] = get("width", "height");
return (
<>
{randomCoords([50, 50, 50], 500, 3).map((p, i) => (
<box
key={i}
scale={1 + 3 * Math.random()}
position={p}
type={"lambert"}
color={randomHexColor()}
/>
))}
<outlinePass args={[new THREE.Vector2(width, height), scene, camera]} />
</>
);
}
if (example === 6) {
const { get, set } = useThree();
const [width, height] = get("width", "height");
const exposure = 1;
set("renderer.toneMappingExposure", Math.pow(exposure, 4.0)); // exposure = 0.1 ~ 2
const onLoad = (model) => {
fitCameraToObject(model);
if (model.animations) {
const animator = get("animator");
animator.playAction(model, model.animations[0]);
}
};
return (
<>
<background color={"black"} />
<Model url={ratamahatta_md2_zip} onLoad={onLoad} />
<unrealBloomPass
args={[new THREE.Vector2(width, height), 1.5, 0.4, 0.85]}
threshold={0}
strength={1}
radius={0}
/>
</>
);
}
if (example === 7) {
const { get, threefy } = useThree();
const scene = get("scene");
const camera = get("camera");
const [width, height] = get("width", "height");
camera.position.z = 500;
const onLoad = (model) => {
const suzanne = model.children[0];
suzanne.visible = false;
const material = suzanne.material;
const geometry = suzanne.geometry;
geometry.rotateX(Math.PI / 2);
const group = new THREE.Group();
const suzannes = 20;
for (let i = 0; i < suzannes; i++) {
const mesh = new THREE.Mesh(geometry, material);
mesh.position.z = Math.cos((i / suzannes) * Math.PI * 2) * 200;
mesh.position.y = Math.sin((i / suzannes) * Math.PI * 3) * 20;
mesh.position.x = Math.sin((i / suzannes) * Math.PI * 2) * 200;
mesh.rotation.y = (i / suzannes) * Math.PI * 2;
mesh.scale.setScalar(20);
group.add(mesh);
}
scene.add(group);
group.update = (dt, ct) => (group.rotation.y += dt * 0.2);
};
const ref = useRef(null);
useFrame((t) => {
if (!ref.current) return;
const bokehPass = ref.current;
bokehPass.mouse = threefy.mouseMovePosition;
});
return (
<>
{/* <background url={hdr_overcast_soil_puresky_2k_hdr} /> */}
<Model url={suzanne_glb} onLoad={onLoad} />
<bokehPass
ref={ref}
args={[
scene,
camera,
{ width, height, vignetting: true, shaderFocus: true },
]}
/>
</>
);
}
};
const DemoCurves = () => {
// Curve (for math)
// - LineCurve, LineCurve3
// - EllipseCurve ==> ArcCurve
// - CatmullRomCurve3
// - SplineCurve
// - QuadraticBezierCurve
// - QuadraticBezierCurve3
// - CubicBezierCurve
// - CubicBezierCurve3
//
// Curve (hierarchy)
// |- CurvePath (= curve array)
// |- Path(2d): provides methods for 2d shapes (eg: .moveTo().lineTo().bezierCurveTo())
// |- Shape(2d): defines a 2d shape plane using paths with (optional) holes
// 1) Shape define the outerPath (ccw)
// 2) Shape.holes define the holes in the shape (cw)
// 3) used to create ShapeGeometry or ExtrudeGeometry
// ShapePath (= path array)
//
// Line (for drawing)
// |- LineLoop
// |- LineSegments
//
// Steps:
// 1) Curve/Path/Shape.getPoints() ==> points
// 2) BufferGeometry.setFromPoints( Path.getPoints() )
// 3) THREE.Line( BufferGeometry, LineBasicMaterial )
//
// Note*:
// 1) Line.computeLineDistances(): needed for LineDashedMaterial
// 2) LineBasicMaterial.linewidth = 1 (always)
// 3) LineBasicMaterial.linecap(linejoin): ignored by WebGLRenderer
const example = 4;
if (example === 1) {
const path = new THREE.Path();
path.moveTo(0.5, 0.3);
path.quadraticCurveTo(0.5, 0.5, 0.3, 0.5);
path.lineTo(-0.3, 0.5);
path.quadraticCurveTo(-0.5, 0.5, -0.5, 0.3);
path.lineTo(-0.5, -0.3);
path.quadraticCurveTo(-0.5, -0.5, -0.3, -0.5);
path.lineTo(0.3, -0.5);
path.quadraticCurveTo(0.5, -0.5, 0.5, -0.3);
path.lineTo(0.5, 0.3);
const points = path.getPoints();
const ref = useRefEffect(() => {
const line = ref.current;
line.computeLineDistances();
});
return (
<line ref={ref} scale={10}>
<geometry type={"buffer"} setFromPoints={[points]} />
<material
type={"dashed"}
color={0xffff00}
dashSize={0.05}
gapSize={0.05}
/>
</line>
);
}
if (example === 2) {
const inputPoints = (format) => {
// all format return the same points
if (format === 1)
return [
new THREE.Vector3(-10, 0, 10),
new THREE.Vector3(-5, 5, 5),
new THREE.Vector3(0, 0, 0),
new THREE.Vector3(5, -5, 5),
new THREE.Vector3(10, 0, 10),
];
else if (format === 2)
return [
[-10, 0, 10],
[-5, 5, 5],
[0, 0, 0],
[5, -5, 5],
[10, 0, 10],
];
else if (format === 3)
return [-10, 0, 10, -5, 5, 5, 0, 0, 0, 5, -5, 5, 10, 0, 10];
else if (format === 4)
return [
{ x: -10, y: 0, z: 10 },
{ x: -5, y: 5, z: 5 },
{ x: 0, y: 0, z: 0 },
{ x: 5, y: -5, z: 5 },
{ x: 10, y: 0, z: 10 },
];
};
const points = new THREE.CatmullRomCurve3(inputPoints(1)).getPoints(50);
// (cf) two curves below are identical
return (
<>
<line position-y={0} computeLineDistances={""}>
<geometry type={"buffer"} setFromPoints={[points]} />
<material
type={"dashed"}
dashSize={1}
gapSize={0.5}
color={"skyblue"}
/>
</line>
<catmullRom3
position-y={2}
args={[inputPoints(2)]}
divisions={50}
type={"dashed"}
dashSize={1}
gapSize={0.5}
color={"red"}
/>
</>
);
}
if (example === 3) {
return (
<>
<lineCurve
dim={2} // 2d lineCurve
args={[
[0, 0],
[10, 10],
]}
type={"line"}
color={"skyblue"}
/>
<lineCurve
dim={3} // 3d LineCurve3
args={[
[0, 0, 0],
[-10, -10, -5],
]}
type={"dashed"}
color={"green"}
dashSize={1}
gapSize={0.5}
/>
<arcCurve // <arcCurve/> is the same as <ellipseCurve/>
args={[0, 0, 15, 10, 0, Math.PI * 2, false, Math.PI / 4]} // [aX, aY, xRadius, yRadius, aStartAngle, aEndAngle, aClockwise, aRotation]
divisions={50}
type={"line"}
color={"red"}
/>
<bezierCurve
order={"quadratic"}
dim={"2"} // QuadraticBezierCurve
args={[
[-10, 0],
[0, 15],
[10, 0],
]}
divisions={50}
type={"line"}
color={0xffff00}
/>
<bezierCurve
order={"cubic"}
dim={3} // CubicBezierCurve3
args={[
[-10, 0, 0],
[-5, 15, 0],
[20, 15, 0],
[10, 0, 0],
]}
divisions={50}
type={"dashed"}
color={0xffffaa}
dashSize={1}
gapSize={0.5}
/>
<splineCurve // <splineCurve dim={3}/> is the same as <catmullRom3/>
args={[
[
[-10, 0],
[0, 15],
[10, 0],
],
]}
divisions={50}
type={"line"}
color={0x0000ff}
/>
<catmullRom3
args={[
[
[-10, 0, 10],
[-5, 5, 5],
[0, 0, 0],
[5, -5, 5],
[10, 0, 10],
],
false,
"centripetal",
0.5,
]} // [points, closed, curveType, tension]
divisions={50}
type={"dashed"}
color={0x00aaff}
dashSize={1}
gapSize={0.5}
/>
<nurbsCurve
scale={4}
args={[
// degree
2,
// knots
[0.0, 0.0, 0.0, 0.25, 0.25, 0.5, 0.5, 0.75, 0.75, 1.0, 1.0, 1.0],
// controlPoints
[
[1.0, 0.0, 0.5, 1.0],
[1.0, 1.0, 0.5, 0.707107],
[0.0, 1.0, 0.5, 1.0],
[-1.0, 1.0, 0.5, 0.707107],
[-1.0, 0.0, 0.5, 1.0],
[-1.0, -1.0, 0.5, 0.707107],
[0.0, -1.0, 0.5, 1.0],
[1.0, -1.0, 0.5, 0.707107],
[1.0, 0.0, 0.5, 1.0],
],
]}
divisions={50}
type={"dashed"}
color={0xfdcfaf}
dashSize={0.1}
gapSize={0.05}
/>
<nurbsCurve
scale={5}
degree={2}
knots={[
0.0, 0.0, 0.0, 0.25, 0.25, 0.5, 0.5, 0.75, 0.75, 1.0, 1.0, 1.0,
]}
controlPoints={[
[1.0, 0.0, -0.5, 1.0],
[1.0, 1.0, -0.5, 0.707107],
[0.0, 1.0, -0.5, 1.0],
[-1.0, 1.0, -0.5, 0.707107],
[-1.0, 0.0, -0.5, 1.0],
[-1.0, -1.0, -0.5, 0.707107],
[0.0, -1.0, -0.5, 1.0],
[1.0, -1.0, -0.5, 0.707107],
[1.0, 0.0, -0.5, 1.0],
]}
divisions={50}
type={"dashed"}
color={"skyblue"}
dashSize={0.1}
gapSize={0.05}
/>
</>
);
}
if (example === 4) {
// the same result as example 3 (except for using 'Curve' component)
return (
<>
<curve // LineCurve
type={"line"} // 'line' can be omitted as default
dim={2} // 2d LineCurve
args={[
[0, 0],
[10, 10],
]}
linetype={"solid"}
color={"skyblue"}
/>
<curve // LineCurve3
type={"line"}
dim={3} // 3d LineCurve3
args={[
[0, 0, 0],
[-10, -10, -5],
]}
linetype={"dashed"}
color={"green"}
dashSize={1}
gapSize={0.5}
/>
<curve // ArcCurve or EllipseCurve
type={"arc"} // or 'ellipse'
args={[0, 0, 15, 10, 0, Math.PI * 2, false, Math.PI / 4]}
divisions={50}
linetype={"solid"}
color={"red"}
/>
<curve // QuadraticBezierCurve
type={"bezier"}
order={"quadratic"}
dim={"2"}
args={[
[-10, 0],
[0, 15],
[10, 0],
]}
divisions={50}
linetype={"solid"}
color={0xffff00}
/>
<curve // CubicBezierCurve3
type={"bezier"}
order={"cubic"}
dim={3}
args={[
[-10, 0, 0],
[-5, 15, 0],
[20, 15, 0],
[10, 0, 0],
]}
divisions={50}
linetype={"dashed"}
color={0xffffaa}
dashSize={1}
gapSize={0.5}
/>
<curve // SplineCurve
type={"spline"}
args={[
[
[-10, 0],
[0, 15],
[10, 0],
],
]}
divisions={50}
linetype={"solid"}
color={0x0000ff}
/>
<curve // CatmullRomCurve3
type={"catmullRom3"}
args={[
[
[-10, 0, 10],
[-5, 5, 5],
[0, 0, 0],
[5, -5, 5],
[10, 0, 10],
],
false,
"centripetal",
0.5,
]}
divisions={50}
linetype={"dashed"}
color={0x00aaff}
dashSize={1}
gapSize={0.5}
/>
<curve // NURBSCurve
type={"nurbs"}
scale={4}
args={[
// degree
2,
// knots
[0.0, 0.0, 0.0, 0.25, 0.25, 0.5, 0.5, 0.75, 0.75, 1.0, 1.0, 1.0],
// controlPoints
[
[1.0, 0.0, 0.5, 1.0],
[1.0, 1.0, 0.5, 0.707107],
[0.0, 1.0, 0.5, 1.0],
[-1.0, 1.0, 0.5, 0.707107],
[-1.0, 0.0, 0.5, 1.0],
[-1.0, -1.0, 0.5, 0.707107],
[0.0, -1.0, 0.5, 1.0],
[1.0, -1.0, 0.5, 0.707107],
[1.0, 0.0, 0.5, 1.0],
],
]}
divisions={50}
linetype={"dashed"}
color={0xfdcfaf}
dashSize={0.1}
gapSize={0.05}
/>
<curve // NURBSCurve
type={"nurbs"}
scale={5}
degree={2}
knots={[
0.0, 0.0, 0.0, 0.25, 0.25, 0.5, 0.5, 0.75, 0.75, 1.0, 1.0, 1.0,
]}
controlPoints={[
[1.0, 0.0, -0.5, 1.0],
[1.0, 1.0, -0.5, 0.707107],
[0.0, 1.0, -0.5, 1.0],
[-1.0, 1.0, -0.5, 0.707107],
[-1.0, 0.0, -0.5, 1.0],
[-1.0, -1.0, -0.5, 0.707107],
[0.0, -1.0, -0.5, 1.0],
[1.0, -1.0, -0.5, 0.707107],
[1.0, 0.0, -0.5, 1.0],
]}
divisions={50}
linetype={"dashed"}
color={"skyblue"}
dashSize={0.1}
gapSize={0.05}
/>
</>
);
}
};
const DemoShapes = () => {
const [x, y] = [2, 0];
const fishShape = new THREE.Shape()
.moveTo(x, y)
.quadraticCurveTo(x + 50, y - 80, x + 90, y - 10)
.quadraticCurveTo(x + 100, y - 10, x + 115, y - 40)
.quadraticCurveTo(x + 115, y, x + 115, y + 40)
.quadraticCurveTo(x + 100, y + 10, x + 90, y + 10)
.quadraticCurveTo(x + 50, y + 80, x, y);
const holePath = new THREE.Path()
.moveTo(x + 30, y + 0) // starting point of arc
.absarc(x + 20, y + 0, 10, 0, Math.PI * 2, true);
fishShape.holes.push(holePath);
const heartShape = new THREE.Shape()
.moveTo(x + 25, y + 25)
.bezierCurveTo(x + 25, y + 25, x + 20, y, x, y)
.bezierCurveTo(x - 30, y, x - 30, y + 35, x - 30, y + 35)
.bezierCurveTo(x - 30, y + 55, x - 10, y + 77, x + 25, y + 95)
.bezierCurveTo(x + 60, y + 77, x + 80, y + 55, x + 80, y + 35)
.bezierCurveTo(x + 80, y + 35, x + 80, y, x + 50, y)
.bezierCurveTo(x + 35, y, x + 25, y + 25, x + 25, y + 25);
const curveSegments = 12;
const extrudeSettings = {
depth: 8,
bevelEnabled: true,
bevelSegments: 2,
steps: 2,
bevelSize: 1,
bevelThickness: 1,
};
const texture = useLoader(raymarch_abstract1_jpg);
texture.wrapS = texture.wrapT = THREE.RepeatWrapping;
texture.repeat.set(0.008, 0.008);
const example = 1;
if (example === 1) {
return (
<>
<group position-y={10}>
<mesh scale={0.2}>
<geometry type={"shape"} args={[fishShape, curveSegments]} />
<material
type={"phong"}
color={0x3a6b67}
side={THREE.DoubleSide}
map={texture}
/>
</mesh>
<mesh scale={0.05} position={[1.3, 7, 0]} rotation-z={Math.PI}>
<geometry type={"shape"} args={[heartShape, curveSegments]} />
<material type={"phong"} color={0xff0000} side={THREE.DoubleSide} />
</mesh>
<mesh scale={0.2} rotation-y={Math.PI}>
<geometry type={"shape"} args={[fishShape, curveSegments]} />
<material
type={"phong"}
color={0xffaaaa}
side={THREE.DoubleSide}
map={texture}
/>
</mesh>
</group>
<group position-y={-10}>
<mesh scale={0.2}>
<geometry type={"extrude"} args={[fishShape, extrudeSettings]} />
<material
type={"phong"}
color={0x3a6b67}
side={THREE.DoubleSide}
map={texture}
/>
</mesh>
<mesh scale={0.05} position={[1.3, 7, 0]} rotation-z={Math.PI}>
<geometry type={"extrude"} args={[heartShape, extrudeSettings]} />
<material type={"phong"} color={0xff0000} side={THREE.DoubleSide} />
</mesh>
<mesh scale={0.2} rotation-y={Math.PI}>
<geometry type={"extrude"} args={[fishShape, extrudeSettings]} />
<material
type={"phong"}
color={0xffaaaa}
side={THREE.DoubleSide}
map={texture}
/>
</mesh>
</group>
</>
);
}
if (example === 2) {
return (
<>
<group position-y={10}>
<shape
scale={0.2}
args={[fishShape, curveSegments]}
type={"phong"}
color={0x3a6b67}
side={THREE.DoubleSide}
map={texture}
/>
<shape
scale={0.05}
position={[1.3, 7, 0]}
rotation-z={Math.PI}
args={[heartShape, curveSegments]}
type={"phong"}
color={0xff0000}
side={THREE.DoubleSide}
/>
<shape
scale={0.2}
rotation-y={Math.PI}
args={[fishShape, curveSegments]}
type={"phong"}
color={0xffaaaa}
side={THREE.DoubleSide}
map={texture}
/>
</group>
<group position-y={-10}>
<extrude
scale={0.2}
args={[fishShape, extrudeSettings]}
type={"phong"}
color={0x3a6b67}
side={THREE.DoubleSide}
map={texture}
/>
<extrude
scale={0.05}
position={[1.3, 7, 0]}
rotation-z={Math.PI}
args={[heartShape, extrudeSettings]}
type={"phong"}
color={0xff0000}
side={THREE.DoubleSide}
/>
<extrude
scale={0.2}
rotation-y={Math.PI}
args={[fishShape, extrudeSettings]}
type={"phong"}
color={0xffaaaa}
side={THREE.DoubleSide}
map={texture}
/>
</group>
</>
);
}
if (example === 3) {
return (
<>
<group position-y={10}>
<line scale={0.2}>
<geometry type={"buffer"} setFromPoints={[fishShape.getPoints()]} />
<material type={"line"} color={0x3a6b67} />
</line>
<line scale={0.2}>
<geometry
type={"buffer"}
setFromPoints={[fishShape.holes[0].getPoints()]}
/>
<material type={"line"} color={0x3a6b67} />
</line>
<line scale={0.05} position={[1.3, 7, 0]} rotation-z={Math.PI}>
<geometry
type={"buffer"}
setFromPoints={[heartShape.getPoints()]}
/>
<material type={"line"} color={0xff0000} />
</line>
<line scale={0.2} rotation-y={Math.PI}>
<geometry type={"buffer"} setFromPoints={[fishShape.getPoints()]} />
<material type={"line"} color={0xffaaaa} />
</line>
<line scale={0.2} rotation-y={Math.PI}>
<geometry
type={"buffer"}
setFromPoints={[fishShape.holes[0].getPoints()]}
/>
<material type={"line"} color={0xffaaaa} />
</line>
</group>
<group position-y={-10}>
<points scale={0.2}>
<geometry type={"buffer"} setFromPoints={[fishShape.getPoints()]} />
<material type={"points"} color={0x3a6b67} />
</points>
<points scale={0.2}>
<geometry
type={"buffer"}
setFromPoints={[fishShape.holes[0].getPoints()]}
/>
<material type={"points"} color={0x3a6b67} />
</points>
<points scale={0.05} position={[1.3, 7, 0]} rotation-z={Math.PI}>
<geometry
type={"buffer"}
setFromPoints={[heartShape.getPoints()]}
/>
<material type={"points"} color={0xff0000} />
</points>
<points scale={0.2} rotation-y={Math.PI}>
<geometry type={"buffer"} setFromPoints={[fishShape.getPoints()]} />
<material type={"points"} color={0xffaaaa} />
</points>
<points scale={0.2} rotation-y={Math.PI}>
<geometry
type={"buffer"}
setFromPoints={[fishShape.holes[0].getPoints()]}
/>
<material type={"points"} color={0xffaaaa} />
</points>
</group>
</>
);
}
};
const DemoCameraEffects = () => {
const DemoInstMesh = () => {
const instCount = 1000;
const ref = useRefEffect((instMesh) => {
for (let i = 0; i < instCount; i++) {
const m = randomMatrix(40, 40, 40, 0.5, 1);
const c = randomHSLColor();
instMesh.setMatrixAt(i, m);
instMesh.setColorAt(i, c);
}
});
useFrame((t) => {
if (ref.current) {
ref.current.rotation.x = Math.sin(t * 1.2);
ref.current.rotation.y = Math.sin(t * 2.4);
}
});
return (
<instancedMesh ref={ref} count={instCount}>
<boxGeometry />
<meshStandardMaterial />
</instancedMesh>
);
};
const example = 6;
const { get } = useThree();
const renderer = get("renderer");
if (example === 1) {
const [width, height] = get("width", "height");
return (
<>
<DemoInstMesh />
<anaglyphEffect args={[renderer, width, height]} />
</>
);
}
if (example === 2) {
const ref = useRefEffect((effect) => {
document.body.appendChild(effect.domElement);
});
return (
<>
<DemoInstMesh />
<asciiEffect
ref={ref}
args={[renderer, " .:-+*=%@#", { invert: true }]}
domElement-style-color={"white"}
domElement-style-backgroundColor={"black"}
/>
</>
);
}
if (example === 3) {
const defaultThickness = 0.003;
const defaultColor = [0, 0, 0];
const defaultAlpha = 1.0;
const defaultKeepAlive = true;
return (
<>
<DemoInstMesh />
<outlineEffect
args={[
renderer,
{ defaultThickness, defaultColor, defaultAlpha, defaultKeepAlive },
]}
/>
</>
);
}
if (example === 4) {
return (
<>
<DemoInstMesh />
<parallaxBarrierEffect args={[renderer]} />
</>
);
}
if (example === 5) {
return (
<>
<DemoInstMesh />
<peppersGhostEffect args={[renderer]} />
</>
);
}
if (example === 6) {
return (
<>
<DemoInstMesh />
<stereoEffect args={[renderer]} />
</>
);
}
};
const DemoAudio = () => {
const example = 2;
if (example === 1) {
const createAudioButton = () => {
const button = document.createElement("buttion");
button.id = "audioButton";
button.innerHTML = "Click To Play";
button.style.cssText = `
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%,-50%);
color: #ffffff;
cursor: pointer;
`;
document.body.appendChild(button);
return button;
};
const removeAudioButton = () => {
document.getElementById("audioButton").remove();
};
const ref = useRefEffect((audio) => {
const button = createAudioButton();
button.addEventListener("click", () => {
loadAudios(sample_mp3).then(async (buffer) => {
audio.setBuffer(buffer);
audio.play();
removeAudioButton();
});
});
});
return (
<audio
ref={ref}
args={[new THREE.AudioListener()]}
setLoop={true}
setVolume={0.2}
/>
);
}
if (example === 2) {
const createAudioButton = () => {
const button = document.createElement("buttion");
button.id = "audioButton";
button.innerHTML = "Click To Play";
button.style.cssText = `
position: absolute;
font-size: 16px;
top: 50%;
left: 50%;
transform: translate(-50%,-50%);
background: rgba(0,0,0,0.2);
border: 1px solid rgb(255, 255, 255);
border-radius: 8px;
color: #ffffff;
padding: 12px 18px;
text-transform: uppercase;
cursor: pointer;
`;
document.body.appendChild(button);
return button;
};
const removeAudioButton = () => {
document.getElementById("audioButton").remove();
};
const setAudioVisualizer = (audio) => {
const fftSize = 128;
const analyser = new THREE.AudioAnalyser(audio, fftSize);
const material = new THREE.ShaderMaterial({
depthWrite: false,
transparent: true,
side: THREE.DoubleSide,
uniforms: {
time: { value: 0.0 },
tAudioData: {
value: new THREE.DataTexture(
analyser.data,
fftSize / 2,
1,
THREE.RedFormat
),
},
},
vertexShader: `
varying vec2 vUv;
void main() {
vUv = uv;
vec4 mvPosition = vec4( position, 1.0 );
gl_Position = projectionMatrix * modelViewMatrix * mvPosition;
}
`,
fragmentShader: `
uniform sampler2D tAudioData;
uniform float time;
varying vec2 vUv;
void main() {
float f = texture2D( tAudioData, vec2( vUv.x, 0.0 ) ).r;
vec3 backColor = vec3( 0.0, vUv.x, vUv.y );
vec3 color = vec3( f, 0.5+0.5*sin(2.0*time), vUv.x );
float i = step( vUv.y, f );
float alpha = (1.0 - 0.2) * i + 0.2;
gl_FragColor = vec4( mix( backColor, color, i ), alpha );
}
`,
});
const geometry = new THREE.PlaneGeometry(1, 1);
const mesh = new THREE.Mesh(geometry, material);
mesh.position.z += 0.7;
let oldfreq = 0;
mesh.update = function (dt, ct) {
// oscillate along the x-axis
mesh.position.x = 0.01 * Math.sin(ct * 10);
// oscillate along the y-axis
const avgfreq = analyser.getAverageFrequency();
mesh.position.y = 0.01 * (avgfreq - oldfreq);
oldfreq = avgfreq;
// update material.uniforms
const uniforms = mesh.material.uniforms;
analyser.getFrequencyData();
uniforms["time"].value = ct;
uniforms["tAudioData"].value.needsUpdate = true;
};
audio.add(mesh);
};
const ref = useRefEffect((audio) => {
console.log(audio);
const button = createAudioButton();
button.addEventListener("click", () => {
// NOTE*: audio.source
// temporary used for audio source URLs
// to be used as AudioNodes in the future
loadAudios(audio.source).then(async (buffer) => {
audio.setBuffer(buffer);
audio.play();
// audio.listener ==> camera
useThree().camera.add(audio.listener);
// audio helper: display the directional sound
const { PositionalAudioHelper } = await import(
"three/examples/jsm/helpers/PositionalAudioHelper"
);
audio.add(new PositionalAudioHelper(audio, 1.5));
// audio visualizer: display the frequencies on plane
setAudioVisualizer(audio);
removeAudioButton();
});
});
});
return (
<box
scale={10}
type={"lambert"}
map={rockMossy_diffuse_jpg}
normalMap={rockMossy_normal_jpg}
>
<positionalAudio
ref={ref}
args={[new THREE.AudioListener()]}
setVolume={0.5}
setLoop={true}
setRefDistance={20} // reference distance at which the volume reduction starts taking effect
setDirectionalCone={[180, 230, 0.1]} // define the directional sound
source={sample_mp3} // temporary use for audio source URLs
/>
</box>
);
}
};
const DemoLOD = () => {
const example = 3;
if (example === 1) {
const ref = useRefEffect((lod) => {
const material = new THREE.MeshBasicMaterial({ wireframe: true });
const highDetail = new THREE.Mesh(
new THREE.IcosahedronGeometry(10, 3),
material
);
const midDetail = new THREE.Mesh(
new THREE.IcosahedronGeometry(10, 2),
material
);
const lowDetail = new THREE.Mesh(
new THREE.IcosahedronGeometry(10, 1),
material
);
lod.addLevel(highDetail, 0);
lod.addLevel(midDetail, 75);
lod.addLevel(lowDetail, 150);
});
return <lod ref={ref} />;
}
if (example === 2) {
const ref = useRefEffect((lod) => {
const distances = [0, 75, 150];
lod.children.forEach((child, i) => {
lod.levels.push({
distance: distances[i],
object: child,
hysteresis: 0,
});
});
});
return (
<lod ref={ref}>
<icosahedron args={[10, 3]} type={"basic"} wireframe color={"red"} />
<icosahedron args={[10, 2]} type={"basic"} wireframe color={"green"} />
<icosahedron args={[10, 1]} type={"basic"} wireframe color={"blue"} />
</lod>
);
}
if (example === 3) {
const level0 = new THREE.Mesh(
new THREE.IcosahedronGeometry(10, 3),
new THREE.MeshBasicMaterial({ wireframe: true, color: 0xff0000 })
);
const level1 = new THREE.Mesh(
new THREE.IcosahedronGeometry(10, 2),
new THREE.MeshBasicMaterial({ wireframe: true, color: 0x00ff00 })
);
const level2 = new THREE.Mesh(
new THREE.IcosahedronGeometry(10, 1),
new THREE.MeshBasicMaterial({ wireframe: true, color: 0x0000ff })
);
return (
<lod
addLevels={[
[level0, 0], // high-level mesh at distance = 0
[level1, 75], // middle-level mesh at distance = 75
[level2, 150], // low-level mesh at distance = 150
]}
/>
);
}
};
const DemoGridHelper = () => {
const size = 500;
const divisions = 50;
const gridXZCoords = (size, divisions) => {
const coords = [];
const spacing = size / divisions;
const textHeight = spacing * 0.05;
const x1 = size / 2,
x0 = -x1;
for (let x = x0; x <= x1; x += spacing) {
const coord = x.toFixed(2);
const coordX = new TextSprite(coord, {
textHeight: textHeight,
fontWeight: "bold",
});
const coordZ = coordX.clone();
coordX.position.set(parseFloat(coord), textHeight / 2, 0);
coordZ.position.set(0, textHeight / 2, parseFloat(coord));
coords.push(coordX, coordZ);
}
return coords;
};
const ref = useRefEffect((gridHelper) => {
const coords = gridXZCoords(size, divisions);
gridHelper.add(...coords);
});
return <gridHelper ref={ref} args={[size, divisions, 0xff4444, 0x404040]} />;
};
const DemoBackground = () => {
const example = 3;
if (example === 1) {
switch (1) {
case 1:
return <background color={"blue"} />;
case 2:
return <background color={0x0000ff} />;
case 3:
return <background color={[0, 0, 1]} />;
case 4:
return <background color={new THREE.Color(0, 0, 1)} />;
}
}
if (example === 2) return <background url={raymarch_pebbles_jpg} />;
if (example === 3)
return (
<background
url={[
cloud_px_png,
cloud_nx_png,
cloud_py_png,
cloud_ny_png,
cloud_pz_png,
cloud_nz_png,
]}
/>
);
if (example === 4)
return <background url={hdr_overcast_soil_puresky_2k_hdr} />;
};
const DemoAddonGeometries = () => {
const example = 5;
if (example === 1) {
const getTestPoints = () => {
const geometry = new THREE.IcosahedronGeometry(10);
const posAttrib = geometry.getAttribute("position");
const vertices = [];
for (let i = 0; i < posAttrib.count; i++) {
const vertex = new THREE.Vector3();
vertex.fromBufferAttribute(posAttrib, i);
vertices.push(vertex);
}
return vertices;
};
const points = getTestPoints();
// 1) normal expression:
// return <mesh>
// <geometry type={'convex'} args={[points]}/>
// <material type={'phong'} color={'yellow'} wireframe/>
// </mesh>;
// 2) abbreviated expression:
return <convex args={[points]} type={"phong"} color={"yellow"} wireframe />;
}
if (example === 2) {
const [step, setStep] = useState(0);
const [args, setArgs] = useState({
helper: new THREE.Mesh(new THREE.BoxGeometry(1, 1, 10)),
position: new THREE.Vector3(),
orientation: new THREE.Euler(),
size: new THREE.Vector3(),
color: new THREE.Color(),
mesh: null,
});
const onClick = (e, mesh) => {
const intersect = mesh.intersect;
const { helper, position, orientation, size, color } = args;
helper.position.copy(intersect.point);
const n = intersect.face.normal.clone();
n.transformDirection(mesh.matrixWorld);
n.multiplyScalar(10);
n.add(intersect.point);
helper.lookAt(n);
position.copy(intersect.point);
orientation.copy(helper.rotation);
orientation.z = Math.random() * 2 * Math.PI;
const scale = 5 + Math.random() * (10 - 5);
size.setScalar(scale);
color.setHex(Math.random() * 0xffffff);
setArgs({ helper, position, orientation, size, color, mesh });
setStep(step + 1);
};
const onLoad = (model) => {
const mesh = model.children[0];
mesh.material.color.set(0xeec1ad); // skin_color = 0xf1c27d
mesh.onClick = onClick;
// (cf)
// 1) first, model(= .glb) is loaded
// 2) then, decal is created using onClick()
};
if (step === 0) {
return <Model url={LeePerrySmith_glb} scale={5} onLoad={onLoad} />;
}
if (step > 0) {
return (
<decal
// geometry
args={[args.mesh, args.position, args.orientation, args.size]}
// material
type={"phong"}
color={args.color}
specular={0x444444}
map={decal_diffuse_png}
normalMap={decal_normal_jpg}
normalScale={[1, 1]}
shininess={30}
transparent={true}
depthTest={true}
depthWrite={false}
polygonOffset={true}
polygonOffsetFactor={-4}
wireframe={false}
/>
);
}
}
if (example === 3) {
const surfaceFn = (u, v, target) => {
const freq = Math.PI * 2 * 2;
u = u * 2 - 1;
v = v * 2 - 1;
target.set(u, v, Math.cos(u * freq) * Math.sin(v * freq));
};
const ref = useRefEffect((model) => {
model.geometry.attributes.uv2 = model.geometry.attributes.uv;
});
return (
<parametric
ref={ref}
args={[surfaceFn, 64, 64]}
scale={[15, 15, 1]}
rotation-x={Math.PI / -2}
type={"standard"}
color={"white"}
map={rockMossy_diffuse_jpg}
normalMap={rockMossy_normal_jpg}
aoMap={rockMossy_ao_jpg}
roughnessMap={rockMossy_aoRoughMetal_jpg}
/>
);
}
if (example === 4) {
const [font, setFont] = useState(null);
if (!font) {
const loader = new FontLoader();
// (cf) see https://github.com/mrdoob/three.js/tree/master/examples/fonts
// fontName = helvetiker, optimer, gentilis, droid sans, droid serif
// fontWeight = normal bold
// loader.load(optimer_bold_typeface_json, (font) => setFont(font));
loader.load("../public/fonts/optimer_bold.typeface.json", (font) =>
setFont(font)
);
}
const ref = useRef(null);
let novaTex;
if (font) {
novaTex = useLoader(raymarch_abstract1_jpg);
novaTex.wrapS = novaTex.wrapT = THREE.RepeatWrapping;
novaTex.repeat.set(0.008, 0.008);
useFrame((t) => {
const group = ref.current;
group.rotation.y = t * 0.4;
const text = group.children[0];
text.rotation.x = Math.sin(t * 2.5) * 0.2;
});
}
useEffect(() => {
const group = ref.current;
if (group) {
// 1st text
let text = group.children[0];
const g = text.geometry;
g.computeBoundingBox();
const xoffset = 1.0 * (g.boundingBox.max.x - g.boundingBox.min.x);
const yoffset = 1.0 * (g.boundingBox.max.y - g.boundingBox.min.y);
text.position.x = -xoffset;
// 2nd text
text = group.children[1];
text.position.x = xoffset * 0.03;
// 3rd text
text = group.children[2];
text.position.x = -xoffset * 0.975;
text.position.y = yoffset * 1.25;
}
});
return (
font && (
<group ref={ref} scale={0.1} position-y={-4}>
{/* 1st text */}
<text
args={[
"Nova",
{
font: font,
size: 70,
depth: 20,
curveSegments: 4,
bevelThickness: 2,
bevelSize: 1.5,
bevelEnabled: true,
},
]}
type={"standard"}
map={novaTex}
metalness={0.8}
roughness={0.1}
/>
{/* 2nd text */}
<text
args={[
"Graphix",
{
font: font,
size: 70,
depth: 20,
curveSegments: 4,
bevelThickness: 2,
bevelSize: 1.5,
bevelEnabled: true,
},
]}
type={"standard"}
color={0xbaff41}
metalness={0.8}
roughness={0.1}
/>
{/* 3rd text */}
<text
args={[
"https://www.nova-graphix.com",
{
font: font,
size: 22,
depth: 20,
curveSegments: 4,
bevelThickness: 2,
bevelSize: 1.5,
bevelEnabled: true,
},
]}
type={"standard"}
color={0xffffff}
metalness={0.8}
roughness={0.1}
/>
<background url={"images/background/leather.jpg"} />
</group>
)
);
}
if (example === 5) {
const bathrooms = useLoader([bathroom_diffuse_jpg, bathroom_normal_jpg]);
for (let i = 0; i < 2; i++) {
bathrooms[i].wrapS = bathrooms[i].wrapT = THREE.RepeatWrapping;
bathrooms[i].repeat.set(2, 8);
}
bathrooms[0].colorSpace = THREE.SRGBColorSpace;
const brickWalls = useLoader([brickWall_diffuse_jpg, brickWall_normal_jpg]);
for (let i = 0; i < 2; i++) {
brickWalls[i].wrapS = brickWalls[i].wrapT = THREE.RepeatWrapping;
brickWalls[i].repeat.set(4, 1);
}
brickWalls[0].colorSpace = THREE.SRGBColorSpace;
const mosss = useLoader([moss_diffuse_jpg, moss_normal_jpg]);
for (let i = 0; i < 2; i++) {
mosss[i].wrapS = mosss[i].wrapT = THREE.RepeatWrapping;
mosss[i].repeat.set(1, 1);
}
mosss[0].colorSpace = THREE.SRGBColorSpace;
const rockMossys = useLoader([
rockMossy_diffuse_jpg,
rockMossy_normal_jpg,
rockMossy_aoRoughMetal_jpg,
]);
for (let i = 0; i < 3; i++) {
rockMossys[i].wrapS = rockMossys[i].wrapT = THREE.RepeatWrapping;
rockMossys[i].repeat.set(4, 16);
}
rockMossys[0].colorSpace = THREE.SRGBColorSpace;
const r = 5,
h = 5,
e = 0.1;
const RR = 12; // major radius of a torus
const rr = 2; // minor radius of a torus
const Rmax = RR + rr,
Rmin = RR - rr;
const cylControlNet_01 = [
[
[r, -h, 0, 1],
[r, -h, r, 0.7071],
[0, -h, r, 1],
[-r, -h, r, 0.7071],
[-r, -h, 0, 1],
[-r, -h, -r, 0.7071],
[0, -h, -r, 1],
[r, -h, -r, 0.7071],
[r, -h, 0, 1],
],
[
[r, h, 0, 1],
[r, h, r, 0.7071],
[0, h, r, 1],
[-r, h, r, 0.7071],
[-r, h, 0, 1],
[-r, h, -r, 0.7071],
[0, h, -r, 1],
[r, h, -r, 0.7071],
[r, h, 0, 1],
],
];
const cylControlNet_02 = [
[
[r, h, 0, 1],
[r, -h, 0, 1],
],
[
[r, h, r, 0.7071],
[r, -h, r, 0.7071],
],
[
[0, h, r, 1],
[0, -h, r, 1],
],
[
[-r, h, r, 0.7071],
[-r, -h, r, 0.7071],
],
[
[-r, h, 0, 1],
[-r, -h, 0, 1],
],
[
[-r, h, -r, 0.7071],
[-r, -h, -r, 0.7071],
],
[
[0, h, -r, 1],
[0, -h, -r, 1],
],
[
[r, h, -r, 0.7071],
[r, -h, -r, 0.7071],
],
[
[r, h, 0, 1],
[r, -h, 0, 1],
],
];
const sphControlNet = [
[
[e, -r, 0, 1],
[e, -r, e, 0.7071],
[0, -r, e, 1],
[-e, -r, e, 0.7071],
[-e, -r, 0, 1],
[-e, -r, -e, 0.7071],
[0, -r, -e, 1],
[e, -r, -e, 0.7071],
[e, -r, 0, 1],
],
[
[r, -r, 0, 0.7071],
[r, -r, r, 0.5],
[0, -r, r, 0.7071],
[-r, -r, r, 0.5],
[-r, -r, 0, 0.7071],
[-r, -r, -r, 0.5],
[0, -r, -r, 0.7071],
[r, -r, -r, 0.5],
[r, -r, 0, 0.7071],
],
[
[r, 0, 0, 1],
[r, 0, r, 0.7071],
[0, 0, r, 1],
[-r, 0, r, 0.7071],
[-r, 0, 0, 1],
[-r, 0, -r, 0.7071],
[0, 0, -r, 1],
[r, 0, -r, 0.7071],
[r, 0, 0, 1],
],
[
[r, r, 0, 0.7071],
[r, r, r, 0.5],
[0, r, r, 0.7071],
[-r, r, r, 0.5],
[-r, r, 0, 0.7071],
[-r, r, -r, 0.5],
[0, r, -r, 0.7071],
[r, r, -r, 0.5],
[r, r, 0, 0.7071],
],
[
[e, r, 0, 1],
[e, r, e, 0.7071],
[0, r, e, 1],
[-e, r, e, 0.7071],
[-e, r, 0, 1],
[-e, r, -e, 0.7071],
[0, r, -e, 1],
[e, r, -e, 0.7071],
[e, r, 0, 1],
],
];
const torusControlNet = [
[
[RR, -rr, 0, 1],
[RR, -rr, RR, 0.7071],
[0, -rr, RR, 1],
[-RR, -rr, RR, 0.7071],
[-RR, -rr, 0, 1],
[-RR, -rr, -RR, 0.7071],
[0, -rr, -RR, 1],
[RR, -rr, -RR, 0.7071],
[RR, -rr, 0, 1],
],
[
[Rmax, -rr, 0, 0.7071],
[Rmax, -rr, Rmax, 0.5],
[0, -rr, Rmax, 0.7071],
[-Rmax, -rr, Rmax, 0.5],
[-Rmax, -rr, 0, 0.7071],
[-Rmax, -rr, -Rmax, 0.5],
[0, -rr, -Rmax, 0.7071],
[Rmax, -rr, -Rmax, 0.5],
[Rmax, -rr, 0, 0.7071],
],
[
[Rmax, 0, 0, 1],
[Rmax, 0, Rmax, 0.7071],
[0, 0, Rmax, 1],
[-Rmax, 0, Rmax, 0.7071],
[-Rmax, 0, 0, 1],
[-Rmax, 0, -Rmax, 0.7071],
[0, 0, -Rmax, 1],
[Rmax, 0, -Rmax, 0.7071],
[Rmax, 0, 0, 1],
],
[
[Rmax, rr, 0, 0.7071],
[Rmax, rr, Rmax, 0.5],
[0, rr, Rmax, 0.7071],
[-Rmax, rr, Rmax, 0.5],
[-Rmax, rr, 0, 0.7071],
[-Rmax, rr, -Rmax, 0.5],
[0, rr, -Rmax, 0.7071],
[Rmax, rr, -Rmax, 0.5],
[Rmax, rr, 0, 0.7071],
],
[
[RR, rr, 0, 1],
[RR, rr, RR, 0.7071],
[0, rr, RR, 1],
[-RR, rr, RR, 0.7071],
[-RR, rr, 0, 1],
[-RR, rr, -RR, 0.7071],
[0, rr, -RR, 1],
[RR, rr, -RR, 0.7071],
[RR, rr, 0, 1],
],
[
[Rmin, rr, 0, 0.7071],
[Rmin, rr, Rmin, 0.5],
[0, rr, Rmin, 0.7071],
[-Rmin, rr, Rmin, 0.5],
[-Rmin, rr, 0, 0.7071],
[-Rmin, rr, -Rmin, 0.5],
[0, rr, -Rmin, 0.7071],
[Rmin, rr, -Rmin, 0.5],
[Rmin, rr, 0, 0.7071],
],
[
[Rmin, 0, 0, 1],
[Rmin, 0, Rmin, 0.7071],
[0, 0, Rmin, 1],
[-Rmin, 0, Rmin, 0.7071],
[-Rmin, 0, 0, 1],
[-Rmin, 0, -Rmin, 0.7071],
[0, 0, -Rmin, 1],
[Rmin, 0, -Rmin, 0.7071],
[Rmin, 0, 0, 1],
],
[
[Rmin, -rr, 0, 0.7071],
[Rmin, -rr, Rmin, 0.5],
[0, -rr, Rmin, 0.7071],
[-Rmin, -rr, Rmin, 0.5],
[-Rmin, -rr, 0, 0.7071],
[-Rmin, -rr, -Rmin, 0.5],
[0, -rr, -Rmin, 0.7071],
[Rmin, -rr, -Rmin, 0.5],
[Rmin, -rr, 0, 0.7071],
],
[
[RR, -rr, 0, 1],
[RR, -rr, RR, 0.7071],
[0, -rr, RR, 1],
[-RR, -rr, RR, 0.7071],
[-RR, -rr, 0, 1],
[-RR, -rr, -RR, 0.7071],
[0, -rr, -RR, 1],
[RR, -rr, -RR, 0.7071],
[RR, -rr, 0, 1],
],
];
const getControlPolygonLine = (controlPolygon) => {
// create a line showing the control polygon of nurbs-curve
const n = controlPolygon.length;
let polygon = [];
for (let i = 0; i < n; i++) {
const c = controlPolygon[i];
polygon.push(new THREE.Vector3(c[0], c[1], c[2]));
}
return new THREE.Line(
new THREE.BufferGeometry().setFromPoints(polygon),
new THREE.LineBasicMaterial({
color: 0x333333,
opacity: 0.25,
transparent: true,
})
);
};
const getControlNetLines = (controlNet) => {
// create lines showing the control net of nurbs-surface
const lines = [];
const nu = controlNet.length;
const nv = controlNet[0].length;
const m = new THREE.LineBasicMaterial({
color: 0x333333,
opacity: 0.25,
transparent: true,
});
let polygon = [];
for (let i = 0; i < nu; i++) {
for (let j = 0; j < nv; j++) {
const c = controlNet[i][j];
polygon.push(new THREE.Vector3(c[0], c[1], c[2]));
}
const g = new THREE.BufferGeometry().setFromPoints(polygon);
lines.push(new THREE.Line(g, m));
}
polygon = [];
for (let j = 0; j < nv; j++) {
for (let i = 0; i < nu; i++) {
const c = controlNet[i][j];
polygon.push(new THREE.Vector3(c[0], c[1], c[2]));
}
const g = new THREE.BufferGeometry().setFromPoints(polygon);
lines.push(new THREE.Line(g, m));
}
return lines;
};
const cylRef_01 = useRefEffect((cyl) =>
cyl.add(...getControlNetLines(cylControlNet_01))
);
const cylRef_02 = useRefEffect((cyl) =>
cyl.add(...getControlNetLines(cylControlNet_02))
);
const sphRef = useRefEffect((sph) =>
sph.add(...getControlNetLines(sphControlNet))
);
const torusRef = useRefEffect((torus) => {
torus.geometry.attributes.uv2 = torus.geometry.attributes.uv;
torus.add(...getControlNetLines(torusControlNet));
});
return (
<>
<nurbsSurface
ref={cylRef_01}
position-x={-r * 1.1}
// nurbs definition
args={[
1, // u-degree
2, // v-degree
[0, 0, 1, 1], // u-knot
[0, 0, 0, 0.25, 0.25, 0.5, 0.5, 0.75, 0.75, 1, 1, 1], // v-knot
cylControlNet_01, // control points
]}
// parametric geometry
slices={2} // u = straight
stacks={50} // v = circular
// mesh material
type={"standard"}
side={THREE.DoubleSide}
map={bathrooms[0]}
normalMap={bathrooms[1]}
/>
<nurbsSurface
ref={cylRef_02}
position-x={r * 1.1}
// nurbs definition
args={[
2, // u-degree
1, // v-degree
[0, 0, 0, 0.25, 0.25, 0.5, 0.5, 0.75, 0.75, 1, 1, 1], // u-knot
[0, 0, 1, 1], // v-knot
cylControlNet_02, // control points
]}
// parametric geometry
slices={50} // u = circular
stacks={2} // v = straight
// mesh material
type={"standard"}
side={THREE.DoubleSide}
map={brickWalls[0]}
normalMap={brickWalls[1]}
/>
<nurbsSurface
ref={sphRef}
position-y={r * 2}
// nurbs definition
args={[
2, // u-degree
2, // v-degree
[0, 0, 0, 0.5, 0.5, 1, 1, 1], // u-knot
[0, 0, 0, 0.25, 0.25, 0.5, 0.5, 0.75, 0.75, 1, 1, 1], // v-knot
sphControlNet, // control points
]}
// parametric geometry
slices={25} // u = half-circular
stacks={50} // v = circular
// mesh material
type={"standard"}
map={mosss[0]}
normalMap={mosss[1]}
/>
<nurbsSurface
ref={torusRef}
position-y={-h * 1.5}
// nurbs definition
args={[
2, // u-degree
2, // v-degree
[0, 0, 0, 0.25, 0.25, 0.5, 0.5, 0.75, 0.75, 1, 1, 1], // u-knot
[0, 0, 0, 0.25, 0.25, 0.5, 0.5, 0.75, 0.75, 1, 1, 1], // v-knot
torusControlNet, // control points
]}
// parametric geometry
slices={50} // u = circular
stacks={50} // v = circular
// mesh material
type={"standard"}
color={0xdfd29e}
map={rockMossys[0]}
normalMap={rockMossys[1]}
aoMap={rockMossys[2]}
roughnessMap={rockMossys[2]}
/>
</>
);
}
};
const DemoExamples = ({ example }) => {
switch (example) {
case 51:
return <DemoFog />;
case 52:
return <DemoPostProcessing />;
case 53:
return <DemoCurves />;
case 54:
return <DemoShapes />;
case 55:
return <DemoCameraEffects />;
case 56:
return <DemoAudio />;
case 57:
return <DemoLOD />;
case 58:
return <DemoGridHelper />;
case 59:
return <DemoBackground />;
case 60:
return <DemoAddonGeometries />;
}
};
export { DemoExamples };
Last updated