当前位置:   article > 正文

Three.js--》实现3d地球模型展示_threejs粒子效果地球

threejs粒子效果地球

目录

项目搭建

实现网页简单布局

初始化three.js基础代码

创建环境背景

加载地球模型

实现光柱效果

添加月球模型


今天简单实现一个three.js的小Demo,加强自己对three知识的掌握与学习,只有在项目中才能灵活将所学知识运用起来,话不多说直接开始。

项目搭建

本案例还是借助框架书写three项目,借用vite构建工具搭建vue项目,vite这个构建工具如果有不了解的朋友,可以参考我之前对其讲解的文章:vite脚手架的搭建与使用 。搭建完成之后,用编辑器打开该项目,在终端执行 npm i 安装一下依赖,安装完成之后终端在安装 npm i three 即可。

因为我搭建的是vue3项目,为了便于代码的可读性,所以我将three.js代码单独抽离放在一个组件当中,在App根组件中进入引入该组件。具体如下:

  1. <template>
  2. <!-- 3D地球 -->
  3. <CoolEarth></CoolEarth>
  4. </template>
  5. <script setup>
  6. import CoolEarth from './components/CoolEarth.vue';
  7. </script>
  8. <style lang="less">
  9. *{
  10. margin: 0;
  11. padding: 0;
  12. }
  13. </style>

实现网页简单布局

在HTML布局处进行设置一个loading效果,并通过一个loading.glf动态图使loading效果更加具体,相关代码样式如下:

  1. <template>
  2. <div class="home">
  3. <div class="canvas-container" ref="screenDom"></div>
  4. <div class="loading" v-if="progress != 100"></div>
  5. <div class="progress" v-if="progress != 100">
  6. <img src="../assets/loading.gif" alt="" />
  7. <span>地球加载中:{{ progress }}%</span>
  8. </div>
  9. <div class="title">酷炫3D地球</div>
  10. </div>
  11. </template>
  12. <style>
  13. body {
  14. background-color: #000;
  15. }
  16. .canvas-container {
  17. width: 100vw;
  18. height: 100vh;
  19. }
  20. .home {
  21. width: 100vw;
  22. height: 100vh;
  23. transform-origin: 0 0;
  24. }
  25. .loading {
  26. position: fixed;
  27. top: 0;
  28. left: 0;
  29. width: 1920px;
  30. height: 1080px;
  31. background-image: url(../assets/loading.jpg);
  32. background-size: cover;
  33. filter: blur(50px);
  34. z-index: 100;
  35. }
  36. .progress {
  37. position: fixed;
  38. top: 0;
  39. left: 0;
  40. width: 1920px;
  41. height: 1080px;
  42. z-index: 101;
  43. display: flex;
  44. justify-content: center;
  45. align-items: center;
  46. font-size: 20px;
  47. color: #fff;
  48. }
  49. .progress > img {
  50. padding: 0 15px;
  51. }
  52. .title {
  53. width: 380px;
  54. height: 40px;
  55. position: fixed;
  56. right: 100px;
  57. top: 50px;
  58. background-color: rgba(0, 0, 0, 0.5);
  59. line-height: 40px;
  60. text-align: center;
  61. color: #fff;
  62. border-radius: 5px;
  63. z-index: 110;
  64. }
  65. </style>

初始化three.js基础代码

three.js开启必须用到的基础代码如下:

导入three库

import * as THREE from 'three'

初始化场景

const scene = new THREE.Scene()

初始化相机

  1. const camera = new THREE.PerspectiveCamera(75,window.innerWidth/window.innerHeight,0.1,1000)
  2. camera.position.set(0,50,300)

初始化渲染器

  1. const renderer = new THREE.WebGLRenderer({ antialias: true })
  2. renderer.setSize(window.innerWidth,window.innerHeight)

监听屏幕大小的改变,修改渲染器的宽高和相机的比例

  1. window.addEventListener("resize",()=>{
  2. renderer.setSize(window.innerWidth,window.innerHeight)
  3. camera.aspect = window.innerWidth/window.innerHeight
  4. camera.updateProjectionMatrix()
  5. })

设置渲染函数

  1. const render = () =>{
  2. controls.update();
  3. requestAnimationFrame(render);
  4. renderer.render(scene, camera);
  5. }

进行挂载

  1. onMounted(()=>{
  2. // 设置进度
  3. THREE.DefaultLoadingManager.onProgress = function (item, loaded, total) {
  4. progress.value = new Number((loaded / total) * 100).toFixed(2);
  5. };
  6. // 将画布添加到页面中
  7. screenDom.value.appendChild(renderer.domElement)
  8. render()
  9. })

ok,写完基础代码之后,接下来开始具体的Demo实操。

创建环境背景

这里通过TextureLoader加载各种类型的纹理图像,包括JPEG、PNG、GIF等。通过TextureLoader,开发人员可以轻松地将纹理加载到自己的Three.js场景中,从而为场景增加更多的细节和视觉效果。

  1. // 创建星空的背景颜色
  2. scene.background = new THREE.Color(0x030311);
  3. // 加载点材质纹理
  4. const starsTexture = new THREE.TextureLoader().load("./images/stars.png");
  5. const starsMaterial = new THREE.PointsMaterial({
  6. size: 2,
  7. sizeAttenuation: true, // 尺寸衰减
  8. color: 0x4d76cf,
  9. transparent: true,
  10. opacity: 1,
  11. map: starsTexture,
  12. });

接下来通过点材质创建星空效果,setAttribute方法可以用于向这些BufferAttribute对象中设置顶点属性数据,BufferAttribute是在Three.js等WebGL引擎中用于描述几何体或粒子的渲染数据结构,也是WebGL中顶点缓存对象(VBO)中存储顶点数据的方式之一:

  1. // 使用点材质创建星空效果
  2. const vertices = [];
  3. for (let i = 0; i < 500; i++) {
  4. const vertex = new THREE.Vector3();
  5. vertex.x = 800 * Math.random() - 400;
  6. vertex.y = 800 * Math.random() - 400;
  7. vertex.z = 800 * Math.random() - 400;
  8. vertices.push(vertex.x, vertex.y, vertex.z);
  9. }
  10. // 星空效果
  11. let starsGeometry = new THREE.BufferGeometry();
  12. starsGeometry.setAttribute(
  13. "position",
  14. new THREE.BufferAttribute(new Float32Array(vertices), 3)
  15. );
  16. let stars = new THREE.Points(starsGeometry, starsMaterial);
  17. scene.add(stars);

加载地球模型

接下来依然通过TextureLoader加载各种类型的纹理图像:

  1. // 创建地球
  2. let earthGeometry = new THREE.SphereGeometry(50, 32, 32);
  3. let earthTexture = new THREE.TextureLoader().load("./images/map.jpg");
  4. let earthMaterial = new THREE.MeshBasicMaterial({
  5. map: earthTexture,
  6. });
  7. let earth = new THREE.Mesh(earthGeometry, earthMaterial);
  8. scene.add(earth);

接下来在原有地球的基础上再加一层发光球体的壳,使地球更具有美感:

  1. // 发光地球
  2. let lightTexture = new THREE.TextureLoader().load("./images/earth.jpg");
  3. let lightEarthGeometry = new THREE.SphereGeometry(53, 32, 32);
  4. let lightEarthMaterial = new THREE.MeshBasicMaterial({
  5. map: lightTexture,
  6. alphaMap: lightTexture,
  7. blending: THREE.AdditiveBlending,
  8. transparent: true,
  9. });
  10. let lightEarth = new THREE.Mesh(lightEarthGeometry, lightEarthMaterial);
  11. scene.add(lightEarth);

接下来通过 Sprite 将Sprite 对象图像资源打包在一张贴图上,然后在需要渲染Sprite 的时候使用不同的纹理坐标选取对应的图像片段进行绘制。

  1. // 添加地球内外发光精灵
  2. let spriteTexture = new THREE.TextureLoader().load("./images/glow.png");
  3. let spriteMaterial = new THREE.SpriteMaterial({
  4. map: spriteTexture,
  5. color: 0x4d76cf,
  6. transparent: true,
  7. depthWrite: false,
  8. depthTest: false,
  9. blending: THREE.AdditiveBlending,
  10. });
  11. let sprite = new THREE.Sprite(spriteMaterial);
  12. sprite.scale.set(155, 155, 0);
  13. scene.add(sprite);

接下来接着使用该函数使其内发光:

  1. // 内发光
  2. let spriteTexture1 = new THREE.TextureLoader().load("./images/innerGlow.png");
  3. let spriteMaterial1 = new THREE.SpriteMaterial({
  4. map: spriteTexture1,
  5. color: 0x4d76cf,
  6. transparent: true,
  7. depthWrite: false,
  8. depthTest: false,
  9. blending: THREE.AdditiveBlending,
  10. });
  11. let sprite1 = new THREE.Sprite(spriteMaterial1);
  12. sprite1.scale.set(128, 128, 0);
  13. scene.add(sprite1);
  14. let scale = new THREE.Vector3(1, 1, 1);

实现光柱效果

通过for循环实现30个光柱效果的展示,这里依然通过TextureLoader加载各种类型的纹理图像:

  1. for (let i = 0; i < 30; i++) {
  2. // 实现光柱
  3. let lightPillarTexture = new THREE.TextureLoader().load(
  4. "./images/light_column.png"
  5. );
  6. let lightPillarGeometry = new THREE.PlaneGeometry(3, 20);
  7. let lightPillarMaterial = new THREE.MeshBasicMaterial({
  8. color: 0xffffff,
  9. map: lightPillarTexture,
  10. alphaMap: lightPillarTexture,
  11. transparent: true,
  12. blending: THREE.AdditiveBlending,
  13. side: THREE.DoubleSide,
  14. depthWrite: false,
  15. });
  16. let lightPillar = new THREE.Mesh(lightPillarGeometry, lightPillarMaterial);
  17. lightPillar.add(lightPillar.clone().rotateY(Math.PI / 2));
  18. // 设置光柱的位置
  19. let lat = Math.random() * 180 - 90;
  20. let lon = Math.random() * 360 - 180;
  21. let position = lon2xyz(60, lon, lat);
  22. lightPillar.position.set(position.x, position.y, position.z);
  23. lightPillar.quaternion.setFromUnitVectors(
  24. new THREE.Vector3(0, 1, 0),
  25. position.clone().normalize()
  26. );
  27. scene.add(lightPillar);
  28. }

接下来利用贴图给地球的每个光柱添加光圈效果,这里利用gsap动画库实现:

  1. // 创建波纹扩散效果
  2. let circlePlane = new THREE.PlaneGeometry(6, 6);
  3. let circleTexture = new THREE.TextureLoader().load("./images/label.png");
  4. let circleMaterial = new THREE.MeshBasicMaterial({
  5. color: 0xffffff,
  6. map: circleTexture,
  7. transparent: true,
  8. blending: THREE.AdditiveBlending,
  9. depthWrite: false,
  10. side: THREE.DoubleSide,
  11. });
  12. let circleMesh = new THREE.Mesh(circlePlane, circleMaterial);
  13. circleMesh.rotation.x = -Math.PI / 2;
  14. circleMesh.position.set(0, -7, 0);
  15. lightPillar.add(circleMesh);
  16. gsap.to(circleMesh.scale, {
  17. duration: 1 + Math.random() * 0.5,
  18. x: 2,
  19. y: 2,
  20. z: 2,
  21. repeat: -1,
  22. delay: Math.random() * 0.5,
  23. yoyo: true,
  24. ease: "power2.inOut",
  25. });

添加月球模型

接下来依然通过TextureLoader加载各种类型的纹理图像:

  1. // 绕地球运行的月球
  2. let moonTexture = new THREE.TextureLoader().load("./images/moon.jpg");
  3. let moonMaterial = new THREE.MeshStandardMaterial({
  4. map: moonTexture,
  5. emissive: 0xffffff,
  6. emissiveMap: moonTexture,
  7. });
  8. let moonGeometry = new THREE.SphereGeometry(5, 32, 32);
  9. let moon = new THREE.Mesh(moonGeometry, moonMaterial);
  10. moon.position.set(150, 0, 0);
  11. scene.add(moon);

接下来实现月球环模型:

  1. // 创建月球环
  2. let moonRingTexture = new THREE.TextureLoader().load("./images/moon_ring.png");
  3. let moonRingMaterial = new THREE.MeshBasicMaterial({
  4. map: moonRingTexture,
  5. transparent: true,
  6. blending: THREE.AdditiveBlending,
  7. side: THREE.DoubleSide,
  8. depthWrite: false,
  9. opacity: 0.5,
  10. });
  11. let moonRingGeometry = new THREE.RingGeometry(145, 155, 64);
  12. let moonRing = new THREE.Mesh(moonRingGeometry, moonRingMaterial);
  13. moonRing.rotation.x = -Math.PI / 2;
  14. scene.add(moonRing);

接下来通过gsap动画库当月球顺时针绕地球无限匀速旋转运动下去:

  1. let time = {
  2. value: 0,
  3. };
  4. gsap.to(time, {
  5. value: 1,
  6. duration: 10,
  7. repeat: -1,
  8. ease: "linear",
  9. onUpdate: () => {
  10. moon.position.x = 150 * Math.cos(time.value * Math.PI * 2);
  11. moon.position.z = 150 * Math.sin(time.value * Math.PI * 2);
  12. moon.rotation.y = time.value * Math.PI * 8;
  13. },
  14. });

效果完成之后,我们在一开始设置的挂载时显示进度也就有效果了,如下:

demo做完,给出本案例的完整代码:(获取素材也可以私信博主)

  1. <template>
  2. <div class="home">
  3. <div class="canvas-container" ref="screenDom"></div>
  4. <div class="loading" v-if="progress != 100"></div>
  5. <div class="progress" v-if="progress != 100">
  6. <img src="../assets/loading.gif" alt="" />
  7. <span>地球加载中:{{ progress }}%</span>
  8. </div>
  9. <div class="title">酷炫3D地球</div>
  10. </div>
  11. </template>
  12. <script setup>
  13. import * as THREE from 'three'
  14. import { ref,onMounted } from 'vue'
  15. import { gsap } from 'gsap'
  16. import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls'
  17. let screenDom = ref(null)
  18. let progress = ref(0);
  19. // 经纬度转换函数
  20. const lon2xyz = (R,longitude,latitude) =>{
  21. let lon = ( longitude * Math.PI ) / 180 // 转弧度值
  22. const lat = (latitude * Math.PI) / 180 // 转弧度值
  23. lon = -lon // js坐标系z坐标轴对应经度-90度,而不是90度
  24. // 经纬度坐标转球面坐标计算公式
  25. const x = R * Math.cos(lat) * Math.cos(lon)
  26. const y = R * Math.sin(lat)
  27. const z = R * Math.cos(lat) * Math.sin(lon)
  28. // 返回球面坐标
  29. return new THREE.Vector3(x,y,z)
  30. }
  31. // 创建场景
  32. const scene = new THREE.Scene()
  33. // 创建相机
  34. const camera = new THREE.PerspectiveCamera(75,window.innerWidth/window.innerHeight,0.1,1000)
  35. camera.position.set(0,50,300)
  36. // 创建渲染器
  37. const renderer = new THREE.WebGLRenderer({ antialias: true })
  38. renderer.setSize(window.innerWidth,window.innerHeight)
  39. // 创建控制器
  40. const controls = new OrbitControls(camera,renderer.domElement)
  41. controls.autoRotate = true
  42. window.addEventListener("resize",()=>{
  43. renderer.setSize(window.innerWidth,window.innerHeight)
  44. camera.aspect = window.innerWidth/window.innerHeight
  45. camera.updateProjectionMatrix()
  46. })
  47. // 创建渲染函数
  48. const render = () =>{
  49. controls.update();
  50. requestAnimationFrame(render);
  51. renderer.render(scene, camera);
  52. }
  53. onMounted(()=>{
  54. // 设置进度
  55. THREE.DefaultLoadingManager.onProgress = function (item, loaded, total) {
  56. progress.value = new Number((loaded / total) * 100).toFixed(2);
  57. };
  58. // 将画布添加到页面中
  59. screenDom.value.appendChild(renderer.domElement)
  60. render()
  61. })
  62. // 创建星空的背景颜色
  63. scene.background = new THREE.Color(0x030311);
  64. // 加载点材质纹理
  65. const starsTexture = new THREE.TextureLoader().load("./images/stars.png");
  66. const starsMaterial = new THREE.PointsMaterial({
  67. size: 2,
  68. sizeAttenuation: true, // 尺寸衰减
  69. color: 0x4d76cf,
  70. transparent: true,
  71. opacity: 1,
  72. map: starsTexture,
  73. });
  74. // 使用点材质创建星空效果
  75. const vertices = [];
  76. for (let i = 0; i < 500; i++) {
  77. const vertex = new THREE.Vector3();
  78. vertex.x = 800 * Math.random() - 400;
  79. vertex.y = 800 * Math.random() - 400;
  80. vertex.z = 800 * Math.random() - 400;
  81. vertices.push(vertex.x, vertex.y, vertex.z);
  82. }
  83. // 星空效果
  84. let starsGeometry = new THREE.BufferGeometry();
  85. starsGeometry.setAttribute(
  86. "position",
  87. new THREE.BufferAttribute(new Float32Array(vertices), 3)
  88. );
  89. let stars = new THREE.Points(starsGeometry, starsMaterial);
  90. scene.add(stars);
  91. // 创建地球
  92. let earthGeometry = new THREE.SphereGeometry(50, 32, 32);
  93. let earthTexture = new THREE.TextureLoader().load("./images/map.jpg");
  94. let earthMaterial = new THREE.MeshBasicMaterial({
  95. map: earthTexture,
  96. });
  97. let earth = new THREE.Mesh(earthGeometry, earthMaterial);
  98. scene.add(earth);
  99. // 发光地球
  100. let lightTexture = new THREE.TextureLoader().load("./images/earth.jpg");
  101. let lightEarthGeometry = new THREE.SphereGeometry(53, 32, 32);
  102. let lightEarthMaterial = new THREE.MeshBasicMaterial({
  103. map: lightTexture,
  104. alphaMap: lightTexture,
  105. blending: THREE.AdditiveBlending,
  106. transparent: true,
  107. });
  108. let lightEarth = new THREE.Mesh(lightEarthGeometry, lightEarthMaterial);
  109. scene.add(lightEarth);
  110. // 添加地球内外发光精灵
  111. let spriteTexture = new THREE.TextureLoader().load("./images/glow.png");
  112. let spriteMaterial = new THREE.SpriteMaterial({
  113. map: spriteTexture,
  114. color: 0x4d76cf,
  115. transparent: true,
  116. depthWrite: false,
  117. depthTest: false,
  118. blending: THREE.AdditiveBlending,
  119. });
  120. let sprite = new THREE.Sprite(spriteMaterial);
  121. sprite.scale.set(155, 155, 0);
  122. scene.add(sprite);
  123. // 内发光
  124. let spriteTexture1 = new THREE.TextureLoader().load("./images/innerGlow.png");
  125. let spriteMaterial1 = new THREE.SpriteMaterial({
  126. map: spriteTexture1,
  127. color: 0x4d76cf,
  128. transparent: true,
  129. depthWrite: false,
  130. depthTest: false,
  131. blending: THREE.AdditiveBlending,
  132. });
  133. let sprite1 = new THREE.Sprite(spriteMaterial1);
  134. sprite1.scale.set(128, 128, 0);
  135. scene.add(sprite1);
  136. let scale = new THREE.Vector3(1, 1, 1);
  137. for (let i = 0; i < 30; i++) {
  138. // 实现光柱
  139. let lightPillarTexture = new THREE.TextureLoader().load(
  140. "./images/light_column.png"
  141. );
  142. let lightPillarGeometry = new THREE.PlaneGeometry(3, 20);
  143. let lightPillarMaterial = new THREE.MeshBasicMaterial({
  144. color: 0xffffff,
  145. map: lightPillarTexture,
  146. alphaMap: lightPillarTexture,
  147. transparent: true,
  148. blending: THREE.AdditiveBlending,
  149. side: THREE.DoubleSide,
  150. depthWrite: false,
  151. });
  152. let lightPillar = new THREE.Mesh(lightPillarGeometry, lightPillarMaterial);
  153. lightPillar.add(lightPillar.clone().rotateY(Math.PI / 2));
  154. // 设置光柱的位置
  155. let lat = Math.random() * 180 - 90;
  156. let lon = Math.random() * 360 - 180;
  157. let position = lon2xyz(60, lon, lat);
  158. lightPillar.position.set(position.x, position.y, position.z);
  159. lightPillar.quaternion.setFromUnitVectors(
  160. new THREE.Vector3(0, 1, 0),
  161. position.clone().normalize()
  162. );
  163. scene.add(lightPillar);
  164. // 创建波纹扩散效果
  165. let circlePlane = new THREE.PlaneGeometry(6, 6);
  166. let circleTexture = new THREE.TextureLoader().load("./images/label.png");
  167. let circleMaterial = new THREE.MeshBasicMaterial({
  168. color: 0xffffff,
  169. map: circleTexture,
  170. transparent: true,
  171. blending: THREE.AdditiveBlending,
  172. depthWrite: false,
  173. side: THREE.DoubleSide,
  174. });
  175. let circleMesh = new THREE.Mesh(circlePlane, circleMaterial);
  176. circleMesh.rotation.x = -Math.PI / 2;
  177. circleMesh.position.set(0, -7, 0);
  178. lightPillar.add(circleMesh);
  179. gsap.to(circleMesh.scale, {
  180. duration: 1 + Math.random() * 0.5,
  181. x: 2,
  182. y: 2,
  183. z: 2,
  184. repeat: -1,
  185. delay: Math.random() * 0.5,
  186. yoyo: true,
  187. ease: "power2.inOut",
  188. });
  189. }
  190. // 绕地球运行的月球
  191. let moonTexture = new THREE.TextureLoader().load("./images/moon.jpg");
  192. let moonMaterial = new THREE.MeshStandardMaterial({
  193. map: moonTexture,
  194. emissive: 0xffffff,
  195. emissiveMap: moonTexture,
  196. });
  197. let moonGeometry = new THREE.SphereGeometry(5, 32, 32);
  198. let moon = new THREE.Mesh(moonGeometry, moonMaterial);
  199. moon.position.set(150, 0, 0);
  200. scene.add(moon);
  201. // 创建月球环
  202. let moonRingTexture = new THREE.TextureLoader().load("./images/moon_ring.png");
  203. let moonRingMaterial = new THREE.MeshBasicMaterial({
  204. map: moonRingTexture,
  205. transparent: true,
  206. blending: THREE.AdditiveBlending,
  207. side: THREE.DoubleSide,
  208. depthWrite: false,
  209. opacity: 0.5,
  210. });
  211. let moonRingGeometry = new THREE.RingGeometry(145, 155, 64);
  212. let moonRing = new THREE.Mesh(moonRingGeometry, moonRingMaterial);
  213. moonRing.rotation.x = -Math.PI / 2;
  214. scene.add(moonRing);
  215. let time = {
  216. value: 0,
  217. };
  218. gsap.to(time, {
  219. value: 1,
  220. duration: 10,
  221. repeat: -1,
  222. ease: "linear",
  223. onUpdate: () => {
  224. moon.position.x = 150 * Math.cos(time.value * Math.PI * 2);
  225. moon.position.z = 150 * Math.sin(time.value * Math.PI * 2);
  226. moon.rotation.y = time.value * Math.PI * 8;
  227. },
  228. });
  229. </script>
  230. <style>
  231. body {
  232. background-color: #000;
  233. }
  234. .canvas-container {
  235. width: 100vw;
  236. height: 100vh;
  237. }
  238. .home {
  239. width: 100vw;
  240. height: 100vh;
  241. transform-origin: 0 0;
  242. }
  243. .loading {
  244. position: fixed;
  245. top: 0;
  246. left: 0;
  247. width: 1920px;
  248. height: 1080px;
  249. background-image: url(../assets/loading.jpg);
  250. background-size: cover;
  251. filter: blur(50px);
  252. z-index: 100;
  253. }
  254. .progress {
  255. position: fixed;
  256. top: 0;
  257. left: 0;
  258. width: 1920px;
  259. height: 1080px;
  260. z-index: 101;
  261. display: flex;
  262. justify-content: center;
  263. align-items: center;
  264. font-size: 20px;
  265. color: #fff;
  266. }
  267. .progress > img {
  268. padding: 0 15px;
  269. }
  270. .title {
  271. width: 380px;
  272. height: 40px;
  273. position: fixed;
  274. right: 100px;
  275. top: 50px;
  276. background-color: rgba(0, 0, 0, 0.5);
  277. line-height: 40px;
  278. text-align: center;
  279. color: #fff;
  280. border-radius: 5px;
  281. z-index: 110;
  282. }
  283. </style>
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/羊村懒王/article/detail/340031
推荐阅读
相关标签
  

闽ICP备14008679号