7.5 Example codes (41~50)
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, { useRef } from "react";
import {
CustomMaterial,
mergeMeshes,
MergedMesh,
Mesh,
useFrame,
useRefEffect,
useThree,
} from "threefy";
import {
gridCoords,
gridIndices,
randomHSLColor,
randomMatrix,
transformMatrix,
} from "./ThreeUtils";
import { Model } from "./ThreeModels";
import {
Grass,
SimpleTree,
Sky,
SkyDome,
Terrain,
Water,
} from "./ThreeNatures";
import { Raymarch } from "./ThreeRaymarch";
import * as THREE from "three";
import crate_gif from "../public/images/crate.gif";
import bathroom_diffuse_jpg from "../public/images/bathroom/diffuse.jpg";
import terrain_Rugged_Terrain_diffuse_jpg from "../public/images/terrain/Rugged Terrain/diffuse.jpg";
import terrain_Rugged_Terrain_heightmap_jpg from "../public/images/terrain/Rugged Terrain/heightmap.jpg";
import raymarch_abstract1_jpg from "../public/images/raymarch/abstract1.jpg";
import raymarch_abstract2_jpg from "../public/images/raymarch/abstract2.jpg";
import raymarch_grayNoise256_png from "../public/images/raymarch/grayNoise256.png";
import raymarch_lichen_jpg from "../public/images/raymarch/lichen.jpg";
import raymarch_organic1_jpg from "../public/images/raymarch/organic1.jpg";
import raymarch_organic2_jpg from "../public/images/raymarch/organic2.jpg";
import raymarch_pebbles_jpg from "../public/images/raymarch/pebbles.jpg";
import raymarch_rgbaNoise256_png from "../public/images/raymarch/rgbaNoise256.png";
import raymarch_rockTiles_jpg from "../public/images/raymarch/rockTiles.jpg";
import water_normal_jpg from "../public/images/water/normal.jpg";
import leaf_ao_jpg from "../public/images/leaf/ao.jpg";
import leaf_diffuse_jpg from "../public/images/leaf/diffuse.jpg";
import leaf_displacement_png from "../public/images/leaf/displacement.png";
import leaf_normal_jpg from "../public/images/leaf/normal.jpg";
import leaf_roughness_jpg from "../public/images/leaf/roughness.jpg";
import wood_aoRoughMetal_jpg from "../public/images/wood/aoRoughMetal.jpg";
import wood_diffuse_jpg from "../public/images/wood/diffuse.jpg";
import wood_displacement_jpg from "../public/images/wood/displacement.jpg";
import wood_normal_jpg from "../public/images/wood/normal.jpg";
import moss_ao_jpg from "../public/images/moss/ao.jpg";
import moss_diffuse_jpg from "../public/images/moss/diffuse.jpg";
import moss_normal_jpg from "../public/images/moss/normal.jpg";
import moss_displacement_jpg from "../public/images/moss/displacement.jpg";
import moss_roughness_jpg from "../public/images/moss/roughness.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_displacement_jpg from "../public/images/rockMossy/displacement.jpg";
import rockMossy_normal_jpg from "../public/images/rockMossy/normal.jpg";
import gravel_diffuse_jpg from "../public/images/gravel/diffuse.jpg";
import gravel_displacement_jpg from "../public/images/gravel/displacement.jpg";
import gravel_normal_jpg from "../public/images/gravel/normal.jpg";
import gravel_aoRoughMetal_jpg from "../public/images/gravel/aoRoughMetal.jpg";
import jump_animation_glb from "../public/models/jump-animation.glb";
import ratamahatta_md2_zip from "../public/models/ratamahatta_md2.zip";
import wild_town_zip from "../public/models/wild_town.zip";
const DemoMergedMesh = () => {
const { set } = useThree();
// (cf)
// set( 'camera.far', 5000 ); // possible
// set( 'camera', { far: 5000 } ); // possible
// set( { 'camera.far': 10000 } ); // possible
const example = 1;
let url;
if (example === 1) {
set("camera.far", 10000);
url = wild_town_zip;
}
if (example === 2) {
set("camera", { near: 0.01, far: 100 });
set({ "camera.position.z": 5 });
url = jump_animation_glb;
}
if (example === 3) {
url = ratamahatta_md2_zip;
}
const ref = useRef(null);
const onLoad = (model) => {
// extract all meshes from model
const meshes = [];
model.traverse((object) => object.isMesh && meshes.push(object));
// find the meshes with UV
const meshes_with_uv = meshes.filter((mesh) =>
mesh.geometry.hasAttribute("uv")
);
mergeMeshes(meshes_with_uv).then((mergMesh) => {
const parent = model.parent;
parent.remove(model);
parent.add(mergMesh);
ref.current = mergMesh;
if (example === 1) {
mergMesh.scale.setScalar(0.1);
}
});
};
return <Model ref={ref} url={url} onLoad={onLoad} />;
};
const DemoMergedMesh2 = () => {
const [ni, nj, nk] = [20, 20, 20];
// const [ ni, nj, nk ] = [ 30, 30, 30 ];
// const [ ni, nj, nk ] = [ 40, 40, 40 ];
const [hi, hj, hk] = [ni / 2, nj / 2, nk / 2];
const example = 2;
if (example === 1) {
// slow rendering
return (
<>
{gridIndices(ni, nj, nk).map(([i, j, k]) => (
<box
key={`${i},${j},${k}`}
scale={0.7}
position={[-hi + i, -hj + j, -hk + k]}
map={crate_gif}
/>
))}
</>
);
}
if (example === 2) {
// fast rendering
return (
<MergedMesh>
{gridIndices(ni, nj, nk).map(([i, j, k]) => (
<box
key={`${i},${j},${k}`}
scale={0.7}
position={[-hi + i, -hj + j, -hk + k]}
map={crate_gif} // or map={useLoader(crate_gif)}
/>
))}
</MergedMesh>
);
}
};
const DemoMergedMesh3 = () => {
const example = 2;
if (example === 1) {
return (
<MergedMesh>
<box args={[10, 1, 10]} color={"tan"} map={crate_gif} />
<box args={[5, 5, 5]} color={"skyblue"} />
<box args={[1, 10, 1]} color={[1, 1, 0]} />
</MergedMesh>
);
}
if (example === 2) {
const tx = 2;
const trf = new THREE.Matrix4();
const rot = new THREE.Matrix4()
.premultiply(trf.makeRotationY(0.05))
.premultiply(trf.makeRotationX(0.025));
const scaleUp = new THREE.Matrix4()
.premultiply(trf.makeTranslation(-tx, 0, 0))
.premultiply(trf.makeScale(1.01, 1.01, 1.01))
.premultiply(trf.makeTranslation(tx, 0, 0));
const scaleDown = new THREE.Matrix4()
.premultiply(trf.makeTranslation(-tx, 0, 0))
.premultiply(trf.makeScale(0.99, 0.99, 0.99))
.premultiply(trf.makeTranslation(tx, 0, 0));
const ref = useRef(null);
useFrame((t) => {
const mergMesh = ref.current;
if (mergMesh) {
// instance id = 2
mergMesh.getMatrixAt(2, trf);
trf.premultiply(rot);
mergMesh.setMatrixAt(2, trf);
// instance id = 0
mergMesh.getMatrixAt(0, trf);
trf.premultiply(Math.sin(t * 10) > 0 ? scaleUp : scaleDown);
mergMesh.setMatrixAt(0, trf);
}
});
return (
<MergedMesh ref={ref} scale={10}>
{/* instance id = 0 */}
<box position={[tx, 0, 0]} color={"tan"} map={crate_gif} />
{/* instance id = 1 */}
<mesh position={[-tx, 0, 0]}>
<sphereGeometry args={[0.7]} />
<meshBasicMaterial color={0xffaa99} map={raymarch_organic1_jpg} />
</mesh>
{/* instance id = 2 */}
<Mesh>
<geometry type={"box"} args={[1, 2, 1]} />
<geometry type={"cylinder"} />
<material type={"standard"} map={raymarch_abstract2_jpg} />
</Mesh>
</MergedMesh>
);
}
};
const DemoCompareMeshes = () => {
const example = 4;
//=====================================================
// meshes: different geometry + different material
//=====================================================
if (example === 1) {
// indexed geometries
const types1 = [
"box",
"capsule",
"circle",
"cone",
"cylinder",
"lathe",
"plane",
"ring",
"shape",
"sphere",
"torus",
"torusKnot",
"tube",
];
// non-indexed geometries
const types2 = [
"dodecahedron",
"extrude",
"icosahedron",
"octahedron",
"tetrahedron",
]; // 'polyhedron' excluded why additional input is required
const materials = [
"basic",
"lambert",
"matcap",
"phong",
"standard",
"physical",
"toon",
];
const texUrls = [
raymarch_abstract1_jpg,
raymarch_abstract2_jpg,
raymarch_lichen_jpg,
raymarch_organic1_jpg,
raymarch_organic2_jpg,
raymarch_pebbles_jpg,
raymarch_rockTiles_jpg,
];
const { threefy } = useThree();
const textures = texUrls.map((url) => threefy.loadTexture(url));
textures.forEach((tex) => (tex.colorSpace = THREE.SRGBColorSpace));
const type1Count = types1.length;
const type2Count = types2.length;
const mtlCount = materials.length;
const texCount = textures.length;
const [n, dx, dim] = [10, 3, 3];
return (
<group>
{/* meshes with 'indexed' geometry */}
<group position={[-15, 0, 0]}>
{gridCoords(n, dx, dim).map((p, i) => (
<mesh key={i} scale={1} position={p}>
<geometry type={types1[i % type1Count]} />
<material
type={materials[i % mtlCount]}
map={textures[i % texCount]}
/>
</mesh>
))}
</group>
{/* meshes with 'non-indexed' geometry */}
<group position={[15, 0, 0]}>
{gridCoords(n, dx, dim).map((p, i) => (
<mesh key={i} scale={1} position={p}>
<geometry type={types2[i % type2Count]} />
<material
type={materials[i % mtlCount]}
map={textures[i % texCount]}
/>
</mesh>
))}
</group>
</group>
);
}
//=====================================================
// instancedMesh: same geometry + same material
//=====================================================
if (example === 2) {
const { threefy } = useThree();
const texture1 = threefy.loadTexture(raymarch_abstract1_jpg);
const texture2 = threefy.loadTexture(raymarch_abstract2_jpg);
// texture1.colorSpace = THREE.SRGBColorSpace;
// texture2.colorSpace = THREE.SRGBColorSpace;
const count = 1000;
const ref1 = useRefEffect((instMesh) => {
for (let i = 0; i < count; i++) {
const m = randomMatrix(30, 30, 30, 1, 1);
instMesh.setMatrixAt(i, m);
const c = randomHSLColor();
instMesh.setColorAt(i, c);
}
});
const ref2 = useRefEffect((instMesh) => {
for (let i = 0; i < count; i++) {
const m = randomMatrix(30, 30, 30, 1, 1);
instMesh.setMatrixAt(i, m);
const c = randomHSLColor();
instMesh.setColorAt(i, c);
}
});
return (
<group>
<instancedMesh
ref={ref1}
count={count}
scale={1}
position={[-15, 0, 0]}
>
<geometry type={"box"} />
<material type={"standard"} map={texture1} />
</instancedMesh>
<instancedMesh ref={ref2} count={count} scale={1} position={[15, 0, 0]}>
<geometry type={"sphere"} />
<material type={"standard"} map={texture2} />
</instancedMesh>
</group>
);
}
//=====================================================
// batchedMesh = different geometry + same material
//=====================================================
if (example === 3) {
// indexed geometries
const types1 = [
"box",
"capsule",
"circle",
"cone",
"cylinder",
"lathe",
"plane",
"ring",
"shape",
"sphere",
"torus",
"torusKnot",
"tube",
];
// non-indexed geometries
const types2 = [
"dodecahedron",
"extrude",
"icosahedron",
"octahedron",
"tetrahedron",
]; // 'polyhedron' excluded why additional input is required
const { threefy } = useThree();
const indexTex = threefy.loadTexture(raymarch_abstract1_jpg);
const nonindexTex = threefy.loadTexture(raymarch_abstract2_jpg);
indexTex.colorSpace = THREE.SRGBColorSpace;
nonindexTex.colorSpace = THREE.SRGBColorSpace;
const createGeometries = (count, isIndexed) =>
// count: total number of geometries
// isIndexed: types1 if true, types2 if false
{
const types = isIndexed ? types1 : types2;
const typeCount = types.length;
return Array(count)
.fill(0)
.map((x, i) => {
const type = types[i % typeCount];
return <geometry key={i} type={type} attach={`geometries-${i}`} />;
});
};
const [n, dx, dim] = [10, 3, 3];
const count = Math.pow(n, dim);
const posFn = (x, y, z, t) => [x, y, z];
const composeBatchMesh = (batchMesh) => {
const instIds = [];
batchMesh.geometries.forEach((geometry) => {
const geomId = batchMesh.addGeometry(geometry);
const instId = batchMesh.addInstance(geomId);
instIds.push(instId);
});
delete batchMesh.geometries;
gridCoords(n, dx, dim).map((p, i) => {
const trfm = transformMatrix([...p, 0], posFn);
batchMesh.setMatrixAt(instIds[i], trfm);
});
};
const ref1 = useRefEffect((batchMesh) => composeBatchMesh(batchMesh));
const ref2 = useRefEffect((batchMesh) => composeBatchMesh(batchMesh));
return (
<group>
{/* meshes with 'indexed' geometry */}
<batchedMesh
ref={ref1}
args={[count, 6553600, 6553600 * 2]}
position={[-15, 0, 0]}
>
{createGeometries(count, true)}
<material type={"standard"} map={indexTex} />
</batchedMesh>
{/* meshes with 'non-indexed' geometry */}
<batchedMesh
ref={ref2}
args={[count, 6553600, 6553600 * 2]}
position={[15, 0, 0]}
>
{createGeometries(count, false)}
<material type={"standard"} map={nonindexTex} />
</batchedMesh>
</group>
);
}
//=====================================================
// mergedMesh = different geometry + same material (but different texture)
//=====================================================
if (example === 4) {
// indexed geometries
const types1 = [
"box",
"capsule",
"circle",
"cone",
"cylinder",
"lathe",
"plane",
"ring",
"shape",
"sphere",
"torus",
"torusKnot",
"tube",
];
// non-indexed geometries
const types2 = [
"dodecahedron",
"extrude",
"icosahedron",
"octahedron",
"tetrahedron",
]; // 'polyhedron' excluded why additional input is required
const materials = [
"basic",
"lambert",
"matcap",
"phong",
"standard",
"physical",
"toon",
];
const texUrls = [
raymarch_abstract1_jpg,
raymarch_abstract2_jpg,
raymarch_lichen_jpg,
raymarch_organic1_jpg,
raymarch_organic2_jpg,
raymarch_pebbles_jpg,
raymarch_rockTiles_jpg,
];
const { threefy } = useThree();
const textures = texUrls.map((url) => threefy.loadTexture(url));
const createMeshes = (n, dx, dim, scale, isIndexed) =>
// n: # of meshes along each axis
// dx: distance between meshes
// dim: grid dimension
// scale: mesh scale
// isIndexed: types1 if true, types2 if false
{
const types = isIndexed ? types1 : types2;
const typeCount = types.length;
const mtlCount = materials.length;
const texCount = textures.length;
return gridCoords(n, dx, dim).map((p, i) => {
const Type = types[i % typeCount];
const mtl = materials[i % mtlCount];
const tex = textures[i % texCount];
if (dim === 1) {
return (
<Type
key={i}
scale={scale}
position={[p, 0, 0]}
type={mtl}
map={tex}
/>
);
} else if (dim === 2) {
return (
<Type
key={i}
scale={scale}
position={[p[0], p[1], 0]}
type={mtl}
map={tex}
/>
);
} else if (dim === 3) {
return (
<Type key={i} scale={scale} position={p} type={mtl} map={tex} />
);
}
});
};
const ref1 = useRef(null);
const ref2 = useRef(null);
const [n, dx, dim, scale] = [10, 5, 3, 1.5];
return (
<group>
{/* meshes with 'indexed' geometry */}
<MergedMesh ref={ref1} position={[-25, 0, 0]}>
{createMeshes(n, dx, dim, scale, true)}
</MergedMesh>
{/* meshes with 'non-indexed' geometry */}
<MergedMesh ref={ref2} position={[25, 0, 0]}>
{createMeshes(n, dx, dim, scale, false)}
</MergedMesh>
</group>
);
}
};
const DemoShaderMaterial = () => {
const ref = useRef(null);
useFrame((t) => {
if (!ref.current) return;
const mesh = ref.current;
const uniforms = mesh.material.uniforms;
uniforms["time"].value = t;
});
return (
<box
ref={ref}
args={[40, 10, 10, 40, 10, 10]}
type={"shader"}
uniforms={{
time: { value: 0.0 },
textureMaps: {
value: [
raymarch_organic2_jpg,
raymarch_abstract1_jpg,
raymarch_pebbles_jpg,
raymarch_lichen_jpg,
],
},
}}
vertexShader={`
varying vec3 vPos;
varying vec2 vUv;
uniform float time;
void main()
{
vec4 result = vec4( position.x, 1.0 * sin( position.x / 3.0 + time ) + position.y, position.z, 1.0 );
vPos = position;
vUv = uv;
gl_Position = projectionMatrix * (modelViewMatrix * result);
}
`}
fragmentShader={`
uniform sampler2D textureMaps[4];
varying vec3 vPos;
varying vec2 vUv;
uniform float time;
void main()
{
float g = abs(mod( vPos.y, 2.0 ));
float b = abs(sin( 0.5*time ));
if( vPos.x > 10.0 ) gl_FragColor = texture( textureMaps[0], vUv );
else if( vPos.x > 0.0 ) gl_FragColor = texture( textureMaps[1], vUv );
else if( vPos.x > -10.0 ) gl_FragColor = texture( textureMaps[2], vUv ) * vec4(1.0,g,b,1.0);
else gl_FragColor = texture( textureMaps[3], vUv );
}
`}
/>
);
};
const DemoCustomMaterial = () => {
const example = 3;
const heightUrl = terrain_Rugged_Terrain_heightmap_jpg;
const diffuseUrl = terrain_Rugged_Terrain_diffuse_jpg;
const normalUrl = water_normal_jpg;
const baseMaterialType = "standard"; // base material type (for custom-material)
const py = -20,
rx = -Math.PI / 2; // object(plane) transformation
const args = [100, 100, 64, 64]; // geometry(plane) arguments
const uniforms = {
// uniforms used by custom-material
height: { value: 70 },
tHeight: { value: heightUrl },
tDiffuse: { value: diffuseUrl },
};
// vertex declaration (injected to custom-material)
const vdeclare = `
uniform float height;
uniform sampler2D tHeight;
uniform sampler2D tDiffuse;
varying vec2 vUv;
`;
// vertex transform (injected to custom-material)
const vvertex = `
float h = texture( tHeight, uv ).x;
position = position + normal * h * height;
vUv = uv;
`;
// fragment declaration (injected to custom-material)
const fdeclare = `
uniform sampler2D tHeight;
uniform sampler2D tDiffuse;
varying vec2 vUv;
`;
// fragment diffuse transform (injected to custom-material)
const fdiffuse = `
diffuse *= texture2D( tDiffuse, vUv ).rgb;
`;
// fragment color transform (injected to custom-material)
const fcolor = `
gl_FragColor.rgb *= texture2D( tDiffuse, vUv ).rgb;
`;
if (example === 1) {
const material = new CustomMaterial(baseMaterialType, {
normalMap: normalUrl,
uniforms: uniforms,
vdeclare: vdeclare,
vvertex: vvertex,
fdeclare: fdeclare,
fdiffuse: fdiffuse,
fcolor: fcolor,
});
const geometry = new THREE.PlaneGeometry(...args);
const mesh = new THREE.Mesh(geometry, material);
mesh.position.y = py;
mesh.rotation.x = rx;
return <primitive object={mesh} />;
}
if (example === 2) {
return (
<mesh rotation-x={rx} position-y={py}>
<planeGeometry args={args} />
<customMaterial
type={baseMaterialType}
normalMap={normalUrl}
uniforms={uniforms}
vdeclare={vdeclare}
vvertex={vvertex}
fdeclare={fdeclare}
fdiffuse={fdiffuse}
fcolor={fcolor}
/>
</mesh>
);
}
if (example === 3) {
return (
<plane
rotation-x={rx}
position-y={py}
args={args}
type={`custom-${baseMaterialType}`} // 'custom-standard' (*order important)
normalMap={normalUrl}
uniforms={uniforms}
vdeclare={vdeclare}
vvertex={vvertex}
fdeclare={fdeclare}
fdiffuse={fdiffuse}
fcolor={fcolor}
/>
);
}
};
const DemoRaymarchShaders = () => {
const example = 2;
if (example === 1) {
// useful as background
const fshader = "cloudsFS";
let texture;
switch (fshader) {
case "cloudsFS":
texture = raymarch_rgbaNoise256_png;
break;
case "cloudyFS":
case "sunsetFS":
case "cellsFS":
break;
}
return <Raymarch fshader={fshader} textures={texture} />;
}
if (example === 2) {
// raymarch based on shadertoy
const fshader = "terrain2FS";
let textures;
switch (fshader) {
case "iceFS":
textures = [raymarch_pebbles_jpg];
break;
case "boxesFS":
textures = [raymarch_pebbles_jpg];
break;
case "spheresFS":
textures = [];
break;
case "spoutFS":
textures = [bathroom_diffuse_jpg];
break;
case "terrainFS":
textures = [raymarch_grayNoise256_png];
break;
case "terrain2FS":
textures = [
raymarch_lichen_jpg,
raymarch_organic1_jpg,
raymarch_grayNoise256_png,
raymarch_lichen_jpg,
];
break;
case "tunnelFS":
textures = [raymarch_lichen_jpg];
break;
case "galaxyFS":
textures = [raymarch_pebbles_jpg];
break;
case "mountainsFS":
textures = [raymarch_pebbles_jpg];
break;
case "canyonFS":
textures = [
raymarch_organic2_jpg,
raymarch_abstract1_jpg,
raymarch_rgbaNoise256_png,
];
break;
case "cavesFS":
textures = [raymarch_pebbles_jpg, raymarch_organic1_jpg];
break;
case "seaFS":
textures = [];
break;
case "weatherFS":
textures = [raymarch_rgbaNoise256_png];
break;
case "riverFS":
textures = [raymarch_grayNoise256_png, raymarch_organic1_jpg];
break;
case "forestFS":
textures = [raymarch_grayNoise256_png];
break;
case "fishFS":
textures = [
raymarch_organic2_jpg,
raymarch_abstract1_jpg,
raymarch_grayNoise256_png,
raymarch_lichen_jpg,
];
break;
}
return <Raymarch fshader={fshader} textures={textures} />;
}
};
const DemoNatureShaders = () => {
const example = 5;
if (example === 1) {
return <SkyDome />;
}
// if (example === 2) {
// return <Clouds />;
// }
if (example === 3) {
return (
<>
<Sky />
<Water waterSize={1024} />
</>
);
}
if (example === 4) {
// return <plane
// rotation-x={Math.PI/-2}
// // position-y={py}
// args={[1024,1024,256,256]}
// type={'standard'}
// map={'images/terrain/Rugged Terrain/diffuse.jpg'}
// displacementMap={'images/terrain/Rugged Terrain/heightmap.jpg'}
// displacementScale={600}
// />;
return <Terrain />;
}
if (example === 5) {
useThree().camera.position.set(0, 110, 200);
return (
<>
<Grass width={256} numBlades={5000} />
<SimpleTree scale={20} leafScale={20} />
</>
);
}
// if (example === 6) {
// return (
// <>
// <Grass width={256} numBlades={5000} color={0x3f6d21} />
// <ProcTree
// scale={20}
// twigDensity={7}
// twigColor={0x3f6d21}
// trunkColor={0x7c6344}
// />
// </>
// );
// }
};
const DemoPBRmaterials = () => {
const ref = useRefEffect((model) => {
// (cf)
// uv2: required for aoMap, lightMap
// aoMap: red channel is used
// roughnessMap: green channel is used
// metalnessMap: blue channel is used
model.geometry.attributes.uv2 = model.geometry.attributes.uv;
});
const example = "rockMossy";
switch (example) {
case "leaf":
return (
<sphere
ref={ref}
args={[16, 64, 32]}
type={"standard"}
map={leaf_diffuse_jpg}
normalMap={leaf_normal_jpg}
aoMap={leaf_ao_jpg}
roughnessMap={leaf_roughness_jpg}
displacementMap={leaf_displacement_png}
displacementScale={2}
/>
);
case "wood":
return (
<sphere
ref={ref}
args={[16, 64, 32]}
type={"standard"}
map={wood_diffuse_jpg}
normalMap={wood_normal_jpg}
aoMap={wood_aoRoughMetal_jpg}
roughnessMap={wood_aoRoughMetal_jpg}
displacementMap={wood_displacement_jpg}
displacementScale={2}
/>
);
case "moss":
return (
<sphere
ref={ref}
args={[16, 64, 32]}
type={"standard"}
map={moss_diffuse_jpg}
normalMap={moss_normal_jpg}
aoMap={moss_ao_jpg}
roughnessMap={moss_roughness_jpg}
displacementMap={moss_displacement_jpg}
displacementScale={2}
/>
);
case "rockMossy":
return (
<sphere
ref={ref}
args={[16, 64, 32]}
type={"standard"}
map={rockMossy_diffuse_jpg}
normalMap={rockMossy_normal_jpg}
aoMap={rockMossy_ao_jpg}
roughnessMap={rockMossy_aoRoughMetal_jpg}
displacementMap={rockMossy_displacement_jpg}
displacementScale={2}
/>
);
case "gravel":
return (
<sphere
ref={ref}
args={[16, 64, 32]}
type={"standard"}
map={gravel_diffuse_jpg}
normalMap={gravel_normal_jpg}
aoMap={gravel_aoRoughMetal_jpg}
roughnessMap={gravel_aoRoughMetal_jpg}
displacementMap={gravel_displacement_jpg}
displacementScale={2}
/>
);
}
};
const DemoControls = () => {
const { camera, renderer, scene } = useThree();
const example = 9;
// arcballControls
if (example === 1) {
return (
<>
<hemisphereLight />
<sphere type={"standard"} scale={5} position-x={-10} color={0xfe828c} />
<box type={"standard"} scale={10} position-x={10} color={"skyblue"} />
<gridHelper args={[5000, 500, 0xff4444, 0x404040]} />
<arcballControls args={[camera, renderer.domElement, scene]} />
</>
);
}
// dragControls
if (example === 2) {
return (
<>
<hemisphereLight />
<sphere type={"standard"} scale={5} position-x={-10} color={"red"} />
<box type={"standard"} scale={10} position-x={10} color={"skyblue"} />
<gridHelper args={[5000, 500, 0xff4444, 0x404040]} />
<dragControls args={[scene.children, camera, renderer.domElement]} />
</>
);
}
// firstPersonControls
if (example === 3) {
return (
<>
<hemisphereLight />
<sphere type={"standard"} scale={5} position-x={-10} color={"red"} />
<box type={"standard"} scale={10} position-x={10} color={"skyblue"} />
<gridHelper args={[5000, 500, 0xff4444, 0x404040]} />
<firstPersonControls
args={[camera, renderer.domElement]}
movementSpeed={10}
lookSpeed={0.05}
/>
</>
);
}
// flyControls
if (example === 4) {
return (
<>
<hemisphereLight />
<sphere type={"standard"} scale={5} position-x={-10} color={"red"} />
<box type={"standard"} scale={10} position-x={10} color={"skyblue"} />
<gridHelper args={[5000, 500, 0xff4444, 0x404040]} />
<flyControls
args={[camera, renderer.domElement]}
movementSpeed={10}
rollSpeed={0.2}
/>
</>
);
}
// mapControls
if (example === 5) {
return (
<>
<hemisphereLight />
<sphere type={"standard"} scale={5} position-x={-10} color={"red"} />
<box type={"standard"} scale={10} position-x={10} color={"skyblue"} />
<gridHelper args={[5000, 500, 0xff4444, 0x404040]} />
<mapControls
args={[camera, renderer.domElement]}
enableDamping={true}
/>
</>
);
}
// orbitControls
if (example === 6) {
return (
<>
<hemisphereLight />
<sphere type={"standard"} scale={5} position-x={-10} color={"red"} />
<box type={"standard"} scale={10} position-x={10} color={"skyblue"} />
<gridHelper args={[5000, 500, 0xff4444, 0x404040]} />
<orbitControls
args={[camera, renderer.domElement]}
enableDamping={true}
dampingFactor={0.075}
/>
</>
);
}
// pointerLockControls
if (example === 7) {
return (
<>
<hemisphereLight />
<sphere type={"standard"} scale={5} position-x={-10} color={"red"} />
<box type={"standard"} scale={10} position-x={10} color={"skyblue"} />
<gridHelper args={[5000, 500, 0xff4444, 0x404040]} />
<pointerLockControls args={[camera, document.body]} />
</>
);
}
// trackballControls
if (example === 8) {
return (
<>
<hemisphereLight />
<sphere type={"standard"} scale={5} position-x={-10} color={"red"} />
<box type={"standard"} scale={10} position-x={10} color={"skyblue"} />
<gridHelper args={[5000, 500, 0xff4444, 0x404040]} />
<trackballControls
args={[camera, renderer.domElement]}
rotateSpeed={5}
/>
</>
);
}
// transformControls
if (example === 9) {
return (
<>
<hemisphereLight />
<sphere type={"standard"} scale={5} position-x={-10} color={"red"} />
<box type={"standard"} scale={10} position-x={10} color={"skyblue"} />
<gridHelper args={[5000, 500, 0xff4444, 0x404040]} />
<transformControls args={[camera, renderer.domElement]} />
</>
);
}
};
const DemoExamples = ({ example }) => {
switch (example) {
case 41:
return <DemoMergedMesh />;
case 42:
return <DemoMergedMesh2 />;
case 43:
return <DemoMergedMesh3 />;
case 44:
return <DemoCompareMeshes />;
case 45:
return <DemoShaderMaterial />;
case 46:
return <DemoCustomMaterial />;
case 47:
return <DemoRaymarchShaders />;
case 48:
return <DemoNatureShaders />;
case 49:
return <DemoPBRmaterials />;
case 50:
return <DemoControls />;
}
};
export { DemoExamples };
Last updated