@polygonjs/polygonjs
Version:
node-based WebGL 3D engine https://polygonjs.com
345 lines (323 loc) • 9.57 kB
text/typescript
import {Number2} from '../../types/GlobalTypes';
import {
Object3D,
LineSegments,
InstancedMesh,
Mesh,
Points,
Group,
Scene,
MeshStandardMaterial,
PointsMaterial,
LineBasicMaterial,
FrontSide,
} from 'three';
import type {
AmbientLight,
// SkinnedMesh,
// Bone,
CubeCamera,
DirectionalLight,
HemisphereLight,
LightProbe,
Material,
LOD,
OrthographicCamera,
PerspectiveCamera,
PointLight,
RectAreaLight,
SpotLight,
} from 'three';
import {GroupCollectionData} from './EntityGroupCollection';
import {CoreObjectType, ObjectContent} from './ObjectContent';
import type {PhysicalCamera, ShapedAreaLight, PhysicalSpotLight} from '../render/PBR/three-gpu-pathtracer';
// import {Poly} from '../../engine/Poly';
interface MaterialsByString {
[propName: string]: Material;
}
export enum ObjectType {
AMBIENT_LIGHT = 'AmbientLight',
AREA_LIGHT = 'AreaLight',
// BONE = 'Bone',
CUBE_CAMERA = 'CubeCamera',
DIRECTIONAL_LIGHT = 'DirectionalLight',
GROUP = 'Group',
HEMISPHERE_LIGHT = 'HemisphereLight',
INSTANCED_MESH = 'InstancedMesh',
LIGHT_PROBE = 'LightProbe',
LINE_SEGMENTS = 'LineSegments',
LOD = 'LOD',
MESH = 'Mesh',
OBJECT3D = 'Object3D',
ORTHOGRAPHIC_CAMERA = 'OrthographicCamera',
PERSPECTIVE_CAMERA = 'PerspectiveCamera',
PHYSICAL_CAMERA = 'PhysicalCamera',
PHYSICAL_SPOT_LIGHT = 'PhysicalSpotLight',
POINT_LIGHT = 'PointLight',
POINTS = 'Points',
SCENE = 'Scene',
SHAPED_AREA_LIGHT = 'ShapedAreaLight',
// SKINNED_MESH = 'SkinnedMesh',
SPOT_LIGHT = 'SpotLight',
UNKNOWN = 'Unknown',
QUAD = 'Quad',
}
export const OBJECT_TYPES: ObjectType[] = [
ObjectType.GROUP,
ObjectType.LINE_SEGMENTS,
ObjectType.MESH,
ObjectType.OBJECT3D,
ObjectType.POINTS,
ObjectType.SCENE,
];
interface ObjectContentConstructor<T extends CoreObjectType> {
new (arg0: any, arg1?: any, arg2?: any): ObjectContent<T>;
}
export type DefaultObjectContentConstructor = ObjectContentConstructor<CoreObjectType>;
export interface ObjectByObjectType {
[ObjectType.AMBIENT_LIGHT]: AmbientLight;
[ObjectType.AREA_LIGHT]: RectAreaLight;
// [ObjectType.BONE]: typeof Bone;
[ObjectType.CUBE_CAMERA]: CubeCamera;
[ObjectType.DIRECTIONAL_LIGHT]: DirectionalLight;
[ObjectType.GROUP]: Group;
[ObjectType.HEMISPHERE_LIGHT]: HemisphereLight;
[ObjectType.INSTANCED_MESH]: InstancedMesh;
[ObjectType.LIGHT_PROBE]: LightProbe;
[ObjectType.LINE_SEGMENTS]: LineSegments;
[ObjectType.LOD]: LOD;
[ObjectType.MESH]: Mesh;
[ObjectType.OBJECT3D]: Object3D;
[ObjectType.POINT_LIGHT]: PointLight;
[ObjectType.POINTS]: Points;
[ObjectType.ORTHOGRAPHIC_CAMERA]: OrthographicCamera;
[ObjectType.PERSPECTIVE_CAMERA]: PerspectiveCamera;
[ObjectType.PHYSICAL_CAMERA]: PhysicalCamera;
[ObjectType.PHYSICAL_SPOT_LIGHT]: PhysicalSpotLight;
// [ObjectType.POINTS]: typeof Points;
[ObjectType.SCENE]: Scene;
[ObjectType.SHAPED_AREA_LIGHT]: ShapedAreaLight;
// [ObjectType.SKINNED_MESH]: typeof SkinnedMesh;
[ObjectType.SPOT_LIGHT]: SpotLight;
[ObjectType.UNKNOWN]: null;
[ObjectType.QUAD]: null;
}
export interface ObjectData {
type: ObjectType;
name: string | null;
childrenCount: number;
groupData: GroupCollectionData;
verticesCount: number;
pointsCount: number;
primitivesCount: number;
primitiveName: string;
}
const UNKNOWN_OBJECT_TYPE: ObjectTypeData = {
type: ObjectType.UNKNOWN,
checkFunc: (o) => ObjectType.UNKNOWN,
humanName: 'Unknown',
ctor: null as any,
};
// type DataByConstructor = Map<DefaultObjectContentConstructor, ObjectTypeData>;
type ObjectTypeCheckFunction = (object: ObjectContent<CoreObjectType>) => ObjectType | undefined;
type DataByObjectType = Map<ObjectType, ObjectTypeData>;
export interface ObjectTypeData {
type: ObjectType;
checkFunc: ObjectTypeCheckFunction;
ctor: DefaultObjectContentConstructor;
humanName: string;
}
interface ObjectTypeConstructorRegisters {
objectTypeCheckFunctions: ObjectTypeCheckFunction[];
dataByObjectType: DataByObjectType;
}
function _initializeObjectTypeFromConstructor() {
const objectTypeCheckFunctions: ObjectTypeCheckFunction[] = [];
const dataByObjectType: DataByObjectType = new Map();
const maps: ObjectTypeConstructorRegisters = {objectTypeCheckFunctions, dataByObjectType};
function _register(
type: ObjectType,
checkFunc: ObjectTypeCheckFunction,
ctor: DefaultObjectContentConstructor,
humanName?: string
) {
_registerObjectType_(maps, {
type,
checkFunc,
ctor,
humanName: humanName || type,
});
}
_register(
ObjectType.OBJECT3D,
(o) => ((o as Object3D).isObject3D ? ObjectType.OBJECT3D : undefined),
Object3D,
'Object3D'
);
_register(ObjectType.MESH, (o) => ((o as Mesh).isMesh ? ObjectType.MESH : undefined), Mesh, 'Mesh');
_register(ObjectType.GROUP, (o) => ((o as Group).isGroup ? ObjectType.GROUP : undefined), Group, 'Group');
_register(
ObjectType.LINE_SEGMENTS,
(o) => ((o as LineSegments).isLineSegments ? ObjectType.LINE_SEGMENTS : undefined),
LineSegments,
'LineSegments'
);
_register(
ObjectType.INSTANCED_MESH,
(o) => ((o as InstancedMesh).isInstancedMesh ? ObjectType.INSTANCED_MESH : undefined),
InstancedMesh,
'InstancedMesh'
);
_register(ObjectType.POINTS, (o) => ((o as Points).isPoints ? ObjectType.POINTS : undefined), Points, 'Points');
_register(ObjectType.SCENE, (o) => ((o as Scene).isScene ? ObjectType.SCENE : undefined), Scene, 'Scene');
return maps;
}
const {objectTypeCheckFunctions, dataByObjectType}: ObjectTypeConstructorRegisters =
_initializeObjectTypeFromConstructor();
function _registerObjectType_(maps: ObjectTypeConstructorRegisters, data: ObjectTypeData) {
maps.objectTypeCheckFunctions.unshift(data.checkFunc);
maps.dataByObjectType.set(data.type, data);
}
export function registerObjectType(data: ObjectTypeData) {
_registerObjectType_({objectTypeCheckFunctions, dataByObjectType}, data);
}
export function objectTypeFromObject(object: ObjectContent<CoreObjectType>): ObjectType {
return dataFromObject(object).type;
}
export function dataFromObject(object: ObjectContent<CoreObjectType>): ObjectTypeData {
for (const checkFunc of objectTypeCheckFunctions) {
const objectType = checkFunc(object);
if (objectType) {
return dataByObjectType.get(objectType) as ObjectTypeData;
}
}
return UNKNOWN_OBJECT_TYPE;
}
export function objectConstructorByObjectType<O extends ObjectType>(objectType: O): ObjectByObjectType[O] {
const data = dataByObjectType.get(objectType);
if (data) {
return data.ctor as any as ObjectByObjectType[O];
} else {
console.warn(`no constructor found for type '${objectType}'`);
return dataByObjectType.get(ObjectType.MESH) as any as ObjectByObjectType[O];
}
}
export const DEFAULT_MATERIALS: MaterialsByString = {
MeshStandard: new MeshStandardMaterial({
color: 0xffffff,
side: FrontSide,
metalness: 0.5,
roughness: 0.9,
}),
// [ObjectType.MESH]: new MeshLambertMaterial({
// color: new Color(1, 1, 1),
// side: FrontSide,
// vertexColors: false,
// transparent: true,
// depthTest: true,
// }),
[ObjectType.MESH]: new MeshStandardMaterial({
color: 0xffffff,
side: FrontSide,
metalness: 0.0,
roughness: 0.9,
}),
[ObjectType.POINTS]: new PointsMaterial({
color: 0xffffff,
size: 0.1,
//blending: AdditiveBlending
depthTest: true,
}),
[ObjectType.LINE_SEGMENTS]: new LineBasicMaterial({
color: 0xffffff,
linewidth: 1,
}),
};
export enum AttribClass {
POINT = 'point',
VERTEX = 'vertex',
PRIMITIVE = 'primitive',
OBJECT = 'object',
CORE_GROUP = 'coreGroup',
}
export const ATTRIBUTE_CLASSES: Array<AttribClass> = [
AttribClass.POINT,
AttribClass.VERTEX,
AttribClass.PRIMITIVE,
AttribClass.OBJECT,
AttribClass.CORE_GROUP,
];
export const ATTRIBUTE_CLASSES_WITHOUT_CORE_GROUP: Array<AttribClass> = [
AttribClass.POINT,
AttribClass.VERTEX,
AttribClass.PRIMITIVE,
AttribClass.OBJECT,
];
export const AttribClassMenuEntries = ATTRIBUTE_CLASSES.map((name, value) => ({name, value}));
export const AttribClassMenuEntriesWithoutCoreGroup = ATTRIBUTE_CLASSES_WITHOUT_CORE_GROUP.map((name, value) => ({
name,
value,
}));
export enum AttribType {
NUMERIC = 'numeric',
STRING = 'string',
}
export const ATTRIBUTE_TYPES: Array<AttribType> = [AttribType.NUMERIC, AttribType.STRING];
export const AttribTypeMenuEntries = ATTRIBUTE_TYPES.map((name, value) => ({name, value}));
export enum AttribSize {
FLOAT = 1,
VECTOR2 = 2,
VECTOR3 = 3,
VECTOR4 = 4,
}
export const ATTRIBUTE_SIZES: Array<AttribSize> = [
AttribSize.FLOAT,
AttribSize.VECTOR2,
AttribSize.VECTOR3,
AttribSize.VECTOR4,
];
export const ATTRIBUTE_SIZE_RANGE: Number2 = [AttribSize.FLOAT, AttribSize.VECTOR4];
// export const CoreConstant = {
// ATTRIB_CLASS: {
// VERTEX: AttribClass.POINT,
// OBJECT: AttribClass.OBJECT,
// },
// OBJECT_TYPES: ObjectTypes,
// CONSTRUCTOR_NAMES_BY_CONSTRUCTOR_NAME: {
// [Scene.name]: 'Scene',
// [Group.name]: 'Group',
// [Object3D.name]: 'Object3D',
// [Mesh.name]: 'Mesh',
// [Points.name]: 'Points',
// [LineSegments.name]: 'LineSegments',
// [Bone.name]: 'Bone',
// [SkinnedMesh.name]: 'SkinnedMesh',
// },
// CONSTRUCTORS_BY_NAME: {
// [ObjectType.MESH]: Mesh,
// [ObjectType.POINTS]: Points,
// [ObjectType.LINE_SEGMENTS]: LineSegments,
// },
// MATERIALS: materials,
// };
export enum ComponentName {
x = 'x',
y = 'y',
z = 'z',
w = 'w',
r = 'r',
g = 'g',
b = 'b',
}
export type ComponentIndex = 0 | 1 | 2 | 3;
export const COMPONENT_INDICES: Record<ComponentName, ComponentIndex> = {
x: 0,
y: 1,
z: 2,
w: 3,
r: 0,
g: 1,
b: 2,
};
export const DOT = '.';
export type GroupString = string;