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.43 to 1.0.44

59

default.js

@@ -155,2 +155,5 @@ import * as THREE from 'star_mod_custom_three';

export const FEMALE_HEAD_MATERIAL_KEY = 1403;
export const MALE_HEAD_MATERIAL_KEY = 1401;
export const FEMALE_BODY_KEY = 404;

@@ -160,23 +163,27 @@ export const MALE_BODY_KEY = 402;

export const MALE_HAIR_KEY = 401;
export const FEMALE_HEAD_MATERIAL_KEY = 1403;
export const MALE_HEAD_MATERIAL_KEY = 1401;
export const MALE_FASHION_ANIMATION_KEY = 501;
export const FEMALE_FASHION_ANIMATION_KEY = 502;
export const isFashion = (key) => {
return key === FEMALE_BODY_KEY || key === FEMALE_HAIR_KEY || key === MALE_HAIR_KEY || key === MALE_BODY_KEY;
return Number(key) === FEMALE_BODY_KEY || Number(key) === FEMALE_HAIR_KEY || Number(key) === MALE_HAIR_KEY || Number(key) === MALE_BODY_KEY;
};
export const isFashionHair = (key) => {
return key === FEMALE_HAIR_KEY || key === MALE_HAIR_KEY;
return Number(key) === FEMALE_HAIR_KEY || Number(key) === MALE_HAIR_KEY;
}
export const isFashionBody = (key) => {
return key === FEMALE_BODY_KEY || key === MALE_BODY_KEY;
return Number(key) === FEMALE_BODY_KEY || Number(key) === MALE_BODY_KEY;
}
export const isFashionAnimation = (key) => {
return Number(key) === MALE_FASHION_ANIMATION_KEY || Number(key) === FEMALE_FASHION_ANIMATION_KEY;
}
export const isFashionFemale = (key) => {
return key === FEMALE_BODY_KEY || key === FEMALE_HAIR_KEY;
return Number(key) === FEMALE_BODY_KEY || Number(key) === FEMALE_HAIR_KEY || Number(key) === FEMALE_FASHION_ANIMATION_KEY;
}
export const isFashionMale = (key) => {
return key === MALE_HAIR_KEY || key === MALE_BODY_KEY;
return Number(key) === MALE_HAIR_KEY || Number(key) === MALE_BODY_KEY || Number(key) === MALE_FASHION_ANIMATION_KEY;
}

@@ -218,3 +225,13 @@

export const fashionFemaleAnimationModel = {
domesticPath: 'https://mod-img.westar.qq.com/mod/modOfficial/1677122095-mesh.fbx',
abroadPath: 'https://xqhw-1255691311.cos.ap-singapore.myqcloud.com/mod/modOfficial/1677122257-mesh.fbx'
};
export const fashionMaleAnimationModel = {
domesticPath: 'https://mod-img.westar.qq.com/mod/modOfficial/1677122095-mesh.fbx',
abroadPath: 'https://xqhw-1255691311.cos.ap-singapore.myqcloud.com/mod/modOfficial/1677122257-mesh.fbx'
};
export const defaultModel = {

@@ -225,3 +242,3 @@ 401: {

fbx: {
domesticPath: 'https://mod-img.westar.qq.com/mod/modOfficial/1684145245_M_CSZ_head_01.FBX'
domesticPath: 'https://mod-img.westar.qq.com/mod/modOfficial/1695037543_M_CSZ_head_01.FBX'
},

@@ -233,3 +250,3 @@ },

fbx: {
domesticPath: 'https://mod-img.westar.qq.com/mod/modOfficial/1684145150_F_CSZ_01_Head.FBX'
domesticPath: 'https://mod-img.westar.qq.com/mod/modOfficial/1695301452_nvluomo.FBX'
},

@@ -240,16 +257,20 @@ },

export const defaultModelAnimation = {
401: {
name: '男',
dancing: {
domesticPath: 'https://mod-img.westar.qq.com/mod/modOfficial/1684224202_Male_Celebrate.FBX',
},
male: {
domesticPath: 'https://mod-img.westar.qq.com/mod/modOfficial/1695037867_Male_Ivankof_Stand.fbx'
},
403: {
name: '女',
dancing: {
domesticPath: 'https://mod-img.westar.qq.com/mod/modOfficial/1684224183_Female_BellyDancing.FBX',
},
female: {
domesticPath: 'https://mod-img.westar.qq.com/mod/modOfficial/1694511493_Female_Jambudiv_Stand.FBX',
},
}
// 默认骨骼数据
export const defaultSkeletonData = {
female: {
domesticPath: ''
},
male: {
domesticPath: ''
}
}
// 玻璃、男性头部皮肤、男性身体皮肤、女性头部皮肤、女性身体皮肤

@@ -256,0 +277,0 @@ export const specificMaterial = {

@@ -8,2 +8,9 @@ import { FBXLoader } from "./FBXLoader";

import { getSceneCoordinateByModel } from "../parser";
// import { loadFile } from '../filesHelper';
import {
isFashionFemale,
isFashionMale,
// isFashionHair,
// isFashionBody
} from '../../default'

@@ -68,3 +75,2 @@ export async function detectFile(key, file, detectRule) {

const object = loader.parse(await file.arrayBuffer());
console.log('object is :', object);
const model = loader.parse(await file.arrayBuffer()).sceneGraph;

@@ -597,3 +603,2 @@ const coordinate = getSceneCoordinateByModel(object);

async function detectFBXFashionFile(file, detectRule) {
console.log('detectRule is :', detectRule);
// 格式要求

@@ -610,16 +615,44 @@ const res = file.name.split(".");

const loader = new FBXLoader();
// TODO: 补充错误处理
const object = loader.parse(await file.arrayBuffer());
// const model = loader.parse(await file.arrayBuffer()).sceneGraph;
const model = loader.parse(await file.arrayBuffer()).sceneGraph;
const coordinate = getSceneCoordinateByModel(object);
console.log('object is :', object);
// 坐标系验证: TODO: +Y 轴朝上的模型
if (Number(coordinate.coord.value) !== 0) {
// 坐标系验证: +Y 轴朝上的模型
if (Number(coordinate.coord.value) !== 0 || Number(coordinate.up.value) !== 1) {
return {
value: false,
message: "模型坐标系不正确, 请重新导出, 注意使用 +Y +Z 作为 up 轴, 并确保 front 轴为 +Z、-Z、-Y、+Y",
message: "模型坐标系不正确, 请重新导出, 注意使用 +Y 作为 up 轴, 并确保 front 轴为 +Z 或 -Z",
};
}
let uniqueSkeleton = null;
model.traverse(child => {
if (child.name === "pelvis" && (child.children[0].name === 'spine_01' || child.children[0].name === 'thigh_l' || child.children[0].name === 'thigh_r')) {
uniqueSkeleton = child;
}
});
if (!uniqueSkeleton) {
return {
value: false,
message: "骨骼信息缺失",
}
}
if (uniqueSkeleton.position.y > 0 && isFashionFemale(detectRule.goodSecondaryClassification)) {
return {
value: false,
message: "女性模型骨骼不正确, 或时装性别选择错误",
};
}
if (uniqueSkeleton.position.y < 0 && isFashionMale(detectRule.goodSecondaryClassification)) {
return {
value: false,
message: "男性模型骨骼不正确, 或时装性别选择错误",
};
}
return {

@@ -640,4 +673,3 @@ value: true,

// 动画 fbx 文件校验
async function detectFBXAnimationFile(file, detectRule) {
console.log('detectRule is :', detectRule);
async function detectFBXAnimationFile(file) {
// 格式要求

@@ -654,17 +686,36 @@ const res = file.name.split(".");

const loader = new FBXLoader();
// TODO: 补充错误处理
const object = loader.parse(await file.arrayBuffer());
// const model = loader.parse(await file.arrayBuffer()).sceneGraph;
const model = loader.parse(await file.arrayBuffer()).sceneGraph;
const coordinate = getSceneCoordinateByModel(object);
console.log('object is :', object);
// 坐标系验证: TODO: +Y 轴朝上的模型
if (Number(coordinate.coord.value) !== 0) {
// 坐标系验证: +Y 轴朝上的模型
if (Number(coordinate.coord.value) !== 0 || Number(coordinate.up.value) !== 1) {
return {
value: false,
message: "模型坐标系不正确, 请重新导出, 注意使用 +Y +Z 作为 up 轴, 并确保 front 轴为 +Z、-Z、-Y、+Y",
message: "模型坐标系不正确, 请重新导出, 注意使用 +Y 作为 up 轴, 并确保 front 轴为 +Z 或 -Z",
};
}
// 骨骼校验,数据当与默认模型骨骼一致
let uniqueSkeleton = null;
model.traverse(child => {
if (child.name === "pelvis" && (child.children[0].name === 'spine_01' || child.children[0].name === 'thigh_l' || child.children[0].name === 'thigh_r')) {
uniqueSkeleton = child;
}
});
if (!uniqueSkeleton) {
return {
value: false,
message: "骨骼信息缺失",
}
}
if (!(model.animations && model.animations.length)) {
return {
value: false,
message: "动画信息缺失",
}
}
return {

@@ -671,0 +722,0 @@ value: true,

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

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

@@ -263,3 +262,8 @@ }

const face = this.model.children[1];
let face = null;
this.model.children.forEach(item => {
if (item.type === "SkinnedMesh") {
face = item;
}
});
const material = face.material;

@@ -312,3 +316,8 @@ // 眉毛与睫毛

const face = this.model.children[1];
let face = null;
this.model.children.forEach(item => {
if (item.type === "SkinnedMesh") {
face = item;
}
});
const material = face.material;

@@ -322,6 +331,6 @@

// 眉毛与睫毛
material[1] = new THREE.MeshPhysicalMaterial(specificMaterial.femaleHead.materialChannelList[1].materialParams);
material[1].map = files[4];
material[1].transparent = true;
material[1].needsUpdate = true;
material[3] = new THREE.MeshPhysicalMaterial(specificMaterial.femaleHead.materialChannelList[1].materialParams);
material[3].map = files[4];
material[3].transparent = true;
material[3].needsUpdate = true;

@@ -328,0 +337,0 @@ // 皮肤

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

{
"name": "star_mod_renderer",
"version": "1.0.43",
"version": "1.0.44",
"description": "star mod project render auxiliary ",

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

@@ -101,2 +101,4 @@ /**

currSelectModel = null;
mixer = null;
clock = new THREE.Clock();
options = {

@@ -194,8 +196,2 @@ mode: RENDER_MODE_PREVIEW,

}
if (this.options.isNeedScreenshot) {
this.setAnimationLoop(() => {
this.customUpdate();
});
}
// this.initAnimation();
}

@@ -210,3 +206,3 @@

this.scene = new THREE.Scene();
this.scene.background = new THREE.Color(SCENE_BACKGROUND_COLOR);
this.setSceneEnvironment();
}

@@ -292,7 +288,2 @@

// TODO: 补充动画
initAnimation() {
}
// TODO: 页面与元素显隐

@@ -791,11 +782,4 @@ initSignal() {

this.renderer.autoClear = true;
}
}
// preview 模式特供 update 用于截取当前帧数据
customUpdate() {
if (this.renderer) {
this.update();
if (this.mixer !== null) {
// this.mixer.update(this.clock.getDelta());
this.mixer.update(this.clock.getDelta());
}

@@ -802,0 +786,0 @@ if (this.generateCurrFrameFlag) {

@@ -66,2 +66,3 @@ /**

import { RenderBase } from "./render.base";
import * as THREE from "star_mod_custom_three";
import {

@@ -71,3 +72,2 @@ getEnvMapList,

// defaultModel,
// defaultModelAnimation,
// FEMALE_HAIR_KEY,

@@ -77,7 +77,13 @@ // MALE_HAIR_KEY,

// MALE_HEAD_MATERIAL_KEY,
RENDER_MODE_PREVIEW
RENDER_MODE_PREVIEW,
isFashion,
isFashionAnimation,
isFashionFemale,
isFashionMale,
// defaultSkeletonData,
defaultModelAnimation
} from "./default";
import { ModelProcessor } from "./helper/modelHelper/index";
// import { calculateVerticesAndFace } from "./helper/calculate";
// import { loadFile } from "./helper/filesHelper";
import { loadFile } from "./helper/filesHelper";
import {

@@ -96,3 +102,4 @@ MainModelAuxiliary, // 主模型辅助类

export class Render extends RenderBase {
mainModels = []; // 所有模型
mainModels = []; // 所有主模型
extraModels = []; // 所有辅助模型
modelsLoader = []; // 请求列表,在 start 时同时执行所有请求内容

@@ -110,10 +117,11 @@ /**

maleHair: null, // 男性时装头发
maleHeader: null, // 男性头部
maleHead: null, // 男性头部
maleBody: null, // 男性时装身体
femaleHair: null, // 女性时装头发
femaleHeader: null, // 女性头部
femaleHead: null, // 女性头部
femaleBody: null, // 女性时装身体
};
previewData = null; // 预览数据
animations = []; // 所有动画: 从配置中请求获取:
animations = []; // 所有动画: 从配置中请求获取
defaultAnimation = null; // 默认动作

@@ -152,4 +160,4 @@ constructor({dom, options}) {

extraMaterialList,
// goodSecondaryClassification,
// fashionConfig,
goodSecondaryClassification,
fashionConfig,
previewData,

@@ -165,2 +173,3 @@ }) {

const modelRender = new ModelProcessor(modelOriginalData);
this.mainModels.push(modelRender);
// channelMaterialHelper

@@ -173,3 +182,2 @@ const channelMaterialAuxiliary = new ChannelMaterialAuxiliary([]);

mainModelAuxiliary.setMainModelData(model);
this.mainModels.push(modelRender);

@@ -218,2 +226,182 @@ const channelTextureLoadSuccess = (textureList) => {

// 如果是时装单品
if (fashionConfig && isFashion(goodSecondaryClassification)) {
if (fashionConfig.defaultHead) {
const defaultHeadModelAuxiliary = new MainModelAuxiliary(fashionConfig.defaultHead.fbx.domesticPath);
const defaultHeadModelOriginalData = await defaultHeadModelAuxiliary.loadModel();
const defaultHeadModelRender = new ModelProcessor(defaultHeadModelOriginalData);
if (isFashionFemale(goodSecondaryClassification)) {
this.auxiliaryModels.femaleHead = defaultHeadModelRender;
}
if (isFashionMale(goodSecondaryClassification)) {
this.auxiliaryModels.maleHead = defaultHeadModelRender;
}
this.extraModels.push(defaultHeadModelRender);
this.modelsLoader.push(
defaultHeadModelRender.createSpecificMaterial(fashionConfig.defaultHead.key)
);
}
if (fashionConfig.defaultHair) {
const defaultHairModelAuxiliary = new MainModelAuxiliary(fashionConfig.defaultHair.mesh);
const defaultHairModelOriginalData = await defaultHairModelAuxiliary.loadModel();
const defaultHairModelRender = new ModelProcessor(defaultHairModelOriginalData);
if (isFashionFemale(goodSecondaryClassification)) {
this.auxiliaryModels.femaleHair = defaultHairModelRender;
}
if (isFashionMale(goodSecondaryClassification)) {
this.auxiliaryModels.maleHair = defaultHairModelRender;
}
if (isFashionFemale(goodSecondaryClassification)) {
this.auxiliaryModels.femaleHair = defaultHairModelRender;
const femaleHairModel = this.auxiliaryModels.femaleHair.getModel();
const femaleHeadModel = this.auxiliaryModels.femaleHead.getModel();
let headBones = null;
femaleHeadModel.traverse((item) => {
if(item.name === 'root') {
headBones = item;
}
});
femaleHairModel.add(headBones.clone(true));
}
this.extraModels.push(defaultHairModelRender);
const loadDefaultHairModelChannelTexture = async () => {
const loaderList = [];
if (fashionConfig.defaultHair.diffuseTexture) {
loaderList.push(loadFile({
url: fashionConfig.defaultHair.diffuseTexture,
type: 'tga'
}))
}
if (fashionConfig.defaultHair.normalTexture) {
loaderList.push(loadFile({
url: fashionConfig.defaultHair.normalTexture,
type: 'tga'
}))
}
if (fashionConfig.defaultHair.ormeTexture) {
loaderList.push(loadFile({
url: fashionConfig.defaultHair.ormeTexture,
type: 'tga'
}))
}
if (loaderList.length) {
const files = await Promise.all(loaderList);
defaultHairModelRender.updateModelMaterialTexture(0, {
diffuseTexture: files[0],
normalTexture: files[1],
ormeTexture: files[2],
});
}
};
this.modelsLoader.push(
loadDefaultHairModelChannelTexture()
);
}
if (fashionConfig.defaultBody) {
const defaultBodyModelAuxiliary = new MainModelAuxiliary(fashionConfig.defaultBody.mesh);
const defaultBodyModelOriginalData = await defaultBodyModelAuxiliary.loadModel();
const defaultBodyModelRender = new ModelProcessor(defaultBodyModelOriginalData);
this.extraModels.push(defaultBodyModelRender);
if (isFashionFemale(goodSecondaryClassification)) {
this.auxiliaryModels.femaleBody = defaultBodyModelRender;
}
if (isFashionMale(goodSecondaryClassification)) {
this.auxiliaryModels.maleBody = defaultBodyModelRender;
}
const loadDefaultBodyModelChannelTexture = async () => {
const loaderList = [];
if (fashionConfig.defaultBody.diffuseTexture) {
loaderList.push(loadFile({
url: fashionConfig.defaultBody.diffuseTexture,
type: 'tga'
}))
}
if (fashionConfig.defaultBody.normalTexture) {
loaderList.push(loadFile({
url: fashionConfig.defaultBody.normalTexture,
type: 'tga'
}))
}
if (fashionConfig.defaultBody.ormeTexture) {
loaderList.push(loadFile({
url: fashionConfig.defaultBody.ormeTexture,
type: 'tga'
}))
}
if (loaderList.length) {
const files = await Promise.all(loaderList);
defaultBodyModelRender.updateModelMaterialTexture(0, {
diffuseTexture: files[0],
normalTexture: files[1],
ormeTexture: files[2],
});
}
};
this.modelsLoader.push(
loadDefaultBodyModelChannelTexture()
);
}
// TODO: 默认动作
if (fashionConfig.animations) {
const loadDefaultAnimations = async () => {
const loaderList = [];
fashionConfig.animations.forEach(item => {
loaderList.push(loadFile({
url: item.fbx,
type: 'fbx'
}));
});
const files = await Promise.all(loaderList);
const animations = files.map(item => {
const animation = item.sceneGraph.animations[0];
return animation;
});
const group = this.mainModels.map(item => {
const object = item.getModel();
return object;
});
Object.keys(this.auxiliaryModels).forEach(key => {
const item = this.auxiliaryModels[key];
if (item && key !== 'floor') {
group.push(item.getModel());
}
});
const flock = new THREE.AnimationObjectGroup(...group);
this.mixer = new THREE.AnimationMixer(flock);
animations.forEach(item => {
const animation = this.mixer.clipAction(item);
this.animations.push(animation);
});
if (isFashionFemale(goodSecondaryClassification)) {
const defaultAnimationFile = await loadFile({
url: defaultModelAnimation.female.domesticPath,
type: 'fbx'
});
const animation = this.mixer.clipAction(defaultAnimationFile.sceneGraph.animations[0]);
this.defaultAnimation = animation;
}
if (isFashionMale(goodSecondaryClassification)) {
const defaultAnimationFile = await loadFile({
url: defaultModelAnimation.male.domesticPath,
type: 'fbx'
});
const animation = this.mixer.clipAction(defaultAnimationFile.sceneGraph.animations[0]);
this.defaultAnimation = animation;
}
};
this.modelsLoader.push(
loadDefaultAnimations()
);
}
}
// 设置预览数据并请求天空盒资源

@@ -242,2 +430,5 @@ const previewHelper = new PreviewDataHelper();

modelRender.setModelMaterialEnvMap(environment.data);
this.extraModels.forEach(modelRender => {
modelRender.setModelMaterialEnvMap(environment.data);
});
}

@@ -251,13 +442,420 @@ resolve();

);
}
// 根据 goodSecondaryClassification 与 fashionConfig 请求对应辅助模型的数据
/*
组合模型参数
{
models: [
{
model,
modelLocalCache,
modelData,
materialMap,
extraMaterialList,
goodSecondaryClassification
},
{
model,
modelLocalCache,
modelData,
materialMap,
extraMaterialList,
goodSecondaryClassification
}
],
previewData,
fashionConfig,
}
*/
async setCombinationModels({
standardGoods,
previewData,
}) {
for (let index = 0; index < standardGoods.length; index++) {
const {
mainModel,
mainModelLocalCache,
mainModelData,
mainMaterialMap,
extraMaterialList
} = standardGoods[index];
const modelAuxiliary = new MainModelAuxiliary(
mainModel,
mainModelLocalCache,
mainModelData
);
const modelOriginalData = await modelAuxiliary.loadModel();
const modelRender = new ModelProcessor(modelOriginalData);
this.mainModels.push(modelRender);
// channelMaterialHelper
const channelMaterialAuxiliary = new ChannelMaterialAuxiliary([]);
// 所有通道纹理全部加载完成并设置对应材质后返回成功
const loadModelChannelTexture = (model) => {
return new Promise((resolve) => {
modelAuxiliary.setMainModelData(model);
}
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);
});
});
};
setCombinationModels() {
channelMaterialAuxiliary.initChannelMaterialParamsList(
getModelMaterialChannelLength(model),
channelMaterialParams,
);
channelMaterialAuxiliary.setMaterialParamsList(mainMaterialMap, extraMaterialList).then(res => {
channelTextureLoadSuccess(res).then(() => {
resolve()
});
});
});
};
this.modelsLoader.push(
loadModelChannelTexture(modelOriginalData)
);
}
const fashionConfig = standardGoods[0].fashionConfig;
const goodSecondaryClassification = standardGoods[0].goodSecondaryClassification;
const defaultHeadModelAuxiliary = new MainModelAuxiliary(fashionConfig.defaultHead.fbx.domesticPath);
const defaultHeadModelOriginalData = await defaultHeadModelAuxiliary.loadModel();
const defaultHeadModelRender = new ModelProcessor(defaultHeadModelOriginalData);
if (isFashionFemale(goodSecondaryClassification)) {
this.auxiliaryModels.femaleHead = defaultHeadModelRender;
}
if (isFashionMale(goodSecondaryClassification)) {
this.auxiliaryModels.maleHead = defaultHeadModelRender;
}
this.extraModels.push(defaultHeadModelRender);
this.modelsLoader.push(
defaultHeadModelRender.createSpecificMaterial(fashionConfig.defaultHead.key)
);
const loadDefaultAnimations = async () => {
const loaderList = [];
fashionConfig.animations.forEach(item => {
loaderList.push(loadFile({
url: item.fbx,
type: 'fbx'
}));
});
const files = await Promise.all(loaderList);
const animations = files.map(item => {
const animation = item.sceneGraph.animations[0];
return animation;
});
const group = this.mainModels.map(item => {
const object = item.getModel();
return object;
});
Object.keys(this.auxiliaryModels).forEach(key => {
const item = this.auxiliaryModels[key];
if (item && key !== 'floor') {
group.push(item.getModel());
}
});
const flock = new THREE.AnimationObjectGroup(...group);
this.mixer = new THREE.AnimationMixer(flock);
animations.forEach(item => {
const animation = this.mixer.clipAction(item);
this.animations.push(animation);
});
if (isFashionFemale(goodSecondaryClassification)) {
const defaultAnimationFile = await loadFile({
url: defaultModelAnimation.female.domesticPath,
type: 'fbx'
});
const animation = this.mixer.clipAction(defaultAnimationFile.sceneGraph.animations[0]);
this.defaultAnimation = animation;
}
if (isFashionMale(goodSecondaryClassification)) {
const defaultAnimationFile = await loadFile({
url: defaultModelAnimation.male.domesticPath,
type: 'fbx'
});
const animation = this.mixer.clipAction(defaultAnimationFile.sceneGraph.animations[0]);
this.defaultAnimation = animation;
}
};
this.modelsLoader.push(
loadDefaultAnimations()
);
// 设置预览数据并请求天空盒资源
const previewHelper = new PreviewDataHelper();
this.previewData = previewHelper.transPreviewDataToRender(previewData);
const getCurrEnvMap = () => {
const envMap = this.previewData.envMap || 'sky';
return new Promise((resolve) => {
let processEnv = "domestic";
try {
if (this.options.platform === "pc") {
processEnv = process.env.VUE_APP_NAME;
} else if (this.options.platform === "mobile") {
processEnv = import.meta.env.VITE_APP_NAME;
}
} catch (e) {
console.error(e);
processEnv = "domestic";
}
getEnvMapByName(envMap, processEnv).then((environment) => {
if (environment) {
this.setSceneEnvironment(environment.data);
this.mainModels.forEach(modelRender => {
modelRender.setModelMaterialEnvMap(environment.data);
})
this.extraModels.forEach(modelRender => {
modelRender.setModelMaterialEnvMap(environment.data);
});
}
resolve();
});
});
}
this.modelsLoader.push(
getCurrEnvMap()
);
}
setFashionAnimations() {
/**
时装动画参数
{
animations: [],
previewData,
fashionConfig,
}
*/
async setFashionAnimations({
mainModel,
mainModelLocalCache,
mainModelData,
goodSecondaryClassification,
fashionConfig,
previewData,
}) {
// 获取个性动作文件
const mainModelAuxiliary = new MainModelAuxiliary(
mainModel,
mainModelLocalCache,
mainModelData
);
const file = await mainModelAuxiliary.loadModel();
const fashionAnimation = file.sceneGraph.animations[0];
// 根据性别设置默认模型并加载对应贴图
if (fashionConfig && isFashionAnimation(goodSecondaryClassification)) {
if (fashionConfig.defaultHead) {
const defaultHeadModelAuxiliary = new MainModelAuxiliary(fashionConfig.defaultHead.fbx.domesticPath);
const defaultHeadModelOriginalData = await defaultHeadModelAuxiliary.loadModel();
const defaultHeadModelRender = new ModelProcessor(defaultHeadModelOriginalData);
this.extraModels.push(defaultHeadModelRender);
if (isFashionFemale(goodSecondaryClassification)) {
this.auxiliaryModels.femaleHead = defaultHeadModelRender;
}
if (isFashionMale(goodSecondaryClassification)) {
this.auxiliaryModels.maleHead = defaultHeadModelRender;
}
this.modelsLoader.push(
defaultHeadModelRender.createSpecificMaterial(fashionConfig.defaultHead.key)
);
}
if (fashionConfig.defaultHair) {
const defaultHairModelAuxiliary = new MainModelAuxiliary(fashionConfig.defaultHair.mesh);
const defaultHairModelOriginalData = await defaultHairModelAuxiliary.loadModel();
const defaultHairModelRender = new ModelProcessor(defaultHairModelOriginalData);
this.extraModels.push(defaultHairModelRender);
if (isFashionFemale(goodSecondaryClassification)) {
this.auxiliaryModels.femaleHair = defaultHairModelRender;
const femaleHairModel = this.auxiliaryModels.femaleHair.getModel();
const femaleHeadModel = this.auxiliaryModels.femaleHead.getModel();
let headBones = null;
femaleHeadModel.traverse((item) => {
if(item.name === 'root') {
headBones = item;
}
});
femaleHairModel.add(headBones.clone(true));
}
if (isFashionMale(goodSecondaryClassification)) {
this.auxiliaryModels.maleHair = defaultHairModelRender;
}
const loadDefaultHairModelChannelTexture = async () => {
const loaderList = [];
if (fashionConfig.defaultHair.diffuseTexture) {
loaderList.push(loadFile({
url: fashionConfig.defaultHair.diffuseTexture,
type: 'tga'
}))
}
if (fashionConfig.defaultHair.normalTexture) {
loaderList.push(loadFile({
url: fashionConfig.defaultHair.normalTexture,
type: 'tga'
}))
}
if (fashionConfig.defaultHair.ormeTexture) {
loaderList.push(loadFile({
url: fashionConfig.defaultHair.ormeTexture,
type: 'tga'
}))
}
if (loaderList.length) {
const files = await Promise.all(loaderList);
defaultHairModelRender.updateModelMaterialTexture(0, {
diffuseTexture: files[0],
normalTexture: files[1],
ormeTexture: files[2],
});
}
};
this.modelsLoader.push(
loadDefaultHairModelChannelTexture()
);
}
if (fashionConfig.defaultBody) {
const defaultBodyModelAuxiliary = new MainModelAuxiliary(fashionConfig.defaultBody.mesh);
const defaultBodyModelOriginalData = await defaultBodyModelAuxiliary.loadModel();
const defaultBodyModelRender = new ModelProcessor(defaultBodyModelOriginalData);
this.extraModels.push(defaultBodyModelRender);
if (isFashionFemale(goodSecondaryClassification)) {
this.auxiliaryModels.femaleBody = defaultBodyModelRender;
}
if (isFashionMale(goodSecondaryClassification)) {
this.auxiliaryModels.maleBody = defaultBodyModelRender;
}
const loadDefaultBodyModelChannelTexture = async () => {
const loaderList = [];
if (fashionConfig.defaultBody.diffuseTexture) {
loaderList.push(loadFile({
url: fashionConfig.defaultBody.diffuseTexture,
type: 'tga'
}))
}
if (fashionConfig.defaultBody.normalTexture) {
loaderList.push(loadFile({
url: fashionConfig.defaultBody.normalTexture,
type: 'tga'
}))
}
if (fashionConfig.defaultBody.ormeTexture) {
loaderList.push(loadFile({
url: fashionConfig.defaultBody.ormeTexture,
type: 'tga'
}))
}
if (loaderList.length) {
const files = await Promise.all(loaderList);
defaultBodyModelRender.updateModelMaterialTexture(0, {
diffuseTexture: files[0],
normalTexture: files[1],
ormeTexture: files[2],
});
}
};
this.modelsLoader.push(
loadDefaultBodyModelChannelTexture()
);
}
}
// 设置动画播放
const animationsModels = [];
Object.keys(this.auxiliaryModels).forEach(key => {
const item = this.auxiliaryModels[key];
if (item && key !== 'floor') {
animationsModels.push(item);
}
});
const group = animationsModels.map(item => {
const object = item.getModel();
return object;
});
const flock = new THREE.AnimationObjectGroup(...group);
this.mixer = new THREE.AnimationMixer(flock);
const animation = this.mixer.clipAction(fashionAnimation);
// 提供动画播放控制到 renderAuxiliary
this.animations.push(animation);
if (isFashionFemale(goodSecondaryClassification)) {
const defaultAnimationFile = await loadFile({
url: defaultModelAnimation.female.domesticPath,
type: 'fbx'
});
const animation = this.mixer.clipAction(defaultAnimationFile.sceneGraph.animations[0]);
this.defaultAnimation = animation;
}
if (isFashionMale(goodSecondaryClassification)) {
const defaultAnimationFile = await loadFile({
url: defaultModelAnimation.male.domesticPath,
type: 'fbx'
});
const animation = this.mixer.clipAction(defaultAnimationFile.sceneGraph.animations[0]);
this.defaultAnimation = animation;
}
// 设置预览与天空盒
const previewHelper = new PreviewDataHelper();
this.previewData = previewHelper.transPreviewDataToRender(previewData);
const getCurrEnvMap = () => {
const envMap = this.previewData.envMap || 'sky';
return new Promise((resolve) => {
let processEnv = "domestic";
try {
if (this.options.platform === "pc") {
processEnv = process.env.VUE_APP_NAME;
} else if (this.options.platform === "mobile") {
processEnv = import.meta.env.VITE_APP_NAME;
}
} catch (e) {
console.error(e);
processEnv = "domestic";
}
getEnvMapByName(envMap, processEnv).then((environment) => {
if (environment) {
this.setSceneEnvironment(environment.data);
this.extraModels.forEach(modelRender => {
modelRender.setModelMaterialEnvMap(environment.data);
});
}
resolve();
});
});
}
this.modelsLoader.push(
getCurrEnvMap()
);
}

@@ -279,3 +877,3 @@

return new Promise((resolve) => {
getEnvMapList().then((envMapList) => {
getEnvMapList(processEnv).then((envMapList) => {
resolve(envMapList);

@@ -294,7 +892,15 @@ });

this.addModel(model);
// 如果有 preview 的话就根据 previewData 执行相机动画,如果没有的话直接 focusModel
this.focusModel(model);
});
this.extraModels.forEach((modelRender) => {
const model = modelRender.getModel();
this.addModel(model);
});
if (this.mainModels.length) {
this.focusModel(this.mainModels[0].getModel());
} else {
this.focusModel(this.extraModels[this.extraModels.length - 1].getModel());
}
this.setPreviewData(this.previewData);

@@ -304,4 +910,2 @@ resolve();

});
// 如果是时装或个性动画类内容则播放默认动画

@@ -313,17 +917,21 @@

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);
if (this.camera) {
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);
} else {
return {};
}
}

@@ -330,0 +938,0 @@

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