import React, { useEffect, useRef } from 'react';
|
import * as THREE from 'three';
|
import { extend } from '@react-three/fiber';
|
import { Geometry, Base, Subtraction, Addition } from '@react-three/csg';
|
import { TextGeometry } from 'three/examples/jsm/geometries/TextGeometry';
|
import { DEBUG } from '../config/setting';
|
extend({ TextGeometry });
|
|
const House = (props) => {
|
const {
|
wallThickness = 2,
|
wallOpacity = .6,
|
width = DEBUG ? 14000 : 1400,
|
length = DEBUG ? 12000 : 1200,
|
height = DEBUG ? 4000 : 400,
|
aside_width = 130,
|
aside_length = 130,
|
position = new THREE.Vector3(200, 0, 0),
|
space_width = 10000,
|
space_length = 12000,
|
road_width = 600,
|
grass_width = 400,
|
cross_width = 100,
|
} = props;
|
|
const getPointToShape = (points, extra) => {
|
const shape = new THREE.Shape();
|
const obj = {};
|
extra?.forEach((item) => {
|
obj[item.i] = item.setShape;
|
});
|
points.forEach((point, index) => {
|
const { x, y } = point;
|
if (!index) {
|
shape.moveTo(x, y);
|
}
|
if (obj[index]) {
|
obj[index](shape, point);
|
} else {
|
shape.lineTo(x, y);
|
}
|
});
|
return shape;
|
};
|
|
// const texture = new THREE.TextureLoader().load('/static/wall_pic5.jpg');
|
const texture = new THREE.TextureLoader().load(
|
`/textures/wall_pic5.jpg`
|
);
|
|
texture.wrapS = THREE.RepeatWrapping; // 水平方向重复
|
texture.repeat.set(0.02, 0.02);
|
|
const roofTexture = new THREE.TextureLoader().load(
|
`/textures/wall_pic7.png`
|
);
|
roofTexture.wrapS = THREE.RepeatWrapping; // 水平方向重复
|
roofTexture.wrapT = THREE.RepeatWrapping; // 垂直方向重复
|
roofTexture.rotation = Math.PI / 2;
|
roofTexture.repeat.set(0.005, 0.005);
|
|
const floorTexture = new THREE.TextureLoader().load(
|
`/textures/floor_02.png`
|
);
|
floorTexture.wrapS = THREE.RepeatWrapping; // 水平方向重复
|
floorTexture.wrapT = THREE.RepeatWrapping; // 垂直方向重复
|
floorTexture.repeat.set(0.01, 0.01);
|
|
const roadTexture = new THREE.TextureLoader().load(
|
`/textures/road2.jpg`
|
);
|
roadTexture.wrapS = THREE.RepeatWrapping; // 水平方向重复
|
roadTexture.wrapT = THREE.RepeatWrapping; // 垂直方向重复
|
roadTexture.repeat.set(5, 1);
|
|
const grassTexture = new THREE.TextureLoader().load(
|
`/textures/grass.jpg`
|
);
|
grassTexture.wrapS = THREE.RepeatWrapping; // 水平方向重复
|
grassTexture.wrapT = THREE.RepeatWrapping; // 垂直方向重复
|
grassTexture.repeat.set(20, 1);
|
|
const surfaceTexture = new THREE.TextureLoader().load(
|
`/textures/surface.jpg`
|
);
|
surfaceTexture.wrapS = THREE.RepeatWrapping; // 水平方向重复
|
surfaceTexture.wrapT = THREE.RepeatWrapping; // 垂直方向重复
|
surfaceTexture.repeat.set(0.01, 0.01);
|
|
const crossTexture = new THREE.TextureLoader().load(
|
`/textures/cross.png`
|
);
|
crossTexture.wrapS = THREE.RepeatWrapping; // 水平方向重复
|
crossTexture.wrapT = THREE.RepeatWrapping; // 垂直方向重复
|
crossTexture.repeat.set(70, 1);
|
|
const getBackWallShape = () => {
|
const shape = getPointToShape([
|
new THREE.Vector2(-length, -height),
|
new THREE.Vector2(-length, height),
|
new THREE.Vector2(length, height),
|
new THREE.Vector2(length, -height),
|
]);
|
const doorHoles = new THREE.Path();
|
doorHoles.moveTo(-width / 30, -height);
|
doorHoles.lineTo(-width / 30, (-2 * height) / 5);
|
doorHoles.lineTo(width / 30, (-2 * height) / 5);
|
doorHoles.lineTo(width / 30, -height);
|
doorHoles.moveTo(-width / 30, -height);
|
shape.holes.push(doorHoles);
|
return shape;
|
};
|
|
// 第一层
|
const getBackWallTopShape = () => {
|
const shape = getPointToShape([
|
new THREE.Vector2(-length, -height / 2),
|
new THREE.Vector2(-length, -(height / 2 - 5)),
|
new THREE.Vector2(-length / 2, height / 4),
|
new THREE.Vector2(0, -(height / 2 - 5)),
|
new THREE.Vector2(length / 2, height / 4),
|
new THREE.Vector2(length, -(height / 2 - 5)), // 右边。x轴是一样的,不断加厚度
|
new THREE.Vector2(length, -height / 2),
|
new THREE.Vector2(-length, -height / 2),
|
]);
|
return shape;
|
};
|
|
// 第二层
|
const getRoofShape = () => {
|
const shape = getPointToShape(
|
[
|
new THREE.Vector2(-length, -(height / 2 - 5)), // 第一个点,椭圆曲线加载第一第二个点之间
|
new THREE.Vector2(-length, -(height / 2 + 5)),
|
new THREE.Vector2(-length - wallThickness - 5, -(height / 2 + 5)),
|
// new THREE.Vector2(-length - (5 * length) / (height / 2 - 10), -(height / 2 + 10)),
|
new THREE.Vector2(-length - wallThickness - 5, -(height / 2 - 5) + 2 * wallThickness), // 做曲线的那一条
|
// new THREE.Vector2(-length - wallThickness, -(height / 2 - 5) + wallThickness),
|
new THREE.Vector2(-length, -(height / 2 - 5) + 2 * wallThickness),
|
new THREE.Vector2(-length, -(height / 2 - 5) + wallThickness), // 第二个点
|
new THREE.Vector2(-length / 2, height / 4 + wallThickness),
|
new THREE.Vector2(0, -(height / 2 - 5) + wallThickness), // 第二低点顶点
|
new THREE.Vector2(length / 2, height / 4 + wallThickness),
|
new THREE.Vector2(length, -(height / 2 - 5) + wallThickness), // 第三低点顶点
|
// 在这里做圆柱
|
new THREE.Vector2(length, -(height / 2 - 5) + 2 * wallThickness),
|
new THREE.Vector2(length + 5, -(height / 2 - 5) + 2 * wallThickness),
|
new THREE.Vector2(length + 5, -(height / 2 - 5) + 2 * wallThickness - 15), // 做曲线的那一条
|
new THREE.Vector2(length, -(height / 2 - 5) + 2 * wallThickness - 15),
|
// over
|
new THREE.Vector2(length, -(height / 2 - 5)), // 第三低点底点
|
new THREE.Vector2(length / 2, height / 4),
|
new THREE.Vector2(0, -(height / 2 - 5)), // 第二低点底点
|
new THREE.Vector2(-length / 2, height / 4),
|
new THREE.Vector2(-length, -(height / 2 - 5)), // 原点
|
],
|
[
|
{
|
i: 3,
|
setShape: (shape, point) => {
|
const { x, y } = point;
|
shape.bezierCurveTo(
|
-length - wallThickness - 5 - 2.5,
|
-(height / 2 + 5 - 14 / 4),
|
-length - wallThickness - 5 - 2.5,
|
-(height / 2 + 5 - (14 * 3) / 4),
|
x,
|
y
|
);
|
},
|
},
|
{
|
i: 12,
|
setShape: (shape, point) => {
|
const { x, y } = point;
|
shape.bezierCurveTo(
|
length + 5 + 2.5,
|
-(height / 2 - 5) + 2 * wallThickness - 14 / 4,
|
length + 5 + 2.5,
|
-(height / 2 - 5) + 2 * wallThickness - (14 * 3) / 4,
|
x,
|
y
|
);
|
},
|
},
|
]
|
);
|
return shape;
|
};
|
|
// 第三层
|
const getTopRoofShape = () => {
|
const shape = getPointToShape([
|
new THREE.Vector2(-length, -(height / 2 - 5) + wallThickness),
|
new THREE.Vector2(-length, -(height / 2 - 5) + 2 * wallThickness),
|
new THREE.Vector2(-length / 2, height / 4 + 2 * wallThickness),
|
new THREE.Vector2(0, -(height / 2 - 5) + 2 * wallThickness),
|
new THREE.Vector2(length / 2, height / 4 + 2 * wallThickness),
|
new THREE.Vector2(length, -(height / 2 - 5) + 2 * wallThickness),
|
new THREE.Vector2(length, -(height / 2 - 5) + wallThickness),
|
new THREE.Vector2(length / 2, height / 4 + wallThickness),
|
new THREE.Vector2(0, -(height / 2 - 5) + wallThickness),
|
new THREE.Vector2(-length / 2, height / 4 + wallThickness),
|
]);
|
return shape;
|
};
|
|
// const Text = (props: any) => {
|
// const font = useLoader(THREE.FontLoader, '/static/STXingkai_Regular.json');
|
// return (
|
// <mesh
|
// scale={[-1, 1, 1]}
|
// position={new THREE.Vector3(width - 50, 2 * height - 150, -length - 10)}
|
// >
|
// <textGeometry args={[props.text, { font, size: 100, height: 10 }]} />
|
// <meshStandardMaterial color={'#22d0d1'} />
|
// </mesh>
|
// );
|
// };
|
|
// 仓库底下的那一块地板,会比仓库略大
|
const HouseFloor = () => {
|
return (
|
<extrudeGeometry
|
args={[
|
getPointToShape([
|
// 下面的不要
|
new THREE.Vector2(-width - aside_width, -length - aside_length),
|
new THREE.Vector2(width + aside_width, -length - aside_length),
|
new THREE.Vector2(width + aside_width, length + aside_length),
|
new THREE.Vector2(-width - aside_width, length + aside_length),
|
]),
|
{ depth: wallThickness },
|
]}
|
/>
|
);
|
};
|
|
// 前面的路,有招牌的那一面
|
const FrontRoad = () => {
|
return (
|
<extrudeGeometry
|
args={[
|
getPointToShape([
|
new THREE.Vector2(width + aside_width, -length - aside_length),
|
new THREE.Vector2(width + aside_width, -space_length),
|
new THREE.Vector2(-width - aside_width, -space_length),
|
new THREE.Vector2(-width - aside_width, -length - aside_length),
|
]),
|
{ depth: wallThickness },
|
]}
|
/>
|
);
|
};
|
//后面的路,招牌的那一边的反面
|
const BackRoad = () => {
|
return (
|
<extrudeGeometry
|
args={[
|
getPointToShape([
|
new THREE.Vector2(-width - aside_width, length + aside_length),
|
new THREE.Vector2(-width - aside_width, space_length),
|
new THREE.Vector2(width + aside_width, space_length),
|
new THREE.Vector2(width + aside_width, length + aside_length),
|
]),
|
{ depth: wallThickness },
|
]}
|
/>
|
);
|
};
|
|
// 右边的镂空的,就是没有墙的那一面
|
const RightRoad = () => {
|
return (
|
<extrudeGeometry
|
args={[
|
getPointToShape([
|
new THREE.Vector2(-width - aside_width, -length - aside_length),
|
new THREE.Vector2(-space_width, -length - aside_length),
|
new THREE.Vector2(-space_width, length + aside_length),
|
new THREE.Vector2(-width - aside_width, length + aside_length),
|
]),
|
{ depth: wallThickness },
|
]}
|
/>
|
);
|
};
|
|
const LeftRoad = () => {
|
return (
|
<extrudeGeometry
|
args={[
|
getPointToShape([
|
new THREE.Vector2(width + aside_width, length + aside_length),
|
new THREE.Vector2(space_width, length + aside_length),
|
new THREE.Vector2(space_width, -length - aside_length),
|
new THREE.Vector2(width + aside_width, -length - aside_length),
|
]),
|
{ depth: wallThickness },
|
]}
|
/>
|
);
|
};
|
|
const RoadMaterial = () => {
|
return <meshBasicMaterial map={roadTexture}></meshBasicMaterial>;
|
};
|
|
const GrassMaterial = () => {
|
return <meshBasicMaterial map={grassTexture}></meshBasicMaterial>;
|
};
|
|
const SurfaceMaterial = () => {
|
return <meshBasicMaterial map={surfaceTexture}></meshBasicMaterial>;
|
};
|
|
const CrossMaterial = () => {
|
return <meshBasicMaterial map={crossTexture}></meshBasicMaterial>;
|
};
|
|
const OutSideSurface = (props) => {
|
return (
|
<group rotation={[0, props.rotation, 0]}>
|
{/* 第一个道路 */}
|
<mesh rotation={[Math.PI / 2, 0, 0]}>
|
<Geometry>
|
<Base position={[0, road_width / 2, 0]}>
|
<boxGeometry args={[props.length * 2, road_width, 10]} />
|
</Base>
|
<Addition position={[0, -road_width / 2, 0]}>
|
<boxGeometry args={[props.length * 2, road_width, 10]} />
|
</Addition>
|
<Subtraction position={[0, 0, 0]}>
|
<boxGeometry args={props.subArgs} />
|
</Subtraction>
|
</Geometry>
|
<RoadMaterial></RoadMaterial>
|
</mesh>
|
<mesh rotation={[Math.PI / 2, 0, 0]}>
|
<Geometry>
|
<Base position={[0, road_width + grass_width / 2, 0]}>
|
<boxGeometry args={[props.length * 2, grass_width, 10]} />
|
</Base>
|
<Addition position={[0, -(road_width + grass_width / 2), 0]}>
|
<boxGeometry args={[props.length * 2, grass_width, 10]} />
|
</Addition>
|
<Subtraction position={[0, 0, 0]}>
|
<boxGeometry args={props.subArgs} />
|
</Subtraction>
|
</Geometry>
|
<GrassMaterial></GrassMaterial>
|
</mesh>
|
<mesh rotation={[Math.PI / 2, 0, 0]}>
|
<Geometry>
|
<Base position={[0, road_width + grass_width + cross_width / 2, 0]}>
|
<boxGeometry args={[props.length * 2, cross_width, 10]} />
|
</Base>
|
<Addition position={[0, -(road_width + grass_width + cross_width / 2), 0]}>
|
<boxGeometry args={[props.length * 2, cross_width, 10]} />
|
</Addition>
|
<Subtraction position={[0, 0, 0]}>
|
<boxGeometry args={props.subArgs} />
|
</Subtraction>
|
</Geometry>
|
<CrossMaterial></CrossMaterial>
|
</mesh>
|
</group>
|
);
|
};
|
|
const floorColor = '#535760';
|
|
return (
|
<group position={position} receiveShadow>
|
{/* 草坪和场景 */}
|
<mesh rotation={[Math.PI / 2, 0, 0]}>
|
{/* <mesh> */}
|
<Geometry>
|
<Base>
|
<extrudeGeometry
|
args={[
|
getPointToShape([
|
new THREE.Vector2(-space_width, -space_length),
|
new THREE.Vector2(space_width, -space_length),
|
new THREE.Vector2(space_width, space_length),
|
new THREE.Vector2(-space_width, space_length),
|
new THREE.Vector2(-space_width, -space_length),
|
]),
|
{ depth: wallThickness },
|
]}
|
/>
|
</Base>
|
{/* 中间的镂空的 */}
|
<Subtraction>
|
<HouseFloor></HouseFloor>
|
</Subtraction>
|
{/* 正面的镂空的 */}
|
<Subtraction>
|
<FrontRoad></FrontRoad>
|
</Subtraction>
|
{/* 后边的镂空的,就是正面对面的那一面 */}
|
<Subtraction>
|
<BackRoad></BackRoad>
|
</Subtraction>
|
{/* 右面的镂空的,没有墙的那一面 */}
|
<Subtraction>
|
<RightRoad></RightRoad>
|
</Subtraction>
|
{/* 左边的镂空的,有个小门的那一边 */}
|
<Subtraction>
|
<LeftRoad></LeftRoad>
|
</Subtraction>
|
</Geometry>
|
<meshStandardMaterial color={'white'} />
|
</mesh>
|
{/* <Text text="劢微机器人"></Text> */}
|
{/* 地板 */}
|
<mesh rotation={[Math.PI / 2, 0, 0]} receiveShadow>
|
<HouseFloor></HouseFloor>
|
<meshPhongMaterial map={floorTexture} reflectivity={1.5}></meshPhongMaterial>
|
</mesh>
|
{/* 后面的墙壁,招牌的另一面 */}
|
<mesh position={new THREE.Vector3(0, height, length - wallThickness)} receiveShadow>
|
<extrudeGeometry
|
args={[
|
getPointToShape([
|
new THREE.Vector2(-width, -height),
|
new THREE.Vector2(-width, height),
|
new THREE.Vector2(width, height),
|
new THREE.Vector2(width, -height),
|
]),
|
{ depth: wallThickness },
|
]}
|
/>
|
<meshPhongMaterial map={texture} metalness={1.0} reflectivity={1.5} transparent={true} opacity={wallOpacity}></meshPhongMaterial>
|
</mesh>
|
{/* 后面的路 */}
|
<mesh rotation={[Math.PI / 2, 0, 0]}>
|
<BackRoad></BackRoad>
|
<SurfaceMaterial></SurfaceMaterial>
|
{/* <meshPhysicalMaterial color={floorColor}></meshPhysicalMaterial> */}
|
</mesh>
|
{/* 前面的墙壁,有招牌的那一边 */}
|
<mesh position={new THREE.Vector3(0, height, -length)} receiveShadow>
|
<extrudeGeometry
|
args={[
|
getPointToShape([
|
new THREE.Vector2(-width, -height),
|
new THREE.Vector2(-width, height),
|
new THREE.Vector2(width, height),
|
new THREE.Vector2(width, -height),
|
]),
|
{ depth: wallThickness },
|
]}
|
/>
|
<meshPhongMaterial map={texture} metalness={1.0} reflectivity={1.5} transparent={true} opacity={wallOpacity}></meshPhongMaterial>
|
</mesh>
|
{/* 前面的墙壁下面的路 */}
|
<mesh rotation={[Math.PI / 2, 0, 0]}>
|
<FrontRoad></FrontRoad>
|
<SurfaceMaterial></SurfaceMaterial>
|
{/* <meshPhongMaterial
|
// color={floorColor}
|
map={roadTexture}
|
metalness={1.0}
|
roughness={0.8}
|
></meshPhongMaterial> */}
|
</mesh>
|
{/* 没有墙的那一面下面的路 */}
|
<mesh rotation={[Math.PI / 2, 0, 0]}>
|
<RightRoad></RightRoad>
|
<SurfaceMaterial></SurfaceMaterial>
|
{/* <meshPhysicalMaterial
|
color={floorColor}
|
metalness={1.0}
|
roughness={0.8}
|
></meshPhysicalMaterial> */}
|
</mesh>
|
{/* 左边的墙壁,有个校门的那一边 */}
|
<mesh
|
position={new THREE.Vector3(width, height, 0)}
|
rotation={[0, Math.PI / 2, 0]}
|
receiveShadow
|
>
|
<extrudeGeometry args={[getBackWallShape(), { depth: wallThickness }]} />
|
<meshPhysicalMaterial map={texture} metalness={1.0} roughness={0.8}
|
transparent={true}
|
opacity={wallOpacity}
|
></meshPhysicalMaterial>
|
</mesh>
|
<mesh rotation={[Math.PI / 2, 0, 0]}>
|
<LeftRoad></LeftRoad>
|
<SurfaceMaterial></SurfaceMaterial>
|
{/* <meshPhysicalMaterial
|
color={floorColor}
|
metalness={1.0}
|
roughness={0.8}
|
></meshPhysicalMaterial> */}
|
</mesh>
|
|
{/* 两个轴的路面参数 */}
|
<OutSideSurface
|
rotation={0}
|
length={space_width}
|
subArgs={[width * 2 + aside_width * 2, length * 2 + aside_length * 2, 10]}
|
></OutSideSurface>
|
<OutSideSurface
|
rotation={Math.PI / 2}
|
length={space_length}
|
subArgs={[length * 2 + aside_length * 2, width * 2 + aside_width * 2, 10]}
|
></OutSideSurface>
|
|
{/* 后面墙壁的顶部 */}
|
<mesh
|
position={new THREE.Vector3(width, (5 / 2) * height, 0)}
|
rotation={[0, Math.PI / 2, 0]}
|
receiveShadow
|
>
|
<extrudeGeometry args={[getBackWallTopShape(), { depth: 2 || wallThickness }]} />
|
<meshPhysicalMaterial
|
color={'#0069c5'}
|
metalness={1.0}
|
roughness={0.8}
|
transparent={true}
|
opacity={wallOpacity}
|
></meshPhysicalMaterial>
|
</mesh>
|
{/* 顶部第二层 */}
|
<mesh
|
position={new THREE.Vector3(-width - 5, (5 / 2) * height, 0)}
|
rotation={[0, Math.PI / 2, 0]}
|
receiveShadow
|
>
|
<extrudeGeometry args={[getRoofShape(), { depth: 2 * width + 10 || wallThickness }]} />
|
<meshPhysicalMaterial
|
color={'#4895f6'}
|
metalness={1.0}
|
roughness={0.8}
|
transparent={true}
|
opacity={wallOpacity}
|
></meshPhysicalMaterial>
|
</mesh>
|
{/* 顶部第三层 */}
|
<mesh
|
position={new THREE.Vector3(-width, (5 / 2) * height, 0)}
|
rotation={[0, Math.PI / 2, 0]}
|
receiveShadow
|
>
|
<extrudeGeometry args={[getTopRoofShape(), { depth: 2 * width || wallThickness }]} />
|
<meshPhysicalMaterial
|
map={roofTexture}
|
metalness={1.0}
|
roughness={0.8}
|
transparent={true}
|
opacity={wallOpacity}
|
></meshPhysicalMaterial>
|
</mesh>
|
</group>
|
);
|
};
|
|
export default House;
|