diff --git a/README.md b/README.md index 62762f6f..a7cd41fa 100644 --- a/README.md +++ b/README.md @@ -46,7 +46,7 @@ Supported Languages: 中文 / [繁體中文](README-tw.md) / [English](README-en 10. 使用`点击场景添加模型`方式时,模型放置到场景之前出现一个预览效果。 11. 新增编辑工具栏:撤销、重做、清空历史记录、复制、删除。 12. 几何体菜单添加文字功能,修改为不缩放的文字。 -13. 新增添加设置:无、下雨。 +13. 新增添加设置:无、下雨、下雪。 ## 技术分享 diff --git a/ShadowEditor.Web/assets/textures/particles/raindrop-1.png b/ShadowEditor.Web/assets/textures/particles/raindrop-1.png new file mode 100644 index 00000000..dbc56adb Binary files /dev/null and b/ShadowEditor.Web/assets/textures/particles/raindrop-1.png differ diff --git a/ShadowEditor.Web/assets/textures/particles/raindrop-2.png b/ShadowEditor.Web/assets/textures/particles/raindrop-2.png new file mode 100644 index 00000000..cbc71dcb Binary files /dev/null and b/ShadowEditor.Web/assets/textures/particles/raindrop-2.png differ diff --git a/ShadowEditor.Web/assets/textures/particles/snowflake1.png b/ShadowEditor.Web/assets/textures/particles/snowflake1.png new file mode 100644 index 00000000..e5750f70 Binary files /dev/null and b/ShadowEditor.Web/assets/textures/particles/snowflake1.png differ diff --git a/ShadowEditor.Web/assets/textures/particles/snowflake2.png b/ShadowEditor.Web/assets/textures/particles/snowflake2.png new file mode 100644 index 00000000..000f93ef Binary files /dev/null and b/ShadowEditor.Web/assets/textures/particles/snowflake2.png differ diff --git a/ShadowEditor.Web/assets/textures/particles/snowflake3.png b/ShadowEditor.Web/assets/textures/particles/snowflake3.png new file mode 100644 index 00000000..363af5da Binary files /dev/null and b/ShadowEditor.Web/assets/textures/particles/snowflake3.png differ diff --git a/ShadowEditor.Web/assets/textures/particles/snowflake4.png b/ShadowEditor.Web/assets/textures/particles/snowflake4.png new file mode 100644 index 00000000..03b357e2 Binary files /dev/null and b/ShadowEditor.Web/assets/textures/particles/snowflake4.png differ diff --git a/ShadowEditor.Web/assets/textures/particles/snowflake5.png b/ShadowEditor.Web/assets/textures/particles/snowflake5.png new file mode 100644 index 00000000..02246c17 Binary files /dev/null and b/ShadowEditor.Web/assets/textures/particles/snowflake5.png differ diff --git a/ShadowEditor.Web/src/event/WeatherEvent.js b/ShadowEditor.Web/src/event/WeatherEvent.js index 7eb8625d..78095896 100644 --- a/ShadowEditor.Web/src/event/WeatherEvent.js +++ b/ShadowEditor.Web/src/event/WeatherEvent.js @@ -1,5 +1,6 @@ import BaseEvent from './BaseEvent'; import Rain from '../object/weather/Rain'; +import Snow from '../object/weather/Snow'; /** * 视图事件 @@ -9,6 +10,7 @@ function WeatherEvent() { BaseEvent.call(this); this.weather = ''; + this.object = null; this.onOptionChange = this.onOptionChange.bind(this); this.onAfterRender = this.onAfterRender.bind(this); @@ -31,42 +33,33 @@ WeatherEvent.prototype.onOptionChange = function (name, value) { return; } this.weather = value; -}; -WeatherEvent.prototype.onAfterRender = function () { - if (this.weather === 'rain') { - this.updateRain(); - } else if (this.weather === 'snow') { - this.updateSnow(); + if (this.object) { + app.editor.sceneHelpers.remove(this.object); + this.object = null; } -}; -WeatherEvent.prototype.updateRain = function () { - if (this.rain === undefined) { - this.rain = new Rain(); + if (this.weather === 'rain') { + if (this.rain === undefined) { + this.rain = new Rain(); + } + this.object = this.rain; app.editor.sceneHelpers.add(this.rain); } - let vertices = this.rain.geometry.vertices; - - vertices.forEach(v => { - v.y = v.y - v.velocityY; - v.x = v.x - v.velocityX; - - if (v.y <= 0) { - v.y = 60; + if (this.weather === 'snow') { + if (this.snow === undefined) { + this.snow = new Snow(); } - - if (v.x <= -20 || v.x >= 20) { - v.velocityX = v.velocityX * -1; - } - }); - - this.rain.geometry.verticesNeedUpdate = true; + this.object = this.snow; + app.editor.sceneHelpers.add(this.snow); + } }; -WeatherEvent.prototype.updateSnow = function () { - +WeatherEvent.prototype.onAfterRender = function () { + if (this.object) { + this.object.update(); + } }; export default WeatherEvent; \ No newline at end of file diff --git a/ShadowEditor.Web/src/object/weather/Rain.js b/ShadowEditor.Web/src/object/weather/Rain.js index 169654ac..97c1f1c1 100644 --- a/ShadowEditor.Web/src/object/weather/Rain.js +++ b/ShadowEditor.Web/src/object/weather/Rain.js @@ -1,8 +1,14 @@ /** * 下雨 */ -class Rain extends THREE.Points { +class Rain extends THREE.Object3D { constructor() { + super(); + + this.createPointClouds('assets/textures/particles/raindrop-3.png'); + } + + createPointClouds(url) { let geometry = new THREE.Geometry(); let range = 40; @@ -21,12 +27,35 @@ class Rain extends THREE.Points { size: 3, transparent: true, opacity: 0.6, - map: new THREE.TextureLoader().load('assets/textures/particles/raindrop-3.png'), + map: new THREE.TextureLoader().load(url), blending: THREE.AdditiveBlending, sizeAttenuation: true, color: 0xffffff }); - super(geometry, material); + + let points = new THREE.Points(geometry, material); + points.sortParticles = true; + + this.add(points); + } + + update() { + this.children.forEach(n => { + n.geometry.vertices.forEach(v => { + v.y = v.y - v.velocityY; + v.x = v.x - v.velocityX; + + if (v.y <= 0) { + v.y = 60; + } + + if (v.x <= -20 || v.x >= 20) { + v.velocityX = v.velocityX * -1; + } + }); + + n.geometry.verticesNeedUpdate = true; + }); } } diff --git a/ShadowEditor.Web/src/object/weather/Snow.js b/ShadowEditor.Web/src/object/weather/Snow.js index e69de29b..0726f205 100644 --- a/ShadowEditor.Web/src/object/weather/Snow.js +++ b/ShadowEditor.Web/src/object/weather/Snow.js @@ -0,0 +1,72 @@ +/** + * 下雪 + */ +class Snow extends THREE.Object3D { + constructor() { + super(); + + this.createPointClouds('assets/textures/particles/snowflake1.png'); + this.createPointClouds('assets/textures/particles/snowflake2.png'); + this.createPointClouds('assets/textures/particles/snowflake3.png'); + this.createPointClouds('assets/textures/particles/snowflake5.png'); + } + + createPointClouds(url) { + let geometry = new THREE.Geometry(); + + let range = 40; + + for (let i = 0; i < 50; i++) { + let particle = new THREE.Vector3( + Math.random() * range - range / 2, + Math.random() * range * 1.5, + Math.random() * range - range / 2); + + particle.velocityY = 0.1 + Math.random() / 5; + particle.velocityX = (Math.random() - 0.5) / 3; + particle.velocityZ = (Math.random() - 0.5) / 3; + geometry.vertices.push(particle); + } + + let color = new THREE.Color(0xffffff); + + let hsl = { h: 0, s: 0, l: 0 }; + color.getHSL(hsl); + color.setHSL(hsl.h, hsl.s, Math.random() * hsl.l); + + let material = new THREE.PointsMaterial({ + size: 10, + transparent: true, + opacity: 0.6, + map: new THREE.TextureLoader().load(url), + blending: THREE.AdditiveBlending, + depthWrite: false, + sizeAttenuation: true, + color: color + }); + + let points = new THREE.Points(geometry, material); + points.sortParticles = true; + this.add(points); + } + + update() { + this.children.forEach(child => { + let vertices = child.geometry.vertices; + + vertices.forEach(v => { + v.y = v.y - v.velocityY; + v.x = v.x - v.velocityX; + v.z = v.z - v.velocityZ; + + if (v.y <= 0) v.y = 60; + if (v.x <= -20 || v.x >= 20) v.velocityX = v.velocityX * -1; + if (v.z <= -20 || v.z >= 20) v.velocityZ = v.velocityZ * -1; + }); + + child.geometry.verticesNeedUpdate = true; + }); + } +} + +export default Snow; \ No newline at end of file