Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

star_mod_renderer

Package Overview
Dependencies
Maintainers
1
Versions
86
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

star_mod_renderer - npm Package Compare versions

Comparing version 1.0.39 to 1.0.40

helper/filesHelper/detect.js

1

assets/EditorControls.js
import * as THREE from 'star_mod_custom_three';
// TODO: 1. 双指放大缩小事件

@@ -3,0 +4,0 @@ class EditorControls extends THREE.EventDispatcher {

@@ -0,0 +0,0 @@ export declare class Signal {

@@ -0,0 +0,0 @@ /* eslint-disable no-unused-vars */

23

default.js

@@ -122,7 +122,8 @@ import * as THREE from 'star_mod_custom_three';

];
const textureCube = new THREE.CubeTextureLoader().load(urls);
textureCube.format = THREE.RGBAFormat;
resolve({
name: envMapMenu[name].name,
data: textureCube,
const textureCube = new THREE.CubeTextureLoader().load(urls, () => {
textureCube.format = THREE.RGBAFormat;
resolve({
name: envMapMenu[name].name,
data: textureCube,
});
});

@@ -133,2 +134,14 @@ });

export async function getEnvMapList () {
const list = [];
list.push(getEnvMapByName("dreamland", process.env.VUE_APP_NAME));
list.push(getEnvMapByName("sky", process.env.VUE_APP_NAME));
list.push(getEnvMapByName("dusk", process.env.VUE_APP_NAME));
return new Promise((resolve) => {
Promise.all(list).then(res => {
resolve(res);
})
});
}
export const SCENE_BACKGROUND_COLOR = 'rgb(68, 68, 68)';

@@ -135,0 +148,0 @@ export const AMBIENT_LIGHT_COLOR = '#c2c2c2';

@@ -0,0 +0,0 @@ import { Cache } from './Cache.js';

@@ -0,0 +0,0 @@ // 对比两个文件内容,同返回 true 异为 false

export * from './diff';
export * from './loader';
export * from './detect';

@@ -59,3 +59,2 @@ import { FBXLoader } from "./FBXLoader";

// TODO: 此处增加判断,如果该文件并非 tga 文件,则判断 Url 后缀是否为 png 或 jpg,如果是,则调用 loadPNGFile
if (type === "tga" && url.endsWith('.tga')) {

@@ -62,0 +61,0 @@ const res = await loadTGAFile(url);

@@ -0,0 +0,0 @@ /* eslint-disable no-fallthrough */

export * from './model';

@@ -61,3 +61,3 @@ import * as THREE from 'star_mod_custom_three';

this.transModelByCoord(assembleModel, trans);
console.log('assembleModel', assembleModel);
return assembleModel;

@@ -335,27 +335,38 @@ }

updateModelMaterialType(channel, type) {
this.model.traverse(async child => {
if (child.material) {
const material = Array.isArray(child.material) ? child.material[channel] : child.material;
if (material.materialType) {
return new Promise((resolve) => {
this.model.traverse(child => {
if (child.material) {
const material = Array.isArray(child.material) ? child.material[channel] : child.material;
if (type === GLASS_MATERIAL_KEY || type === FEMALE_BODY_MATERIAL_KEY || type === MALE_BODY_MATERIAL_KEY) {
material.dispose();
if (Array.isArray(child.material)) {
this.createSpecificMaterial(type).then(res => {
child.material[channel] = res;
child.material[channel].needsUpdate = true;
resolve();
});
} else {
this.createSpecificMaterial(type).then(res => {
child.material = res;
child.material.needsUpdate = true;
resolve();
});
}
} else {
if (material.materialType) {
material.dispose();
}
if (Array.isArray(child.material)) {
child.material[channel] = this.createStandardMaterial();
child.material[channel].needsUpdate = true;
resolve();
} else {
child.material = this.createStandardMaterial();
child.material.needsUpdate = true;
resolve();
}
}
if (type === GLASS_MATERIAL_KEY || type === FEMALE_BODY_MATERIAL_KEY || type === MALE_BODY_MATERIAL_KEY) {
material.dispose();
if (Array.isArray(child.material)) {
child.material[channel] = await this.createSpecificMaterial(type);
child.material[channel].needsUpdate = true;
} else {
child.material = await this.createSpecificMaterial(type);
child.material.needsUpdate = true;
}
}
}
})
});
});
}

@@ -455,3 +466,3 @@

setModelMaterialEnvMap(envMap, renderer) {
setModelMaterialEnvMap(envMap) {
if (!envMap) {

@@ -467,9 +478,5 @@ this.model.traverse(child => {

// TODO: 制空时取消环境贴图
const crt = new THREE.WebGLCubeRenderTarget(envMap.image.height);
crt.fromEquirectangularTexture(renderer, envMap);
const texture = crt.texture;
this.model.traverse(child => {
if (child.material) {
child.material.envMap = texture;
child.material.envMap = envMap;
child.material.envMapIntensity = 1;

@@ -476,0 +483,0 @@ child.material.needsUpdate = true;

@@ -0,0 +0,0 @@ export declare function isMesh(key: string): boolean;

@@ -0,0 +0,0 @@ export function isMesh(key) {

@@ -9,3 +9,3 @@ import * as THREE from 'star_mod_custom_three';

dom: HTMLElement | null;
mode: 'editor' | 'render';
mode: 'edit' | 'preview';
scene: THREE.Scene | null;

@@ -24,17 +24,33 @@ camera: THREE.PerspectiveCamera | THREE.OrthographicCamera | null;

currSelectModel: THREE.Object3D | null;
options: {
mode: string;
platform: string;
width: number;
height: number;
autoResize: boolean;
autoClear: boolean;
isShowModelInfo: boolean;
isShowSelectionBox: boolean;
isShowSceneEnv: boolean;
isNeedScreenshot: boolean;
};
// 渲染器初始化
constructor(options: { mode?: 'editor' | 'render'; dom: HTMLElement; });
constructor(options: { dom: HTMLElement; options: any; });
getCurrMode(mode: 'editor' | 'render'): { isEditor?: boolean; isRender?: boolean; };
getCurrMode(mode: 'edit' | 'preview'): { isEdit?: boolean; isPreview?: boolean; };
initCommonAbility(): void;
initEditorAbility(): void;
initEditAbility(): void;
initRenderer(): void;
initPreviewAbility(): void;
// 相机初始化与控制器
initCamera(): void;
initBaseScene(): void;
changePerspectiveCamera(): void;

@@ -53,2 +69,4 @@

initEditSignal(): void;
changeAmbientLight(options: { color: string; intensity: number; }): void;

@@ -64,3 +82,3 @@

addEditorEventListener(): void;
addEditEventListener(): void;

@@ -125,4 +143,8 @@ getMousePosition(dom: HTMLElement, x: number, y: number): [number, number];

setPreviewData(previewData: any): void;
update(): void;
customUpdate(): void;
getRenderDom(): HTMLElement;

@@ -135,19 +157,29 @@

export declare class Render extends RenderBase {
generateCurrFrameFlag: boolean;
currFrame: HTMLImageElement | null;
modelRender: ModelProcessor | null;
mainModels: any[];
modelsLoader: any[];
auxiliaryModels: any;
previewData: any;
animations: any[];
constructor(options: { container: HTMLElement | null; platform: string; isShowScene: boolean; });
constructor(options: { dom: HTMLElement; options: any; });
setRenderModel(model: Model): void;
initSceneEnv(): void;
handleRenderModelInfo(): void;
initRenderSign(): void;
setRenderPreviewData(previewData: any): void;
setMainModel(any): void;
customUpdate(): void;
setCombinationModels(any): void;
getCurrFrame(): Promise<HTMLImageElement>;
setFashionAnimations(any): void;
getAllEnvMap(any): void;
start(): void;
getCurrPreviewStoreData(): any;
getCurrFrame(): any;
static drawTgaCanvas(url: string): Promise<HTMLImageElement>;
}
export * from './render.js';
export * from './render.base.js';
export * from './default.js';
{
"name": "star_mod_renderer",
"version": "1.0.39",
"version": "1.0.40",
"description": "star mod project render auxiliary ",

@@ -5,0 +5,0 @@ "main": "index.js",

@@ -0,1 +1,70 @@

/**
渲染器基类,提供 Render 的基础能力,根据不同模式选择启用不同的功能
constructor 接受参数:
- dom: 承载 canvas 的节点,如果没有将会在执行阶段自行创建
- options: 渲染器配置项
- mode: 渲染模式,可选值为 'preview' 和 'edit', 默认为 'preview'
- platform 渲染器运行的平台,可选值为 'pc' 和 'mobile', 默认为 'pc'
- width: 渲染器宽度,如果传入了 dom 参数,将会自动获取 dom 的宽度,否则默认为 300
- height: 渲染器高度,如果传入了 dom 参数,将会自动获取 dom 的高度,否则默认为 150
- autoResize: 是否自动调整渲染器大小,如果为 true,将会监听 dom 的 resize 事件,自动调整渲染器大小
- autoClear: 是否自动清除渲染器内容,如果为 true,将会在页面休眠时自动清楚内存中的渲染器内容,请注意在页面重新激活后重新渲染
- isShowModelInfo: 是否显示模型信息,如果为 true,将会在向场景中添加模型时显示对应的模型信息,如有多个模型将合并计算
initCommonAbility 方法提供了渲染器的基础能力,包括:
initRenderer 初始化渲染器
initCamera 初始化相机
initScene 初始化场景
initLight 初始化灯光
initSign 初始化事件标记
- renderError 渲染错误事件
addCommonEventListener 添加渲染器的基础事件监听
- dom resize 事件
- 页面休眠事件,如果 autoClear 为 true,将会在页面休眠时自动清除渲染器内容
initEditAbility 方法提供了渲染器编辑模式的能力,包括:
initEditCamera 初始化编辑模式下的相机
initSelectionBox 初始化选中辅助器
initViewHelper 初始化视角辅助器
initTransformControls 初始化变换控制器
initEditSign 初始化编辑模式下的事件标记
- selected 选中事件
- removeCurrSelectObject 移除当前选中的对象
- updateSelectModelParam 更新选中模型的参数
addEditEventListener 添加编辑模式下的事件监听
- keydown: delete 删除选中模型
- dblclick: focus
- mousedown: 移动相机,滚轮放大
- touchstart: 移动相机,双指放大
initPreviewAbility 方法提供了渲染器预览模式的能力,包括:
customUpdate 自定义更新方法,用于在渲染循环中执行自定义的更新操作
initAnimation 初始化动画与骨骼信息
getCurrMode 获取当前渲染器的模式
getCurrPlatform 获取当前渲染器的平台
changePerspectiveCamera 修改相机为透视相机
changeOrthographicCamera 修改相机为正交相机
addModel 向场景中添加模型
- model: 模型对象
- options: 模型配置项
- name: 模型名称
- id: 模型 id
- modelRank: 'main', 'support', 'combination' 主体模型,辅助支撑模型,组合展示模型
- skeleton: 可以在添加模型时可以指定骨骼
- animations: 可以在添加模型时指定动画, 添加的动画,将保留和模型的索引关系
- [
{
name: '动画名称',
animation: THREE.AnimationClip
models: [] // 指定动画对应的模型,如果不指定,将会默认为所有模型
}
]
removeModel 从场景中移除模型, 同时释放所有资源与内存
clear: 场景销毁与内存清空, 移除所有模型,释放所有变量,取消事件注册,移除 dom 节点
*/
import * as THREE from "star_mod_custom_three";

@@ -12,7 +81,12 @@ import { Signal } from "./assets/signals.min.js";

AMBIENT_LIGHT_INTENSITY,
RENDER_MODE_PREVIEW,
RENDER_PLATFORM_PC,
} from "./default.js";
import {
getMode,
getDom
} from "./helper/renderHelper/base.helper.js"
export class RenderBase {
dom = null;
mode = "editor";
mode = null;
scene = null;

@@ -28,33 +102,37 @@ camera = null;

currSelectModel = null;
options = {
mode: RENDER_MODE_PREVIEW,
platform: RENDER_PLATFORM_PC,
width: 300,
height: 150,
autoResize: true,
autoClear: true,
isShowModelInfo: true,
isShowSelectionBox: false,
isShowSceneEnv: true, // 展示背景
isNeedScreenshot: false,
};
// 渲染器初始化
constructor({ mode = "editor", dom }) {
this.mode = this.getCurrMode(mode);
this.dom = dom;
// TODO: HACK 解决重复注入元素问题,原因待查
if (this.dom && this.dom.children && this.dom.children.length > 0) {
// 对容器进行清空
this.dom.innerHTML = "";
constructor({ dom, options }) {
if (options) {
this.options = {
...this.options,
...options,
}
}
if (dom) {
this.dom = dom;
}
this.mode = getMode(this.options.mode);
this.dom = getDom(this.dom);
this.initCommonAbility();
this.initEditorAbility();
this.setAnimationLoop(() => {
this.update();
});
this.mode.isEdit && this.initEditAbility();
this.mode.isPreview && this.initPreviewAbility();
}
getCurrMode(mode) {
if (mode === "editor") {
return {
isEditor: true,
};
}
if (mode === "render") {
return {
isRender: true,
};
}
}
initCommonAbility() {

@@ -66,4 +144,3 @@ // 渲染器初始化

// 场景初始化
this.scene = new THREE.Scene();
this.scene.background = new THREE.Color(SCENE_BACKGROUND_COLOR);
this.initBaseScene();
// 灯光初始化

@@ -77,4 +154,18 @@ this.initLights();

initEditorAbility() {
if (!this.mode.isEditor) {
initRenderer() {
this.renderer = new THREE.WebGLRenderer({
antialias: true,
});
if (this.dom) {
this.dom.append(this.renderer.domElement);
} else {
this.dom = document.createElement("div");
this.dom.style = "position: relative;";
this.dom.append(this.renderer.domElement);
}
}
initEditAbility() {
if (!this.mode.isEdit) {
return;

@@ -95,19 +186,19 @@ }

this.initTransformControls();
// 编辑类事件注册
this.addEditorEventListener();
// 编辑状态事件注册
this.initEditSign();
// 编辑类事件监听
this.addEditEventListener();
}
initRenderer() {
this.renderer = new THREE.WebGLRenderer({
antialias: true,
});
// TODO: 这里有点问题,之后再改
if (this.dom) {
this.dom.append(this.renderer.domElement);
} else {
this.dom = document.createElement("div");
this.dom.style = "position: relative;";
this.dom.append(this.renderer.domElement);
// TODO: 抛出预览时事件( 鼠标按下与抬起,监控 renderDom 不要监控 dom )
initPreviewAbility() {
if (!this.mode.isPreview) {
return;
}
if (this.options.isNeedScreenshot) {
this.setAnimationLoop(() => {
this.customUpdate();
});
}
// this.initAnimation();
}

@@ -120,74 +211,7 @@

changePerspectiveCamera() {
this.camera = new THREE.PerspectiveCamera(
45,
this.dom.offsetWidth / this.dom.offsetHeight,
0.1,
10000
);
if (this.cameraControls) {
this.cameraControls.dispose();
}
this.cameraControls = new EditorControls(this.camera, this.dom);
this.camera.zoom = 1;
this.viewHelper = new ViewHelper(this.camera, this.dom);
this.viewHelper.controls = this.cameraControls;
this.setSize();
initBaseScene() {
this.scene = new THREE.Scene();
this.scene.background = new THREE.Color(SCENE_BACKGROUND_COLOR);
}
changeOrthographicCamera() {
this.camera = new THREE.OrthographicCamera(
-this.dom.offsetWidth,
this.dom.offsetWidth,
this.dom.offsetHeight,
-this.dom.offsetHeight,
1,
100000
);
if (this.cameraControls) {
this.cameraControls.dispose();
}
this.cameraControls = new EditorControls(
this.camera,
this.dom,
"orthographic"
);
this.camera.zoom = 10;
this.viewHelper = new ViewHelper(this.camera, this.dom);
this.viewHelper.controls = this.cameraControls;
this.setSize();
}
initSignal() {
this.signals = {
selected: new Signal(),
removeCurrSelectObject: new Signal(),
updateSelectModelParam: new Signal(),
renderError: new Signal(),
};
}
initViewHelper() {
this.viewHelper = new ViewHelper(this.camera, this.dom);
this.viewHelper.controls = this.cameraControls;
const dom = document.createElement("div");
dom.style.position = "absolute";
dom.style.right = "0px";
dom.style.bottom = "0px";
dom.style.height = "128px";
dom.style.width = "128px";
this.dom.append(dom);
}
setSceneEnvironment(environment) {
if (environment) {
this.scene.background = environment;
this.scene.environment = environment;
} else {
this.scene.background = new THREE.Color(SCENE_BACKGROUND_COLOR);
this.scene.environment = null;
}
this.update();
}
// 灯光初始化与设定

@@ -226,42 +250,70 @@ initLights() {

changeAmbientLight({ color, intensity }) {
if (color) {
this.ambientLight.color.set(color);
this.hemisphereLight.color.set(color);
this.hemisphereLight.groundColor.set(color);
initSelectionBox() {
if (this.options.isShowSelectionBox) {
this.box = new THREE.Box3();
this.selectionBox = new THREE.Box3Helper(this.box);
this.selectionBox.material.depthTest = false;
this.selectionBox.material.transparent = true;
this.scene.add(this.selectionBox);
}
}
if (intensity) {
this.ambientLight.intensity = intensity;
this.hemisphereLight.intensity = intensity;
}
initViewHelper() {
this.viewHelper = new ViewHelper(this.camera, this.dom);
this.viewHelper.controls = this.cameraControls;
const dom = document.createElement("div");
dom.style.position = "absolute";
dom.style.right = "0px";
dom.style.bottom = "0px";
dom.style.height = "128px";
dom.style.width = "128px";
this.dom.append(dom);
}
changeDirectionalLights(light) {
if (light.color) {
this.directionalLights.forEach((item) => {
item.color.set(light.color);
});
}
// 物体变换器加载
initTransformControls() {
this.transformControls = new TransformControls(this.camera, this.dom);
this.changeTransformControls("translate");
if (light.intensity) {
this.directionalLights.forEach((item) => {
item.intensity = light.intensity;
});
}
this.transformControls.addEventListener(
"change",
this.onTransformControlsChange.bind(this)
);
this.transformControls.addEventListener(
"mouseDown",
this.onTransformControlsMouseDown.bind(this)
);
this.transformControls.addEventListener(
"mouseUp",
this.onTransformControlsMouseUp.bind(this)
);
this.scene.add(this.transformControls);
}
setDirectionLightsPosition(light) {
this.directionalLights[light.index].position.set(light.position);
// TODO: 补充动画
initAnimation() {
}
initSelectionBox() {
this.box = new THREE.Box3();
this.selectionBox = new THREE.Box3Helper(this.box);
this.selectionBox.material.depthTest = false;
this.selectionBox.material.transparent = true;
this.selectionBox.visible = false;
this.scene.add(this.selectionBox);
// TODO: 页面与元素显隐
initSignal() {
this.signals = {
renderError: new Signal(),
renderHidden: new Signal(),
renderShow: new Signal(),
};
}
initEditSign() {
this.signals = {
...this.signals,
selected: new Signal(),
removeCurrSelectObject: new Signal(),
updateSelectModelParam: new Signal(),
}
}
addCommonEventListener() {

@@ -273,6 +325,6 @@ // resize

});
// TODO: 隐藏、关闭与显示
}
// TODO: 编辑器注销后,事件没有移除
addEditorEventListener() {
addEditEventListener() {
// delete

@@ -286,3 +338,3 @@ window.addEventListener("keydown", (event) => {

// 单击
// 单击选中
this.dom.addEventListener("mousedown", (event) => {

@@ -298,2 +350,3 @@ const array = this.getMousePosition(

});
this.dom.addEventListener("touchstart", (event) => {

@@ -332,23 +385,26 @@ const touch = event.changedTouches[0];

getMousePosition(dom, x, y) {
if (dom) {
const rect = dom.getBoundingClientRect();
return [(x - rect.left) / rect.width, (y - rect.top) / rect.height];
// 变形控制器监听
onTransformControlsChange() {
const object = this.transformControls.object;
if (object) {
this.box.setFromObject(object, true);
// 球体可以根据该事件对数值进行调整
this.signals.updateSelectModelParam.dispatch({
model: object,
axis: this.transformControls.axis,
mode: this.transformControls.getMode(),
});
}
this.update();
}
getIntersects(point) {
this.mouse.set(point.x * 2 - 1, -(point.y * 2) + 1);
onTransformControlsMouseDown() {
this.cameraControls.enabled = false;
}
this.raycaster.setFromCamera(this.mouse, this.camera);
const objects = [];
this.scene.traverseVisible(function (child) {
objects.push(child);
});
return this.raycaster.intersectObjects(objects, false);
onTransformControlsMouseUp() {
this.cameraControls.enabled = true;
}
// 鼠标事件
onMouseUp(event) {

@@ -395,68 +451,110 @@ if (this.dom) {

// 模型添加能力
addModel(model) {
this.scene.add(model);
// 获取各类属性
getRenderDom() {
return this.renderer.domElement;
}
getCurrSelectModel() {
return this.currSelectModel;
}
// 默认执行选中逻辑
this.selectModel(model);
getMousePosition(dom, x, y) {
if (dom) {
const rect = dom.getBoundingClientRect();
return [(x - rect.left) / rect.width, (y - rect.top) / rect.height];
}
}
// 模型删除能力与内存释放
removeModel(model) {
// 移除模型
model.parent && model.parent.remove(model);
getIntersects(point) {
this.mouse.set(point.x * 2 - 1, -(point.y * 2) + 1);
// TODO: 移除材质
if (model.children) {
model.traverse((child) => {
if (child.geometry) {
child.geometry.dispose();
}
if (child.material && !Array.isArray(child.material)) {
child.material.dispose();
}
});
this.raycaster.setFromCamera(this.mouse, this.camera);
const objects = [];
this.scene.traverseVisible(function (child) {
objects.push(child);
});
return this.raycaster.intersectObjects(objects, false);
}
// 设置各类内容
setSize(width, height) {
if (!this.dom) {
return;
}
if (width && height) {
this.dom.width = width;
this.dom.height = height;
}
let assembleWidth = 0;
if (this.dom.style.width) {
assembleWidth = width || parseFloat(this.dom.style.width);
} else {
if (model.geometry) {
model.geometry.dispose();
}
assembleWidth = width || this.dom.offsetWidth;
}
// 取消选中
this.selectModel(null);
let assembleHeight = 0;
if (this.dom.style.height) {
assembleHeight = height || parseFloat(this.dom.style.height);
} else {
assembleHeight = height || this.dom.offsetHeight;
}
this.updateAspectRatio(assembleWidth, assembleHeight);
// 这里本身做了防抖
this.renderer.setSize(assembleWidth, assembleHeight);
this.renderer.setViewport(0, 0, assembleWidth, assembleHeight);
}
// 物体变换器加载
initTransformControls() {
this.transformControls = new TransformControls(this.camera, this.dom);
this.changeTransformControls("translate");
// TODO: 设置相机动画
setPreviewData(previewData) {
if (previewData.cameraPosition) {
this.camera.position.set(
previewData.cameraPosition.x,
previewData.cameraPosition.y,
previewData.cameraPosition.z
);
}
this.transformControls.addEventListener(
"change",
this.onTransformControlsChange.bind(this)
);
if (previewData.previewCenter) {
this.camera.lookAt(previewData.previewCenter);
}
this.transformControls.addEventListener(
"mouseDown",
this.onTransformControlsMouseDown.bind(this)
);
if (previewData.ambientLight) {
this.changeAmbientLight({
color: previewData.ambientLight.color,
intensity: previewData.ambientLight.intensity,
});
}
this.transformControls.addEventListener(
"mouseUp",
this.onTransformControlsMouseUp.bind(this)
);
if (previewData.directionalLight) {
this.changeDirectionalLights({
color: previewData.directionalLight[0].color,
intensity: previewData.directionalLight[0].intensity,
});
}
}
this.scene.add(this.transformControls);
// 暂停与播放
setAnimationLoop(callback) {
if (this.renderer) {
this.renderer.setAnimationLoop(callback);
}
}
onTransformControlsChange() {
const object = this.transformControls.object;
if (object) {
this.box.setFromObject(object, true);
// 球体可以根据该事件对数值进行调整
this.signals.updateSelectModelParam.dispatch({
model: object,
axis: this.transformControls.axis,
mode: this.transformControls.getMode(),
});
setDirectionLightsPosition(light) {
this.directionalLights[light.index].position.set(light.position);
}
setSceneEnvironment(environment) {
if (environment) {
this.scene.background = environment;
this.scene.environment = environment;
} else {
this.scene.background = new THREE.Color(SCENE_BACKGROUND_COLOR);
this.scene.environment = null;
}

@@ -466,10 +564,110 @@ this.update();

onTransformControlsMouseDown() {
this.cameraControls.enabled = false;
// 创建各类变量
// 创建网格
createGrid(size, divisions, color) {
const grid = new THREE.GridHelper(size, divisions, color);
grid.isGrid = true;
grid.material.color.setHex(color);
grid.material.vertexColors = false;
grid.visible = false;
grid.traverse((child) => {
child.visible = false;
});
this.grids.push(grid);
this.addModel(grid);
}
onTransformControlsMouseUp() {
this.cameraControls.enabled = true;
changeGirdVisible() {
this.grids.forEach((item) => {
item.visible = !item.visible;
});
this.update();
}
// 这里扩展三种模式
changeTransformControls(mode) {
// 切换转换器模式
this.transformControls.setMode(mode);
}
changeAmbientLight({ color, intensity }) {
if (color) {
this.ambientLight.color.set(color);
this.hemisphereLight.color.set(color);
this.hemisphereLight.groundColor.set(color);
}
if (intensity) {
this.ambientLight.intensity = intensity;
this.hemisphereLight.intensity = intensity;
}
}
changeDirectionalLights(light) {
if (light.color) {
this.directionalLights.forEach((item) => {
item.color.set(light.color);
});
}
if (light.intensity) {
this.directionalLights.forEach((item) => {
item.intensity = light.intensity;
});
}
}
// 创建透视相机
changePerspectiveCamera() {
this.camera = new THREE.PerspectiveCamera(
45,
this.dom.offsetWidth / this.dom.offsetHeight,
0.1,
10000
);
if (this.cameraControls) {
this.cameraControls.dispose();
}
this.cameraControls = new EditorControls(this.camera, this.dom);
this.camera.zoom = 1;
if (this.mode.isEdit) {
this.viewHelper = new ViewHelper(this.camera, this.dom);
this.viewHelper.controls = this.cameraControls;
}
this.setSize();
}
// 创建正交相机 TODO: 正交相机 focus
changeOrthographicCamera() {
this.camera = new THREE.OrthographicCamera(
-this.dom.offsetWidth,
this.dom.offsetWidth,
this.dom.offsetHeight,
-this.dom.offsetHeight,
1,
100000
);
if (this.cameraControls) {
this.cameraControls.dispose();
}
this.cameraControls = new EditorControls(
this.camera,
this.dom,
"orthographic"
);
this.camera.zoom = 10;
if (this.mode.isEdit) {
this.viewHelper = new ViewHelper(this.camera, this.dom);
this.viewHelper.controls = this.cameraControls;
}
this.setSize();
}
// resize 能力
updateAspectRatio(width, height) {
this.camera.aspect = width / height;
this.camera.updateProjectionMatrix();
}
removeTransformControls() {

@@ -500,8 +698,2 @@ this.scene.remove(this.transformControls);

// 这里扩展三种模式
changeTransformControls(mode) {
// 切换转换器模式
this.transformControls.setMode(mode);
}
intersectionsDetected(intersects) {

@@ -547,7 +739,2 @@ if (intersects.length > 0) {

// 模型数据纰漏能力
getCurrSelectModel() {
return this.currSelectModel;
}
// 双击居中能力

@@ -567,52 +754,37 @@ focusModel(target) {

// 创建网格
createGrid(size, divisions, color) {
const grid = new THREE.GridHelper(size, divisions, color);
grid.isGrid = true;
grid.material.color.setHex(color);
grid.material.vertexColors = false;
grid.visible = false;
grid.traverse((child) => {
child.visible = false;
});
// 模型添加能力
addModel(model, options) {
if (options) {
// TODO: 根据 options.modelRank 类别计算展示面数
}
this.scene.add(model);
this.grids.push(grid);
this.addModel(grid);
// 默认执行选中逻辑
this.selectModel(model);
}
changeGirdVisible() {
this.grids.forEach((item) => {
item.visible = !item.visible;
});
this.update();
}
// 模型删除能力与内存释放
removeModel(model) {
// 移除模型
model.parent && model.parent.remove(model);
// resize 能力
updateAspectRatio(width, height) {
this.camera.aspect = width / height;
this.camera.updateProjectionMatrix();
}
setSize(width, height) {
if (!this.dom) {
return;
if (model.children) {
model.traverse((child) => {
if (child.geometry) {
child.geometry.dispose();
}
if (child.material && !Array.isArray(child.material)) {
child.material.dispose();
}
});
} else {
if (model.geometry) {
model.geometry.dispose();
}
}
if (width && height) {
this.dom.width = width;
this.dom.height = height;
}
const assembleWidth = width || this.dom.offsetWidth;
const assembleHeight = height || this.dom.offsetHeight;
this.updateAspectRatio(assembleWidth, assembleHeight);
this.renderer.setSize(assembleWidth, assembleHeight);
this.renderer.setViewport(0, 0, assembleWidth, assembleHeight);
// 取消选中
this.selectModel(null);
}
// 暂停与播放
setAnimationLoop(callback) {
this.renderer.setAnimationLoop(callback);
}
update() {

@@ -634,24 +806,32 @@ if (this.renderer) {

getRenderDom() {
return this.renderer.domElement;
// preview 模式特供 update 用于截取当前帧数据
customUpdate() {
if (this.renderer) {
this.update();
if (this.mixer !== null) {
// this.mixer.update(this.clock.getDelta());
}
if (this.generateCurrFrameFlag) {
const img = new Image();
let imgData = this.renderer.domElement.toDataURL("image/jpeg");
img.src = imgData;
this.currFrame = img;
this.generateCurrFrameFlag = false;
}
}
}
// 场景销毁与内存清空
clear() {
// 删除所有模型与相关内存
this.scene.children.forEach((item) => {
this.removeModel(item);
});
this.renderer.dispose();
this.camera = null;
this.scene = null;
this.renderer = null;
this.viewHelper = null;
this.dom = null;
this.cameraControls = null;
this.transformControls = null;
this.ambientLight = null;
this.directionalLights = [];
this.signals = null;
this.currSelectModel = null;
this.scene.background = new THREE.Color(SCENE_BACKGROUND_COLOR);
this.scene.environment = null;
this.dom.innerHTML = "";
// 移除并清空 dom
// 注销 render
}
}

@@ -1,285 +0,296 @@

import * as THREE from "star_mod_custom_three";
/**
渲染器 preview 模式应用
实例化时可配置所选项 --> 在 renderAuxiliary 中写定
根据需求选择使用那种资源添加方式
setMainModel / setCombinationModels / setFashionAnimations
在执行 start 之后通过 render.helper.js 中的 ChannelMaterialAuxiliary 对通道中的纹理文件进行加载
根据不同的模式激活是否完成加载选项
在对外抛出加载完成前,根据配置选择是否展示 model info, 并提供显隐开关
所有辅助性资源:
1. 地板
2. 头发
3. 头
4. 身体
constructor
- dom
- options
- mode: 固定为 preview
- platform: pc | mobile
- width
- height
- autoResize
- autoClear
- isShowModelInfo
setMainModel / setCombinationModels / setFashionAnimations
- setMainModel
- fbx
- channelMaterial
- auxiliaryType
- setCombinationModels
- models
- fbx
- channelMaterial
- auxiliaryType
- animations 直接获取?
- setFashionAnimations
- animations
- auxiliaryType
start
sign
- loadCompleted 所有资源加载完成可以渲染内容
- 开始展示,并添加 model info
initAnimations 在加载完成后,如果存在动画选项的话
playAnimations
stopAnimations
initAuxiliaryModels 查找辅助模型并一同添加, 保留索引以切换显隐
tga 文件渲染
*/
// import * as THREE from "star_mod_custom_three";
import TgaLoader from "tga-js";
import { RenderBase } from "./render.base";
import {
getEnvMapList,
getEnvMapByName,
defaultModel,
defaultModelAnimation,
FEMALE_HAIR_KEY,
MALE_HAIR_KEY,
FEMALE_HEAD_MATERIAL_KEY,
MALE_HEAD_MATERIAL_KEY,
// defaultModel,
// defaultModelAnimation,
// FEMALE_HAIR_KEY,
// MALE_HAIR_KEY,
// FEMALE_HEAD_MATERIAL_KEY,
// MALE_HEAD_MATERIAL_KEY,
RENDER_MODE_PREVIEW
} from "./default";
import { ModelProcessor } from "./helper/modelHelper/index";
import { calculateVerticesAndFace } from "./helper/calculate";
import { loadFile } from "./helper/filesHelper";
// import { calculateVerticesAndFace } from "./helper/calculate";
// import { loadFile } from "./helper/filesHelper";
import {
MainModelAuxiliary, // 主模型辅助类
channelMaterialParams,
ChannelMaterialAuxiliary, // 材质通道辅助类
} from "./helper/renderHelper/render.helper";
import {
PreviewDataHelper,
} from "@/renderer/render/helper/parameterHelper";
import {
getModelMaterialChannelLength,
} from "@/renderer/render/helper/parser";
export class Render extends RenderBase {
generateCurrFrameFlag = false;
currFrame = null;
modelRender = null;
modelRenderList = [];
combinationModelGroup = null;
clock = new THREE.Clock();
mixer = null;
mainModels = []; // 所有模型
modelsLoader = []; // 请求列表,在 start 时同时执行所有请求内容
/**
* 所有可能存在的组合:
* 上传单个男/女性头发: 增加男/女头部模型,增加默认男/女性身体,添加男/女性默认动画, 添加地板
* 上传单个男/女性身体: 增加男/女头部模型,增加默认男/女性头发,添加男/女性默认动画,添加地板
* 上传组合男/女时装: 增加男/女头部模型,添加男/女性默认动画,添加地板
* 上传单个普通单品: 增加地板
* 上传个性动画: 增加男/女头部模型,增加默认男/女性头发,增加默认男/女性身体,添加男/女性默认动画, 添加地板
*/
auxiliaryModels = {
floor: null, // 地板
maleHair: null, // 男性时装头发
maleHeader: null, // 男性头部
maleBody: null, // 男性时装身体
femaleHair: null, // 女性时装头发
femaleHeader: null, // 女性头部
femaleBody: null, // 女性时装身体
};
previewData = null; // 预览数据
animations = []; // 所有动画: 从配置中请求获取:
constructor(
{ container, platform, isShowScene } = {
container: null,
platform: "pc",
isShowScene: true,
}
) {
super({ mode: "render", dom: container });
this.setAnimationLoop(() => {
this.customUpdate();
});
let processEnv = "domestic";
try {
if (platform === "pc") {
processEnv = process.env.VUE_APP_NAME;
} else if (platform === "mobile") {
processEnv = import.meta.env.VITE_APP_NAME;
}
} catch (e) {
console.error(e);
processEnv = "domestic";
}
if (isShowScene) {
getEnvMapByName("sky", processEnv).then((env) => {
this.setSceneEnvironment(env.data);
});
}
}
constructor({dom, options}) {
super({dom, options: {
...options,
mode: RENDER_MODE_PREVIEW
} });
setRenderModel(model, isShowModelInfo = true) {
// 计算设置模型
const modelRender = new ModelProcessor(model);
// 将模型添加到场景
this.addModel(modelRender.getModel());
this.focusModel(modelRender.getModel());
// 旋转相机角度
// 设置灯光参数
const size = modelRender.getModelSize();
// temp
const max = Math.max(size.x, size.y, size.z);
const min = Math.min(size.x, size.y, size.z);
if (max > 400) {
this.signals.renderError.dispatch();
}
if (min < 10) {
this.signals.renderError.dispatch();
}
this.directionalLights[0].position.set(max * 2, max * 2, max * 2);
this.directionalLights[1].position.set(max * -2, max * -2, max * -2);
this.directionalLights[2].position.set(0, max * -2, max * 2);
this.modelRender = modelRender;
if (isShowModelInfo) {
this.handleRenderModelInfo();
}
this.initRenderSign();
}
setCombinationRenderModel(list) {
const group = new THREE.Group();
const modelRenderList = [];
list.forEach((model) => {
const modelRender = new ModelProcessor(model);
group.add(modelRender.getModel());
modelRenderList.push(modelRender);
});
this.combinationModelGroup = group;
this.addModel(group);
this.focusModel(group);
this.modelRenderList = modelRenderList;
}
async setAuxiliaryModel(key) {
if (key === MALE_HAIR_KEY) {
this.maleHeadModel = await this.createMaleHeadModel();
initSceneEnv() {
if (this.options.isShowSceneEnv) {
// 根据 platform 加载默认天空盒
}
// 女头
if (key === FEMALE_HAIR_KEY) {
this.femaleHeadModel = await this.createFemaleHeadModel();
}
}
async createMaleHeadModel() {
const meshUrl = defaultModel[MALE_HAIR_KEY].fbx.domesticPath;
const mesh = await loadFile({
url: meshUrl,
type: "fbx",
});
const modelRender = new ModelProcessor(mesh);
modelRender.createSpecificMaterial(MALE_HEAD_MATERIAL_KEY);
this.maleHeadModel = modelRender.getModel();
this.maleHeadModel.visible = true;
this.addModel(this.maleHeadModel);
return this.maleHeadModel;
}
initRenderSign() {
changeMaleHeadModelVisible() {
this.maleHeadModel.visible = !this.maleHeadModel.visible;
}
async createFemaleHeadModel() {
const meshUrl = defaultModel[FEMALE_HAIR_KEY].fbx.domesticPath;
const mesh = await loadFile({
url: meshUrl,
type: "fbx",
});
const modelRender = new ModelProcessor(mesh);
/**
* 1. 模型需要主动传入,因为有加密和非加密的情况,需要在外面获取后加载后传入
* 2. previewData 直接传入可以在 render 内转换
* 3. auxiliaryType 传入后获取对应辅助模型
* 4. 纹理文件整理后按照 store 的形式传入加载
* 5. 辅助模型与纹理文件加载完成之后
*/
async setMainModel({
mainModel,
mainModelLocalCache,
mainModelData,
mainMaterialMap,
extraMaterialList,
// goodSecondaryClassification,
// fashionConfig,
previewData,
}) {
// mainModelHelper
const mainModelAuxiliary = new MainModelAuxiliary(
mainModel,
mainModelLocalCache,
mainModelData
);
const modelOriginalData = await mainModelAuxiliary.loadModel();
const modelRender = new ModelProcessor(modelOriginalData);
// channelMaterialHelper
const channelMaterialAuxiliary = new ChannelMaterialAuxiliary([]);
modelRender.createSpecificMaterial(FEMALE_HEAD_MATERIAL_KEY);
this.femaleHeadModel = modelRender.getModel();
this.femaleHeadModel.visible = true;
this.addModel(this.femaleHeadModel);
return this.femaleHeadModel;
}
// 所有通道纹理全部加载完成并设置对应材质后返回成功
const loadModelChannelTexture = (model) => {
return new Promise((resolve) => {
mainModelAuxiliary.setMainModelData(model);
this.mainModels.push(modelRender);
changeFemaleHeadModelVisible() {
this.femaleHeadModel.visible = !this.femaleHeadModel.visible;
}
const channelTextureLoadSuccess = (textureList) => {
const loaderList = [];
return new Promise((resolve) => {
// 更新模型材质类型
for (let index = 0; index < channelMaterialAuxiliary.channelMaterialParamsList.length; index++) {
const item = channelMaterialAuxiliary.channelMaterialParamsList[index];
loaderList.push(modelRender.updateModelMaterialType(index, item.materialType));
}
Promise.all(loaderList).then((res) => {
for(let i = 0; i < textureList.length; i++) {
const texture = textureList[i];
for (let j = 0; j < texture.length; j++) {
const { index, key, res } = texture[j];
channelMaterialAuxiliary.setChannelItemTextureData(index, key, res);
// 更新材质与材质列表
modelRender.updateModelMaterialParam(index, channelMaterialAuxiliary.getChannelItem(index));
modelRender.updateModelMaterialTexture(index, channelMaterialAuxiliary.getChannelItemTextureData(index));
}
}
resolve(res);
});
});
};
stopPlayAnimation() {
this.animationAction.stop();
}
channelMaterialAuxiliary.initChannelMaterialParamsList(
getModelMaterialChannelLength(model),
channelMaterialParams,
);
setAnimationList(list) {
const bones =
this.combinationModelGroup.children[1].children[0].clone(true);
if (this.combinationModelGroup.children[0].children[0].type === "Bone") {
this.combinationModelGroup.children[0].add(bones);
}
this.animations = list;
}
channelMaterialAuxiliary.setMaterialParamsList(mainMaterialMap, extraMaterialList).then(res => {
channelTextureLoadSuccess(res).then(() => {
resolve()
});
});
});
};
playAnimation(index) {
const flock = new THREE.AnimationObjectGroup(
this.combinationModelGroup.children[0],
this.maleHeadModel,
this.combinationModelGroup.children[1]
// 调用 start 时开始同时加载所有内容
this.modelsLoader.push(
loadModelChannelTexture(modelOriginalData)
);
this.mixer = new THREE.AnimationMixer(flock);
this.animationAction = this.mixer.clipAction(this.animations[index]);
this.animationAction.play();
}
// TODO: 补充动画播放
async playDefaultAnimation(key) {
if (defaultModelAnimation[key]) {
const url = defaultModelAnimation[key].dancing.domesticPath;
const file = await loadFile({
url,
type: "fbx",
// 设置预览数据并请求天空盒资源
const previewHelper = new PreviewDataHelper();
this.previewData = previewHelper.transPreviewDataToRender(previewData);
const getCurrEnvMap = () => {
const envMap = this.previewData.envMap || 'sky';
return new Promise((resolve) => {
getEnvMapByName(envMap, process.env.VUE_APP_NAME).then((environment) => {
if (environment) {
this.setSceneEnvironment(environment.data);
modelRender.setModelMaterialEnvMap(environment.data);
}
resolve();
});
});
const modelRender = new ModelProcessor(file);
const bones =
this.combinationModelGroup.children[1].children[0].clone(true);
if (this.combinationModelGroup.children[0].children[0].type === "Bone") {
this.combinationModelGroup.children[0].add(bones);
}
const flock = new THREE.AnimationObjectGroup(
this.combinationModelGroup.children[0],
this.maleHeadModel,
this.combinationModelGroup.children[1]
);
this.mixer = new THREE.AnimationMixer(flock);
this.animationAction = this.mixer.clipAction(
modelRender.getModel().animations[0]
);
}
this.modelsLoader.push(
getCurrEnvMap()
);
this.animationAction.play();
}
// 根据 goodSecondaryClassification 与 fashionConfig 请求对应辅助模型的数据
}
handleRenderModelInfo() {
const mainObject = this.modelRender;
const { faces, vertices } = calculateVerticesAndFace(mainObject.model);
const size = mainObject.getModelSize();
const div = document.createElement("div");
div.innerHTML = `
vertices: ${vertices}<br>
triangles: ${faces}<br>
size: ${parseInt(size.x)}cm * ${parseInt(size.y)}cm * ${parseInt(
size.z
)}cm
`;
div.style.position = "absolute";
div.style.bottom = "6px";
div.style.left = "6px";
div.style.color = "#fff";
div.style.fontSize = "12px";
div.style.zIndex = "100";
div.style.transform = "scale(0.8)";
div.style.transformOrigin = "left bottom";
div.style.textAlign = "left";
setCombinationModels() {
this.dom.appendChild(div);
}
setRenderPreviewData(previewData) {
if (previewData.cameraPosition) {
this.camera.position.set(
previewData.cameraPosition.x,
previewData.cameraPosition.y,
previewData.cameraPosition.z
);
}
setFashionAnimations() {
if (previewData.previewCenter) {
this.camera.lookAt(previewData.previewCenter);
}
}
if (previewData.ambientLight) {
this.changeAmbientLight({
color: previewData.ambientLight.color,
intensity: previewData.ambientLight.intensity,
// 加载完成后可以请求其它的天空盒资源
getAllEnvMap() {
return new Promise((resolve) => {
getEnvMapList().then((envMapList) => {
resolve(envMapList);
});
}
});
}
if (previewData.directionalLight) {
this.changeDirectionalLights({
color: previewData.directionalLight[0].color,
intensity: previewData.directionalLight[0].intensity,
start() {
return new Promise((resolve) => {
// promise 方法,监听所有资源已经加载完成,可以渲染,将所有物品添加到场景当中,执行相机动画,外面可以在 await start 之后切换加载动画的显隐
Promise.all(this.modelsLoader).then(() => {
// 将所有模型添加到场景当中
this.mainModels.forEach((modelRender) => {
const model = modelRender.getModel();
this.addModel(model);
// 如果有 preview 的话就根据 previewData 执行相机动画,如果没有的话直接 focusModel
this.focusModel(model);
});
this.setPreviewData(this.previewData);
resolve();
});
}
});
if (previewData.envMap) {
this.setSceneEnvironment(previewData.envMap.data);
}
}
customUpdate() {
if (this.renderer) {
this.renderer.setViewport(
0,
0,
this.dom.offsetWidth,
this.dom.offsetHeight
);
this.renderer.render(this.scene, this.camera);
if (this.mixer !== null) {
//clock.getDelta()方法获得两帧的时间间隔
// 更新混合器相关的时间
this.mixer.update(this.clock.getDelta());
}
if (this.generateCurrFrameFlag) {
const img = new Image();
let imgData = this.renderer.domElement.toDataURL("image/jpeg");
console.log("this.renderer");
img.src = imgData;
// 如果是时装或个性动画类内容则播放默认动画
this.currFrame = img;
this.generateCurrFrameFlag = false;
}
}
}
// 场景绘制 canvas 生成图片
getCurrPreviewStoreData() {
const previewHelper = new PreviewDataHelper();
const previewData = {
cameraPosition: {
x: this.camera.position.x,
y: this.camera.position.y,
z: this.camera.position.z,
},
previewCenter: {
x: this.cameraControls.center.x,
y: this.cameraControls.center.y,
z: this.cameraControls.center.z,
},
ambientLight: this.ambientLight,
directionalLight: this.directionalLights,
};
return previewHelper.transPreviewDataToStore(previewData);
}
getCurrFrame() {
return new Promise((resolve) => {
this.generateCurrFrameFlag = true;
console.log("this.generateCurrFrameFlag", this.generateCurrFrameFlag);
setTimeout(() => {

@@ -295,3 +306,3 @@ resolve(this.currFrame);

const tga = new TgaLoader();
tga.open(url, () => {
tga.open(url, () => {
const dom = tga.getCanvas();

@@ -298,0 +309,0 @@ const img = new Image();

Sorry, the diff of this file is too big to display

Sorry, the diff of this file is too big to display

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc