Skip to content

Commit

Permalink
a3d-materials
Browse files Browse the repository at this point in the history
  • Loading branch information
Kinatzo committed Oct 15, 2024
1 parent 8eb16f5 commit 2eb95e5
Show file tree
Hide file tree
Showing 23 changed files with 32,681 additions and 974 deletions.
10 changes: 2 additions & 8 deletions packages/abstract-3d/src/abstract-3d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -56,22 +56,16 @@ export type Mesh = {
readonly geometry: Cylinder | Cone | Box | Line | Text | Polygon | Plane | Tube | Sphere | Shape;
};

// Refactor to THREE.MeshStandardMaterial | DXF
export type Material = {
readonly type: MaterialType;
readonly normal: string;
readonly hover?: string;
readonly selected?: string;
readonly dxf?: string;
readonly opacity?: number;
readonly shininess?: number;
readonly metalness?: number;
readonly roughness?: number;
readonly image?:
| { readonly type: "HashImage"; readonly hash: string; readonly imageType?: string }
| { readonly type: "UrlImage"; readonly url: string; readonly imageType?: string };
};

export type MaterialType = "Phong" | "Lambert" | "Basic";

export type Cylinder = {
readonly type: "Cylinder";
readonly pos: Vec3;
Expand Down
1 change: 1 addition & 0 deletions packages/abstract-3d/src/renderers/dxf/color.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export const color = (_color: string): string => "8";
15 changes: 8 additions & 7 deletions packages/abstract-3d/src/renderers/dxf/dxf-geometries/dxf-box.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import * as A3D from "../../../abstract-3d";
import { color } from "../color";
import { dxf3DFACE } from "../dxf-encoding";

export function dxfBox(b: A3D.Box, m: A3D.Material, parentPos: A3D.Vec3, parentRot: A3D.Vec3): string {
Expand All @@ -15,13 +16,13 @@ export function dxfBox(b: A3D.Box, m: A3D.Material, parentPos: A3D.Vec3, parentR
const v6 = vec3tr3(half.x, -half.y, -half.z);
const v7 = vec3tr3(half.x, half.y, -half.z);
const v8 = vec3tr3(-half.x, half.y, -half.z);

const mat = color(m.normal);
return (
dxf3DFACE(v1, v2, v3, v4, m.dxf) + // front
dxf3DFACE(v5, v6, v7, v8, m.dxf) + // Back
dxf3DFACE(v5, v1, v4, v8, m.dxf) + // Left
dxf3DFACE(v6, v2, v3, v7, m.dxf) + // Right
dxf3DFACE(v8, v7, v3, v4, m.dxf) + // Top
dxf3DFACE(v5, v6, v2, v1, m.dxf) // Bottom
dxf3DFACE(v1, v2, v3, v4, mat) + // front
dxf3DFACE(v5, v6, v7, v8, mat) + // Back
dxf3DFACE(v5, v1, v4, v8, mat) + // Left
dxf3DFACE(v6, v2, v3, v7, mat) + // Right
dxf3DFACE(v8, v7, v3, v4, mat) + // Top
dxf3DFACE(v5, v6, v2, v1, mat) // Bottom
);
}
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
import * as A3D from "../../../abstract-3d";
import { color } from "../color";
import { dxf3DFACE } from "../dxf-encoding";

export function dxfCone(c: A3D.Cone, m: A3D.Material, sides: number, parentPos: A3D.Vec3, parentRot: A3D.Vec3): string {
let dxfString = "";
const pos = A3D.vec3TransRot(c.pos, parentPos, parentRot);
const rot = A3D.vec3RotCombine(parentRot, c.rot ?? A3D.vec3Zero);
const vec3tr2 = (x: number, y: number, z: number): A3D.Vec3 => A3D.vec3TransRot(A3D.vec3(x, y, z), pos, rot);

const mat = color(m.normal);
const angleStep = (2 * Math.PI) / sides;
let currentAngle = 0;

Expand All @@ -21,8 +22,7 @@ export function dxfCone(c: A3D.Cone, m: A3D.Material, sides: number, parentPos:

if (i !== 0) {
const prevBot = botVec3Array[i - 1]!;
dxfString +=
dxf3DFACE(botPos, prevBot, currBot, currBot, m.dxf) + dxf3DFACE(currBot, prevBot, topPos, topPos, m.dxf);
dxfString += dxf3DFACE(botPos, prevBot, currBot, currBot, mat) + dxf3DFACE(currBot, prevBot, topPos, topPos, mat);
}
currentAngle += angleStep;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import * as A3D from "../../../abstract-3d";
import { color } from "../color";
import { dxf3DFACE } from "../dxf-encoding";

export function dxfCylinder(
Expand All @@ -12,7 +13,7 @@ export function dxfCylinder(
const pos = A3D.vec3TransRot(c.pos, parentPos, parentRot);
const rot = A3D.vec3RotCombine(parentRot, c.rot ?? A3D.vec3Zero);
const vec3tr = (x: number, y: number, z: number): A3D.Vec3 => A3D.vec3TransRot(A3D.vec3(x, y, z), pos, rot);

const mat = color(m.normal);
const angleStep = (2 * Math.PI) / sides;
let currentAngle = 0;

Expand All @@ -34,9 +35,9 @@ export function dxfCylinder(
const prevBot = botVec3Array[i - 1]!;
const prevTop = topVec3Array[i - 1]!;
dxfString +=
dxf3DFACE(botPos, prevBot, currBot, currBot, m.dxf) +
dxf3DFACE(topPos, prevTop, currTop, currTop, m.dxf) +
dxf3DFACE(currBot, prevBot, prevTop, currTop, m.dxf);
dxf3DFACE(botPos, prevBot, currBot, currBot, mat) +
dxf3DFACE(topPos, prevTop, currTop, currTop, mat) +
dxf3DFACE(currBot, prevBot, prevTop, currTop, mat);
}
currentAngle += angleStep;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import * as A3D from "../../../abstract-3d";
import { color } from "../color";
import { dxf3DFACE } from "../dxf-encoding";

export function dxfPlane(p: A3D.Plane, m: A3D.Material, parentPos: A3D.Vec3, parentRot: A3D.Vec3): string {
Expand All @@ -11,6 +12,6 @@ export function dxfPlane(p: A3D.Plane, m: A3D.Material, parentPos: A3D.Vec3, par
vec3tr(half.x, -half.y),
vec3tr(half.x, half.y),
vec3tr(-half.x, half.y),
m.dxf
color(m.normal)
);
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import * as A3D from "../../../abstract-3d";
import { color } from "../color";
import { dxf3DFACE } from "../dxf-encoding";

const chunkSize = 4;
Expand All @@ -11,21 +12,21 @@ export function dxfPolygon(p: A3D.Polygon, m: A3D.Material, parentPos: A3D.Vec3,
let i = 0;
if (points.length >= chunkSize) {
for (i; i < points.length; i += chunkSize) {
polygonString += dxf3DFACE(points[i]!, points[i + 1]!, points[i + 2]!, points[i + 3]!, m.dxf);
polygonString += dxf3DFACE(points[i]!, points[i + 1]!, points[i + 2]!, points[i + 3]!, color(m.normal));
}
}

if (i <= points.length && chunkSize - 1 <= points.length) {
const lastArrayLength = points.length - i;
switch (lastArrayLength) {
case 1:
polygonString += dxf3DFACE(points[i - 2]!, points[i - 1]!, points[i]!, points[i]!, m.dxf);
polygonString += dxf3DFACE(points[i - 2]!, points[i - 1]!, points[i]!, points[i]!, color(m.normal));
break;
case 2:
polygonString += dxf3DFACE(points[i - 1]!, points[i]!, points[i + 1]!, points[i + 1]!, m.dxf);
polygonString += dxf3DFACE(points[i - 1]!, points[i]!, points[i + 1]!, points[i + 1]!, color(m.normal));
break;
case 3:
polygonString += dxf3DFACE(points[i]!, points[i + 1]!, points[i + 2]!, points[i + 2]!, m.dxf);
polygonString += dxf3DFACE(points[i]!, points[i + 1]!, points[i + 2]!, points[i + 2]!, color(m.normal));
break;
default:
break;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import * as A3D from "../../../abstract-3d";
import { color } from "../color";
import { dxf3DFACE } from "../dxf-encoding";

const chunkSize = 4;
Expand All @@ -8,24 +9,25 @@ export function dxfPolygon(s: A3D.Shape, m: A3D.Material, parentPos: A3D.Vec3, p
const pos = A3D.vec3TransRot(s.pos, parentPos, parentRot);
const rot = A3D.vec3RotCombine(parentRot, s.rot ?? A3D.vec3Zero);
const points = s.points.map((p) => A3D.vec3TransRot(A3D.vec3(p.x, p.y, 0), pos, rot));
const mat = color(m.normal);
let i = 0;
if (points.length >= chunkSize) {
for (i; i < points.length; i += chunkSize) {
polygonString += dxf3DFACE(points[i]!, points[i + 1]!, points[i + 2]!, points[i + 3]!, m.dxf);
polygonString += dxf3DFACE(points[i]!, points[i + 1]!, points[i + 2]!, points[i + 3]!, mat);
}
}

if (i <= points.length && chunkSize - 1 <= points.length) {
const lastArrayLength = points.length - i;
switch (lastArrayLength) {
case 1:
polygonString += dxf3DFACE(points[i - 2]!, points[i - 1]!, points[i]!, points[i]!, m.dxf);
polygonString += dxf3DFACE(points[i - 2]!, points[i - 1]!, points[i]!, points[i]!, mat);
break;
case 2:
polygonString += dxf3DFACE(points[i - 1]!, points[i]!, points[i + 1]!, points[i + 1]!, m.dxf);
polygonString += dxf3DFACE(points[i - 1]!, points[i]!, points[i + 1]!, points[i + 1]!, mat);
break;
case 3:
polygonString += dxf3DFACE(points[i]!, points[i + 1]!, points[i + 2]!, points[i + 2]!, m.dxf);
polygonString += dxf3DFACE(points[i]!, points[i + 1]!, points[i + 2]!, points[i + 2]!, mat);
break;
default:
break;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ export const ReactDimensions = React.memo(
readonly sceneCenter: A3d.Vec3 | undefined;
}): JSX.Element => {
const dimensionMaterial = React.useMemo(
() => (dimensions?.material ? <ReactMaterial material={dimensions?.material} /> : <></>),
() => (dimensions?.material ? <ReactMaterial isText={true} material={dimensions?.material} /> : <></>),
[]
);
return (
Expand Down
1 change: 1 addition & 0 deletions packages/abstract-3d/src/renderers/react/react-group.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,7 @@ export function ReactGroup({
material={m.material}
id={id}
selectedId={selectedId}
isText={m.geometry.type === "Text"}
hoveredId={hoveredId || hoveredIdExternal}
materialStateImages={materialStateImages}
disabled={disabled}
Expand Down
2 changes: 1 addition & 1 deletion packages/abstract-3d/src/renderers/react/react-hotspot.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ export function ReactHotSpot({
})}
>
<ReactMesh mesh={h.mesh}>
<ReactMaterial id={h.id} material={h.mesh.material} hoveredId={hoveredId} />
<ReactMaterial id={h.id} isText={false} material={h.mesh.material} hoveredId={hoveredId} />
</ReactMesh>
</group>
{hotSpotTexts && text && (
Expand Down
112 changes: 38 additions & 74 deletions packages/abstract-3d/src/renderers/react/react-material.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import React from "react";
import { Color, DoubleSide, MaterialParameters, SRGBColorSpace, Texture, TextureLoader } from "three";
import { suspend } from "suspend-react";
import * as A3d from "../../abstract-3d";
import { shade } from "../shared";

const decreasedOpacity = 0.2;

Expand All @@ -16,6 +17,7 @@ export function ReactMaterial({
disabled,
materialStateImages,
state,
isText,
}: {
readonly material: A3d.Material;
readonly id?: string;
Expand All @@ -24,16 +26,24 @@ export function ReactMaterial({
readonly disabled?: boolean;
readonly materialStateImages?: Record<string, string>;
readonly state?: MaterialState | undefined;
readonly isText: boolean;
}): JSX.Element {
const mat =
!state || material.image?.type === "UrlImage"
? material
: state === "Accept"
? acceptMaterial
? acceptMat
: state === "Error"
? errorMaterial
: warningMaterial;
const color = selectedId === id ? mat.selected : hoveredId === id ? mat.hover : mat.normal;
? errorMar
: warningMat;
const color =
selectedId === id
? hoveredId === id
? shade(-0.4, selectMat.normal)
: selectMat.normal
: hoveredId === id
? shade(-0.4, mat.normal)
: mat.normal;
const opacity = material.opacity !== undefined ? material.opacity : materialDefaults.opacity!;
if (material.image?.type === "UrlImage") {
return (
Expand All @@ -44,51 +54,27 @@ export function ReactMaterial({
/>
);
}

switch (mat.type) {
case "Basic":
return (
<meshBasicMaterial
color={color}
side={DoubleSide}
transparent
{...(opacity < 1 ? { opacity } : materialDefaults)}
/>
);
case "Phong":
return (
<meshPhongMaterial
color={color}
shininess={(mat.shininess ?? 70) * 2}
side={DoubleSide}
{...(opacity < 1 || disabled
? { transparent: true, opacity: disabled ? opacity * decreasedOpacity : opacity }
: materialDefaults)}
/>
);
// return (
// <meshStandardMaterial
// color={color}
// roughness={0.45}
// metalness={0.55}
// side={DoubleSide}
// {...(mat.opacity < 1 || disabled
// ? { transparent: true, opacity: disabled ? mat.opacity * decreasedOpacity : mat.opacity }
// : materialDefaults)}
// />
// );
case "Lambert":
default:
return (
<meshLambertMaterial
color={color}
side={DoubleSide}
{...(opacity < 1 || disabled
? { transparent: true, opacity: disabled ? opacity * decreasedOpacity : opacity }
: materialDefaults)}
/>
);
if (isText) {
return (
<meshBasicMaterial
color={color}
side={DoubleSide}
transparent
{...(opacity < 1 ? { opacity } : materialDefaults)}
/>
);
}
return (
<meshStandardMaterial
color={color}
roughness={mat.roughness}
metalness={mat.metalness}
side={DoubleSide}
{...(opacity < 1 || disabled
? { transparent: true, opacity: disabled ? opacity * decreasedOpacity : opacity }
: materialDefaults)}
/>
);
}

function TextureMaterial({
Expand Down Expand Up @@ -131,29 +117,7 @@ const textureLoader = new TextureLoader();

const materialDefaults: MaterialParameters = { transparent: false, opacity: 1.0, depthWrite: true, depthTest: true };

const acceptMaterial: A3d.Material = {
type: "Phong",
normal: "rgb(0,148,91)",
hover: "rgb(1,88,55)",
selected: "rgb(1,88,55)",
opacity: 1.0,
shininess: 50,
};

const errorMaterial: A3d.Material = {
type: "Phong",
normal: "#b82f3a",
hover: "#991c31",
selected: "#991c31",
opacity: 1.0,
shininess: 50,
};

const warningMaterial: A3d.Material = {
type: "Phong",
normal: "rgb(240, 197, 48)",
hover: "rgb(221, 181, 38)",
selected: "rgb(182, 147, 20)",
opacity: 1.0,
shininess: 50,
};
const acceptMat: A3d.Material = { normal: "rgb(0,148,91)", opacity: 1.0, metalness: 0.5, roughness: 0.5 };
const selectMat: A3d.Material = { normal: "rgb(14,82,184)", opacity: 1.0, metalness: 0.5, roughness: 0.5 };
const errorMar: A3d.Material = { normal: "#b82f3a", opacity: 1.0, metalness: 0.5, roughness: 0.5 };
const warningMat: A3d.Material = { normal: "rgb(240, 197, 48)", opacity: 1.0, metalness: 0.5, roughness: 0.5 };
Loading

0 comments on commit 2eb95e5

Please sign in to comment.