У меня плохая проблема, которую нужно решить в приложении, основанном на реакции, написанном машинописным шрифтом, который должен управлять трехмерными фигурами. Проблема в том, что отражения выглядят не очень хорошо. Я перепробовал все, что мог, чтобы улучшить код, но ничего не получилось.
Рабочий процесс заключается в создании держателя материала в блендере, его экспорте и применении к пустой фигуре, импортированной из другого файла gltf.
Для всех материалов, которые я пробовал (бумага, с обычной структурой карты), все работает отлично.
с простым материалом бумаги
Если материал является отражающим (шероховатость 0,2 и металличность 0,8), это результат:
с отражающим материалом
AsВы можете видеть, что часть отраженной среды является совершенно неправильной, если вы считаете, что куб является заполнителем, поэтому:
одно из шести изображений карты куба
Код очень прост, здесь я создаю карту куба:
const loader = new THREE.CubeTextureLoader();
const path = `${this.props.baseUrl}backgrounds/${background.value}`;
const ext = background.value === "test" ? "jpg" : "png";
const bkcg = [
`${path}/py.${ext}`,
`${path}/nz.${ext}`,
`${path}/px.${ext}`,
`${path}/ny.${ext}`,
`${path}/pz.${ext}`,
`${path}/nx.${ext}`,
];
// const loader = new THREE.TextureLoader();
// const bkcg = `${this.props.baseUrl}backgrounds/test_texture.jpg`;
loader.load(bkcg, async (t) => {
t.minFilter = THREE.LinearFilter;
t.magFilter = THREE.LinearFilter;
t.encoding = THREE.sRGBEncoding;
t.format = THREE.RGBFormat;
this.setState({
background: t,
bckgLoaded: true,
});
Здесь я назначаю материал различным сеткам:
public editMeshes = (
item: THREE.Mesh,
isOrderPage: boolean,
design: IDesign,
materials: {[name: string]: THREE.MeshStandardMaterial | string},
textures: ITextures,
renderer: THREE.WebGLRenderer,
scene: THREE.Scene,
) => {
if (item.name === "Ground" || item.name === "X_Ground_Freigabe") {
const color = isOrderPage ? new THREE.Color("#ffffff") : new THREE.Color("#aaaaaa"); // #8f8f8f
const groundMaterial = new THREE.MeshBasicMaterial({ color });
item.material = groundMaterial;
} else {
item.scale.x = item.scale.x + 0;
item.scale.y = item.scale.y + 0;
item.scale.z = item.scale.z + 0;
if (Object.keys(design).indexOf(item.name) !== -1 || Object.keys(materials).indexOf(item.name) !== -1) {
if (Object.keys(design).indexOf(item.name) === -1 && Object.keys(materials).indexOf(item.name) !== -1) {
if (item.material instanceof THREE.MeshStandardMaterial) {
item.material.color = new THREE.Color(`${materials[item.name]}`);
}
} else {
if (typeof(materials[item.name]) !== "string") {
item.material = materials[item.name] as THREE.MeshStandardMaterial;
if (item.material instanceof THREE.MeshStandardMaterial) {
if (shinyMaterials.indexOf((item.material as THREE.MeshStandardMaterial).name) !== -1) {
this.createCubeCamera(item, textures, scene, renderer);
item.material.needsUpdate = true;
} else {
(item.material as THREE.MeshStandardMaterial).map = textures ? textures[item.name] :
(item.material as THREE.MeshStandardMaterial).map;
(item.material as THREE.MeshStandardMaterial).envMapIntensity = 4;
(item.material as THREE.MeshStandardMaterial).needsUpdate = true;
item.material.flatShading = false;
}
}
}
}
} else {
if (shinyMaterials.indexOf((item.material as THREE.MeshStandardMaterial).name) !== -1) {
this.createCubeCamera(item, textures, scene, renderer);
}
}
}
}
}
здесь я создаю камеру для отражений:
public createCubeCamera = (
item: THREE.Mesh,
textures: ITextures,
scene: THREE.Scene,
renderer: THREE.WebGLRenderer) => {
const cubeCamera = new THREE.CubeCamera(0.001, 10000, 2048);
scene.add(cubeCamera);
cubeCamera.name = `cubeCamera_${item.name}`;
cubeCamera.position.set(item.position.x, item.position.y, item.position.z);
item.visible = false;
cubeCamera.update(renderer, scene);
item.visible = true;
const renderCamera = cubeCamera.renderTarget.texture as THREE.CubeTexture; // scene.background as THREE.CubeTexture
(item.material as THREE.MeshStandardMaterial).map =
textures ? textures[item.name] : (item.material as THREE.MeshStandardMaterial).map;
(item.material as THREE.MeshStandardMaterial).envMap = renderCamera;
(item.material as THREE.MeshStandardMaterial).envMapIntensity = 1;
(item.material as THREE.MeshStandardMaterial).flatShading = false;
(item.material as THREE.MeshStandardMaterial).needsUpdate = true;
}
и онre рендеринг сцены:
if (this.props.background) {
scene.background = this.props.background;
const camera = this.props.mainScene.cameras[0];
scene.children[0].children.map((item: THREE.Object3D) => {
if (item instanceof THREE.Light) {
this.props.mockUtils.editLights(
item as THREE.SpotLight | THREE.DirectionalLight,
this.props.scene.lights_intensity,
scene,
);
}
if (item instanceof THREE.Mesh) {
this.props.mockUtils.editMeshes(
item,
this.props.isOrderPage,
this.props.design,
this.props.materials,
this.props.textures,
// this.props.background,
renderer,
scene,
);
}
});
this.props.mockUtils.addAmbientLight(scene, this.props.scene.ambient_light);
scene.children.map((obj: THREE.Object3D) => {
if (obj instanceof THREE.CubeCamera) {
obj.update(renderer, scene);
}
});
renderer.render(scene, camera);
if (this.design.current) {
this.props.mockUtils.finish(
renderer,
FinalImage,
id,
`${this.props.baseUrl}products/${this.props.scene.product_name}.jpg`,
this.props.isOrderPage,
this.props.scene.zoomFactor,
this.design.current,
this.assetsLoaderCallback,
);
}
}
}
Может кто-нибудь помочь мне понять, как получить нормальное отражение карты куба, которая применяется к фону сцены?
Спасибо
Майкл Моретти