快手超火的3D花瓣飘落效果特效代码

原创 小姚  2019-08-08 19:44  阅读 4,600 次

快手超火的3D花瓣飘落效果特效代码,真的很漂亮,表白神器啊!

这是一款基于HTML5实现唯美的3D花瓣飘落效果源码。在明亮的背景下呈现出大量花瓣不规则飘落的视觉效果,且花瓣飘落中呈现出3D立体翻转的效果。是一款非常经典的HTML5动画特效代码。建议使用支持HTML5与css3效果较好的360或谷歌(Chrome)等浏览器预览本源码。

360浏览器下载

演示地址:https://www.xiaoyaogzs.com/wytx/piaohua.html

快手超火的3D花瓣飘落效果特效代码-小姚工作室

  1.  
  2. <!doctype html>
  3. <html>
  4. <head>
  5. <meta charset="utf-8">
  6. <title>HTML5 3D花瓣飘落效果</title>
  7. </head>
  8.  
  9. <style>
  10. body {
  11. padding:0;
  12. margin:0;
  13. overflow:hidden;
  14. height: 600px;
  15. }
  16. canvas {
  17. padding:0;
  18. margin:0;
  19. }
  20. div.btnbg {
  21. position:fixed;
  22. left:0;
  23. top:0;
  24. }
  25. </style>
  26. <body>
  27. <canvas id="sakura"></canvas>
  28. <div class="btnbg">
  29. </div>
  30.  
  31. <!-- sakura shader -->
  32. <script id="sakura_point_vsh" type="x-shader/x_vertex">
  33. uniform mat4 uProjection;
  34. uniform mat4 uModelview;
  35. uniform vec3 uResolution;
  36. uniform vec3 uOffset;
  37. uniform vec3 uDOF; //x:focus distance, y:focus radius, z:max radius
  38. uniform vec3 uFade; //x:start distance, y:half distance, z:near fade start
  39.  
  40. attribute vec3 aPosition;
  41. attribute vec3 aEuler;
  42. attribute vec2 aMisc; //x:size, y:fade
  43.  
  44. varying vec3 pposition;
  45. varying float psize;
  46. varying float palpha;
  47. varying float pdist;
  48.  
  49. //varying mat3 rotMat;
  50. varying vec3 normX;
  51. varying vec3 normY;
  52. varying vec3 normZ;
  53. varying vec3 normal;
  54.  
  55. varying float diffuse;
  56. varying float specular;
  57. varying float rstop;
  58. varying float distancefade;
  59.  
  60. void main(void) {
  61. // Projection is based on vertical angle
  62. vec4 pos = uModelview * vec4(aPosition + uOffset, 1.0);
  63. gl_Position = uProjection * pos;
  64. gl_PointSize = aMisc.x * uProjection[1][1] / -pos.z * uResolution.y * 0.5;
  65.  
  66. pposition = pos.xyz;
  67. psize = aMisc.x;
  68. pdist = length(pos.xyz);
  69. palpha = smoothstep(0.0, 1.0, (pdist - 0.1) / uFade.z);
  70.  
  71. vec3 elrsn = sin(aEuler);
  72. vec3 elrcs = cos(aEuler);
  73. mat3 rotx = mat3(
  74. 1.0, 0.0, 0.0,
  75. 0.0, elrcs.x, elrsn.x,
  76. 0.0, -elrsn.x, elrcs.x
  77. );
  78. mat3 roty = mat3(
  79. elrcs.y, 0.0, -elrsn.y,
  80. 0.0, 1.0, 0.0,
  81. elrsn.y, 0.0, elrcs.y
  82. );
  83. mat3 rotz = mat3(
  84. elrcs.z, elrsn.z, 0.0,
  85. -elrsn.z, elrcs.z, 0.0,
  86. 0.0, 0.0, 1.0
  87. );
  88. mat3 rotmat = rotx * roty * rotz;
  89. normal = rotmat[2];
  90.  
  91. mat3 trrotm = mat3(
  92. rotmat[0][0], rotmat[1][0], rotmat[2][0],
  93. rotmat[0][1], rotmat[1][1], rotmat[2][1],
  94. rotmat[0][2], rotmat[1][2], rotmat[2][2]
  95. );
  96. normX = trrotm[0];
  97. normY = trrotm[1];
  98. normZ = trrotm[2];
  99.  
  100. const vec3 lit = vec3(0.6917144638660746, 0.6917144638660746, -0.20751433915982237);
  101.  
  102. float tmpdfs = dot(lit, normal);
  103. if(tmpdfs < 0.0) {
  104. normal = -normal;
  105. tmpdfs = dot(lit, normal);
  106. }
  107. diffuse = 0.4 + tmpdfs;
  108.  
  109. vec3 eyev = normalize(-pos.xyz);
  110. if(dot(eyev, normal) > 0.0) {
  111. vec3 hv = normalize(eyev + lit);
  112. specular = pow(max(dot(hv, normal), 0.0), 20.0);
  113. }
  114. else {
  115. specular = 0.0;
  116. }
  117.  
  118. rstop = clamp((abs(pdist - uDOF.x) - uDOF.y) / uDOF.z, 0.0, 1.0);
  119. rstop = pow(rstop, 0.5);
  120. //-0.69315 = ln(0.5)
  121. distancefade = min(1.0, exp((uFade.x - pdist) * 0.69315 / uFade.y));
  122. }
  123. </script>
  124. <script id="sakura_point_fsh" type="x-shader/x_fragment">
  125. #ifdef GL_ES
  126. //precision mediump float;
  127. precision highp float;
  128. #endif
  129.  
  130. uniform vec3 uDOF; //x:focus distance, y:focus radius, z:max radius
  131. uniform vec3 uFade; //x:start distance, y:half distance, z:near fade start
  132.  
  133. const vec3 fadeCol = vec3(0.08, 0.03, 0.06);
  134.  
  135. varying vec3 pposition;
  136. varying float psize;
  137. varying float palpha;
  138. varying float pdist;
  139.  
  140. //varying mat3 rotMat;
  141. varying vec3 normX;
  142. varying vec3 normY;
  143. varying vec3 normZ;
  144. varying vec3 normal;
  145.  
  146. varying float diffuse;
  147. varying float specular;
  148. varying float rstop;
  149. varying float distancefade;
  150.  
  151. float ellipse(vec2 p, vec2 o, vec2 r) {
  152. vec2 lp = (p - o) / r;
  153. return length(lp) - 1.0;
  154. }
  155.  
  156. void main(void) {
  157. vec3 p = vec3(gl_PointCoord - vec2(0.5, 0.5), 0.0) * 2.0;
  158. vec3 d = vec3(0.0, 0.0, -1.0);
  159. float nd = normZ.z; //dot(-normZ, d);
  160. if(abs(nd) < 0.0001) discard;
  161.  
  162. float np = dot(normZ, p);
  163. vec3 tp = p + d * np / nd;
  164. vec2 coord = vec2(dot(normX, tp), dot(normY, tp));
  165.  
  166. //angle = 15 degree
  167. const float flwrsn = 0.258819045102521;
  168. const float flwrcs = 0.965925826289068;
  169. mat2 flwrm = mat2(flwrcs, -flwrsn, flwrsn, flwrcs);
  170. vec2 flwrp = vec2(abs(coord.x), coord.y) * flwrm;
  171.  
  172. float r;
  173. if(flwrp.x < 0.0) {
  174. r = ellipse(flwrp, vec2(0.065, 0.024) * 0.5, vec2(0.36, 0.96) * 0.5);
  175. }
  176. else {
  177. r = ellipse(flwrp, vec2(0.065, 0.024) * 0.5, vec2(0.58, 0.96) * 0.5);
  178. }
  179.  
  180. if(r > rstop) discard;
  181.  
  182. vec3 col = mix(vec3(1.0, 0.8, 0.75), vec3(1.0, 0.9, 0.87), r);
  183. float grady = mix(0.0, 1.0, pow(coord.y * 0.5 + 0.5, 0.35));
  184. col *= vec3(1.0, grady, grady);
  185. col *= mix(0.8, 1.0, pow(abs(coord.x), 0.3));
  186. col = col * diffuse + specular;
  187.  
  188. col = mix(fadeCol, col, distancefade);
  189.  
  190. float alpha = (rstop > 0.001)? (0.5 - r / (rstop * 2.0)) : 1.0;
  191. alpha = smoothstep(0.0, 1.0, alpha) * palpha;
  192.  
  193. gl_FragColor = vec4(col * 0.5, alpha);
  194. }
  195. </script>
  196. <!-- effects -->
  197. <script id="fx_common_vsh" type="x-shader/x_vertex">
  198. uniform vec3 uResolution;
  199. attribute vec2 aPosition;
  200.  
  201. varying vec2 texCoord;
  202. varying vec2 screenCoord;
  203.  
  204. void main(void) {
  205. gl_Position = vec4(aPosition, 0.0, 1.0);
  206. texCoord = aPosition.xy * 0.5 + vec2(0.5, 0.5);
  207. screenCoord = aPosition.xy * vec2(uResolution.z, 1.0);
  208. }
  209. </script>
  210. <script id="bg_fsh" type="x-shader/x_fragment">
  211. #ifdef GL_ES
  212. //precision mediump float;
  213. precision highp float;
  214. #endif
  215.  
  216. uniform vec2 uTimes;
  217.  
  218. varying vec2 texCoord;
  219. varying vec2 screenCoord;
  220.  
  221. void main(void) {
  222. vec3 col;
  223. float c;
  224. vec2 tmpv = texCoord * vec2(0.8, 1.0) - vec2(0.95, 1.0);
  225. c = exp(-pow(length(tmpv) * 1.8, 2.0));
  226. col = mix(vec3(0.02, 0.0, 0.03), vec3(0.96, 0.98, 1.0) * 1.5, c);
  227. gl_FragColor = vec4(col * 0.5, 1.0);
  228. }
  229. </script>
  230. <script id="fx_brightbuf_fsh" type="x-shader/x_fragment">
  231. #ifdef GL_ES
  232. //precision mediump float;
  233. precision highp float;
  234. #endif
  235. uniform sampler2D uSrc;
  236. uniform vec2 uDelta;
  237.  
  238. varying vec2 texCoord;
  239. varying vec2 screenCoord;
  240.  
  241. void main(void) {
  242. vec4 col = texture2D(uSrc, texCoord);
  243. gl_FragColor = vec4(col.rgb * 2.0 - vec3(0.5), 1.0);
  244. }
  245. </script>
  246. <script id="fx_dirblur_r4_fsh" type="x-shader/x_fragment">
  247. #ifdef GL_ES
  248. //precision mediump float;
  249. precision highp float;
  250. #endif
  251. uniform sampler2D uSrc;
  252. uniform vec2 uDelta;
  253. uniform vec4 uBlurDir; //dir(x, y), stride(z, w)
  254.  
  255. varying vec2 texCoord;
  256. varying vec2 screenCoord;
  257.  
  258. void main(void) {
  259. vec4 col = texture2D(uSrc, texCoord);
  260. col = col + texture2D(uSrc, texCoord + uBlurDir.xy * uDelta);
  261. col = col + texture2D(uSrc, texCoord - uBlurDir.xy * uDelta);
  262. col = col + texture2D(uSrc, texCoord + (uBlurDir.xy + uBlurDir.zw) * uDelta);
  263. col = col + texture2D(uSrc, texCoord - (uBlurDir.xy + uBlurDir.zw) * uDelta);
  264. gl_FragColor = col / 5.0;
  265. }
  266. </script>
  267. <!-- effect fragment shader template -->
  268. <script id="fx_common_fsh" type="x-shader/x_fragment">
  269. #ifdef GL_ES
  270. //precision mediump float;
  271. precision highp float;
  272. #endif
  273. uniform sampler2D uSrc;
  274. uniform vec2 uDelta;
  275.  
  276. varying vec2 texCoord;
  277. varying vec2 screenCoord;
  278.  
  279. void main(void) {
  280. gl_FragColor = texture2D(uSrc, texCoord);
  281. }
  282. </script>
  283. <!-- post processing -->
  284. <script id="pp_final_vsh" type="x-shader/x_vertex">
  285. uniform vec3 uResolution;
  286. attribute vec2 aPosition;
  287. varying vec2 texCoord;
  288. varying vec2 screenCoord;
  289. void main(void) {
  290. gl_Position = vec4(aPosition, 0.0, 1.0);
  291. texCoord = aPosition.xy * 0.5 + vec2(0.5, 0.5);
  292. screenCoord = aPosition.xy * vec2(uResolution.z, 1.0);
  293. }
  294. </script>
  295. <script id="pp_final_fsh" type="x-shader/x_fragment">
  296. #ifdef GL_ES
  297. //precision mediump float;
  298. precision highp float;
  299. #endif
  300. uniform sampler2D uSrc;
  301. uniform sampler2D uBloom;
  302. uniform vec2 uDelta;
  303. varying vec2 texCoord;
  304. varying vec2 screenCoord;
  305. void main(void) {
  306. vec4 srccol = texture2D(uSrc, texCoord) * 2.0;
  307. vec4 bloomcol = texture2D(uBloom, texCoord);
  308. vec4 col;
  309. col = srccol + bloomcol * (vec4(1.0) + srccol);
  310. col *= smoothstep(1.0, 0.0, pow(length((texCoord - vec2(0.5)) * 2.0), 1.2) * 0.5);
  311. col = pow(col, vec4(0.45454545454545)); //(1.0 / 2.2)
  312.  
  313. gl_FragColor = vec4(col.rgb, 1.0);
  314. gl_FragColor.a = 1.0;
  315. }
  316. </script>
  317. </body>
  318. <script>
  319. // Utilities
  320. var Vector3 = {};
  321. var Matrix44 = {};
  322. Vector3.create = function(x, y, z) {
  323. return {'x':x, 'y':y, 'z':z};
  324. };
  325. Vector3.dot = function (v0, v1) {
  326. return v0.x * v1.x + v0.y * v1.y + v0.z * v1.z;
  327. };
  328. Vector3.cross = function (v, v0, v1) {
  329. v.x = v0.y * v1.z - v0.z * v1.y;
  330. v.y = v0.z * v1.x - v0.x * v1.z;
  331. v.z = v0.x * v1.y - v0.y * v1.x;
  332. };
  333. Vector3.normalize = function (v) {
  334. var l = v.x * v.x + v.y * v.y + v.z * v.z;
  335. if(l > 0.00001) {
  336. l = 1.0 / Math.sqrt(l);
  337. v.x *= l;
  338. v.y *= l;
  339. v.z *= l;
  340. }
  341. };
  342. Vector3.arrayForm = function(v) {
  343. if(v.array) {
  344. v.array[0] = v.x;
  345. v.array[1] = v.y;
  346. v.array[2] = v.z;
  347. }
  348. else {
  349. v.array = new Float32Array([v.x, v.y, v.z]);
  350. }
  351. return v.array;
  352. };
  353. Matrix44.createIdentity = function () {
  354. return new Float32Array([1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0]);
  355. };
  356. Matrix44.loadProjection = function (m, aspect, vdeg, near, far) {
  357. var h = near * Math.tan(vdeg * Math.PI / 180.0 * 0.5) * 2.0;
  358. var w = h * aspect;
  359.  
  360. m[0] = 2.0 * near / w;
  361. m[1] = 0.0;
  362. m[2] = 0.0;
  363. m[3] = 0.0;
  364.  
  365. m[4] = 0.0;
  366. m[5] = 2.0 * near / h;
  367. m[6] = 0.0;
  368. m[7] = 0.0;
  369.  
  370. m[8] = 0.0;
  371. m[9] = 0.0;
  372. m[10] = -(far + near) / (far - near);
  373. m[11] = -1.0;
  374.  
  375. m[12] = 0.0;
  376. m[13] = 0.0;
  377. m[14] = -2.0 * far * near / (far - near);
  378. m[15] = 0.0;
  379. };
  380. Matrix44.loadLookAt = function (m, vpos, vlook, vup) {
  381. var frontv = Vector3.create(vpos.x - vlook.x, vpos.y - vlook.y, vpos.z - vlook.z);
  382. Vector3.normalize(frontv);
  383. var sidev = Vector3.create(1.0, 0.0, 0.0);
  384. Vector3.cross(sidev, vup, frontv);
  385. Vector3.normalize(sidev);
  386. var topv = Vector3.create(1.0, 0.0, 0.0);
  387. Vector3.cross(topv, frontv, sidev);
  388. Vector3.normalize(topv);
  389.  
  390. m[0] = sidev.x;
  391. m[1] = topv.x;
  392. m[2] = frontv.x;
  393. m[3] = 0.0;
  394.  
  395. m[4] = sidev.y;
  396. m[5] = topv.y;
  397. m[6] = frontv.y;
  398. m[7] = 0.0;
  399.  
  400. m[8] = sidev.z;
  401. m[9] = topv.z;
  402. m[10] = frontv.z;
  403. m[11] = 0.0;
  404.  
  405. m[12] = -(vpos.x * m[0] + vpos.y * m[4] + vpos.z * m[8]);
  406. m[13] = -(vpos.x * m[1] + vpos.y * m[5] + vpos.z * m[9]);
  407. m[14] = -(vpos.x * m[2] + vpos.y * m[6] + vpos.z * m[10]);
  408. m[15] = 1.0;
  409. };
  410.  
  411. //
  412. var timeInfo = {
  413. 'start':0, 'prev':0, // Date
  414. 'delta':0, 'elapsed':0 // Number(sec)
  415. };
  416.  
  417. //
  418. var gl;
  419. var renderSpec = {
  420. 'width':0,
  421. 'height':0,
  422. 'aspect':1,
  423. 'array':new Float32Array(3),
  424. 'halfWidth':0,
  425. 'halfHeight':0,
  426. 'halfArray':new Float32Array(3)
  427. // and some render targets. see setViewport()
  428. };
  429. renderSpec.setSize = function(w, h) {
  430. renderSpec.width = w;
  431. renderSpec.height = h;
  432. renderSpec.aspect = renderSpec.width / renderSpec.height;
  433. renderSpec.array[0] = renderSpec.width;
  434. renderSpec.array[1] = renderSpec.height;
  435. renderSpec.array[2] = renderSpec.aspect;
  436.  
  437. renderSpec.halfWidth = Math.floor(w / 2);
  438. renderSpec.halfHeight = Math.floor(h / 2);
  439. renderSpec.halfArray[0] = renderSpec.halfWidth;
  440. renderSpec.halfArray[1] = renderSpec.halfHeight;
  441. renderSpec.halfArray[2] = renderSpec.halfWidth / renderSpec.halfHeight;
  442. };
  443.  
  444. function deleteRenderTarget(rt) {
  445. gl.deleteFramebuffer(rt.frameBuffer);
  446. gl.deleteRenderbuffer(rt.renderBuffer);
  447. gl.deleteTexture(rt.texture);
  448. }
  449.  
  450. function createRenderTarget(w, h) {
  451. var ret = {
  452. 'width':w,
  453. 'height':h,
  454. 'sizeArray':new Float32Array([w, h, w / h]),
  455. 'dtxArray':new Float32Array([1.0 / w, 1.0 / h])
  456. };
  457. ret.frameBuffer = gl.createFramebuffer();
  458. ret.renderBuffer = gl.createRenderbuffer();
  459. ret.texture = gl.createTexture();
  460.  
  461. gl.bindTexture(gl.TEXTURE_2D, ret.texture);
  462. gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, w, h, 0, gl.RGBA, gl.UNSIGNED_BYTE, null);
  463. gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
  464. gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
  465. gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
  466. gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
  467.  
  468. gl.bindFramebuffer(gl.FRAMEBUFFER, ret.frameBuffer);
  469. gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, ret.texture, 0);
  470.  
  471. gl.bindRenderbuffer(gl.RENDERBUFFER, ret.renderBuffer);
  472. gl.renderbufferStorage(gl.RENDERBUFFER, gl.DEPTH_COMPONENT16, w, h);
  473. gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.DEPTH_ATTACHMENT, gl.RENDERBUFFER, ret.renderBuffer);
  474.  
  475. gl.bindTexture(gl.TEXTURE_2D, null);
  476. gl.bindRenderbuffer(gl.RENDERBUFFER, null);
  477. gl.bindFramebuffer(gl.FRAMEBUFFER, null);
  478.  
  479. return ret;
  480. }
  481.  
  482. function compileShader(shtype, shsrc) {
  483. var retsh = gl.createShader(shtype);
  484.  
  485. gl.shaderSource(retsh, shsrc);
  486. gl.compileShader(retsh);
  487.  
  488. if(!gl.getShaderParameter(retsh, gl.COMPILE_STATUS)) {
  489. var errlog = gl.getShaderInfoLog(retsh);
  490. gl.deleteShader(retsh);
  491. console.error(errlog);
  492. return null;
  493. }
  494. return retsh;
  495. }
  496.  
  497. function createShader(vtxsrc, frgsrc, uniformlist, attrlist) {
  498. var vsh = compileShader(gl.VERTEX_SHADER, vtxsrc);
  499. var fsh = compileShader(gl.FRAGMENT_SHADER, frgsrc);
  500.  
  501. if(vsh == null || fsh == null) {
  502. return null;
  503. }
  504.  
  505. var prog = gl.createProgram();
  506. gl.attachShader(prog, vsh);
  507. gl.attachShader(prog, fsh);
  508.  
  509. gl.deleteShader(vsh);
  510. gl.deleteShader(fsh);
  511.  
  512. gl.linkProgram(prog);
  513. if (!gl.getProgramParameter(prog, gl.LINK_STATUS)) {
  514. var errlog = gl.getProgramInfoLog(prog);
  515. console.error(errlog);
  516. return null;
  517. }
  518.  
  519. if(uniformlist) {
  520. prog.uniforms = {};
  521. for(var i = 0; i < uniformlist.length; i++) {
  522. prog.uniforms[uniformlist[i]] = gl.getUniformLocation(prog, uniformlist[i]);
  523. }
  524. }
  525.  
  526. if(attrlist) {
  527. prog.attributes = {};
  528. for(var i = 0; i < attrlist.length; i++) {
  529. var attr = attrlist[i];
  530. prog.attributes[attr] = gl.getAttribLocation(prog, attr);
  531. }
  532. }
  533.  
  534. return prog;
  535. }
  536.  
  537. function useShader(prog) {
  538. gl.useProgram(prog);
  539. for(var attr in prog.attributes) {
  540. gl.enableVertexAttribArray(prog.attributes[attr]);;
  541. }
  542. }
  543.  
  544. function unuseShader(prog) {
  545. for(var attr in prog.attributes) {
  546. gl.disableVertexAttribArray(prog.attributes[attr]);;
  547. }
  548. gl.useProgram(null);
  549. }
  550.  
  551. /////
  552. var projection = {
  553. 'angle':60,
  554. 'nearfar':new Float32Array([0.1, 100.0]),
  555. 'matrix':Matrix44.createIdentity()
  556. };
  557. var camera = {
  558. 'position':Vector3.create(0, 0, 100),
  559. 'lookat':Vector3.create(0, 0, 0),
  560. 'up':Vector3.create(0, 1, 0),
  561. 'dof':Vector3.create(10.0, 4.0, 8.0),
  562. 'matrix':Matrix44.createIdentity()
  563. };
  564.  
  565. var pointFlower = {};
  566. var meshFlower = {};
  567. var sceneStandBy = false;
  568.  
  569. var BlossomParticle = function () {
  570. this.velocity = new Array(3);
  571. this.rotation = new Array(3);
  572. this.position = new Array(3);
  573. this.euler = new Array(3);
  574. this.size = 1.0;
  575. this.alpha = 1.0;
  576. this.zkey = 0.0;
  577. };
  578.  
  579. BlossomParticle.prototype.setVelocity = function (vx, vy, vz) {
  580. this.velocity[0] = vx;
  581. this.velocity[1] = vy;
  582. this.velocity[2] = vz;
  583. };
  584.  
  585. BlossomParticle.prototype.setRotation = function (rx, ry, rz) {
  586. this.rotation[0] = rx;
  587. this.rotation[1] = ry;
  588. this.rotation[2] = rz;
  589. };
  590.  
  591. BlossomParticle.prototype.setPosition = function (nx, ny, nz) {
  592. this.position[0] = nx;
  593. this.position[1] = ny;
  594. this.position[2] = nz;
  595. };
  596.  
  597. BlossomParticle.prototype.setEulerAngles = function (rx, ry, rz) {
  598. this.euler[0] = rx;
  599. this.euler[1] = ry;
  600. this.euler[2] = rz;
  601. };
  602.  
  603. BlossomParticle.prototype.setSize = function (s) {
  604. this.size = s;
  605. };
  606.  
  607. BlossomParticle.prototype.update = function (dt, et) {
  608. this.position[0] += this.velocity[0] * dt;
  609. this.position[1] += this.velocity[1] * dt;
  610. this.position[2] += this.velocity[2] * dt;
  611.  
  612. this.euler[0] += this.rotation[0] * dt;
  613. this.euler[1] += this.rotation[1] * dt;
  614. this.euler[2] += this.rotation[2] * dt;
  615. };
  616.  
  617. function createPointFlowers() {
  618. // get point sizes
  619. var prm = gl.getParameter(gl.ALIASED_POINT_SIZE_RANGE);
  620. renderSpec.pointSize = {'min':prm[0], 'max':prm[1]};
  621.  
  622. var vtxsrc = document.getElementById("sakura_point_vsh").textContent;
  623. var frgsrc = document.getElementById("sakura_point_fsh").textContent;
  624.  
  625. pointFlower.program = createShader(
  626. vtxsrc, frgsrc,
  627. ['uProjection', 'uModelview', 'uResolution', 'uOffset', 'uDOF', 'uFade'],
  628. ['aPosition', 'aEuler', 'aMisc']
  629. );
  630.  
  631. useShader(pointFlower.program);
  632. pointFlower.offset = new Float32Array([0.0, 0.0, 0.0]);
  633. pointFlower.fader = Vector3.create(0.0, 10.0, 0.0);
  634.  
  635. // paramerters: velocity[3], rotate[3]
  636. pointFlower.numFlowers = 1600;
  637. pointFlower.particles = new Array(pointFlower.numFlowers);
  638. // vertex attributes {position[3], euler_xyz[3], size[1]}
  639. pointFlower.dataArray = new Float32Array(pointFlower.numFlowers * (3 + 3 + 2));
  640. pointFlower.positionArrayOffset = 0;
  641. pointFlower.eulerArrayOffset = pointFlower.numFlowers * 3;
  642. pointFlower.miscArrayOffset = pointFlower.numFlowers * 6;
  643.  
  644. pointFlower.buffer = gl.createBuffer();
  645. gl.bindBuffer(gl.ARRAY_BUFFER, pointFlower.buffer);
  646. gl.bufferData(gl.ARRAY_BUFFER, pointFlower.dataArray, gl.DYNAMIC_DRAW);
  647. gl.bindBuffer(gl.ARRAY_BUFFER, null);
  648.  
  649. unuseShader(pointFlower.program);
  650.  
  651. for(var i = 0; i < pointFlower.numFlowers; i++) {
  652. pointFlower.particles[i] = new BlossomParticle();
  653. }
  654. }
  655.  
  656. function initPointFlowers() {
  657. //area
  658. pointFlower.area = Vector3.create(20.0, 20.0, 20.0);
  659. pointFlower.area.x = pointFlower.area.y * renderSpec.aspect;
  660.  
  661. pointFlower.fader.x = 10.0; //env fade start
  662. pointFlower.fader.y = pointFlower.area.z; //env fade half
  663. pointFlower.fader.z = 0.1; //near fade start
  664.  
  665. //particles
  666. var PI2 = Math.PI * 2.0;
  667. var tmpv3 = Vector3.create(0, 0, 0);
  668. var tmpv = 0;
  669. var symmetryrand = function() {return (Math.random() * 2.0 - 1.0);};
  670. for(var i = 0; i < pointFlower.numFlowers; i++) {
  671. var tmpprtcl = pointFlower.particles[i];
  672.  
  673. //velocity
  674. tmpv3.x = symmetryrand() * 0.3 + 0.8;
  675. tmpv3.y = symmetryrand() * 0.2 - 1.0;
  676. tmpv3.z = symmetryrand() * 0.3 + 0.5;
  677. Vector3.normalize(tmpv3);
  678. tmpv = 2.0 + Math.random() * 1.0;
  679. tmpprtcl.setVelocity(tmpv3.x * tmpv, tmpv3.y * tmpv, tmpv3.z * tmpv);
  680.  
  681. //rotation
  682. tmpprtcl.setRotation(
  683. symmetryrand() * PI2 * 0.5,
  684. symmetryrand() * PI2 * 0.5,
  685. symmetryrand() * PI2 * 0.5
  686. );
  687.  
  688. //position
  689. tmpprtcl.setPosition(
  690. symmetryrand() * pointFlower.area.x,
  691. symmetryrand() * pointFlower.area.y,
  692. symmetryrand() * pointFlower.area.z
  693. );
  694.  
  695. //euler
  696. tmpprtcl.setEulerAngles(
  697. Math.random() * Math.PI * 2.0,
  698. Math.random() * Math.PI * 2.0,
  699. Math.random() * Math.PI * 2.0
  700. );
  701.  
  702. //size
  703. tmpprtcl.setSize(0.9 + Math.random() * 0.1);
  704. }
  705. }
  706.  
  707. function renderPointFlowers() {
  708. //update
  709. var PI2 = Math.PI * 2.0;
  710. var limit = [pointFlower.area.x, pointFlower.area.y, pointFlower.area.z];
  711. var repeatPos = function (prt, cmp, limit) {
  712. if(Math.abs(prt.position[cmp]) - prt.size * 0.5 > limit) {
  713. //out of area
  714. if(prt.position[cmp] > 0) {
  715. prt.position[cmp] -= limit * 2.0;
  716. }
  717. else {
  718. prt.position[cmp] += limit * 2.0;
  719. }
  720. }
  721. };
  722. var repeatEuler = function (prt, cmp) {
  723. prt.euler[cmp] = prt.euler[cmp] % PI2;
  724. if(prt.euler[cmp] < 0.0) {
  725. prt.euler[cmp] += PI2;
  726. }
  727. };
  728.  
  729. for(var i = 0; i < pointFlower.numFlowers; i++) {
  730. var prtcl = pointFlower.particles[i];
  731. prtcl.update(timeInfo.delta, timeInfo.elapsed);
  732. repeatPos(prtcl, 0, pointFlower.area.x);
  733. repeatPos(prtcl, 1, pointFlower.area.y);
  734. repeatPos(prtcl, 2, pointFlower.area.z);
  735. repeatEuler(prtcl, 0);
  736. repeatEuler(prtcl, 1);
  737. repeatEuler(prtcl, 2);
  738.  
  739. prtcl.alpha = 1.0;//(pointFlower.area.z - prtcl.position[2]) * 0.5;
  740.  
  741. prtcl.zkey = (camera.matrix[2] * prtcl.position[0]
  742. + camera.matrix[6] * prtcl.position[1]
  743. + camera.matrix[10] * prtcl.position[2]
  744. + camera.matrix[14]);
  745. }
  746.  
  747. // sort
  748. pointFlower.particles.sort(function(p0, p1){return p0.zkey - p1.zkey;});
  749.  
  750. // update data
  751. var ipos = pointFlower.positionArrayOffset;
  752. var ieuler = pointFlower.eulerArrayOffset;
  753. var imisc = pointFlower.miscArrayOffset;
  754. for(var i = 0; i < pointFlower.numFlowers; i++) {
  755. var prtcl = pointFlower.particles[i];
  756. pointFlower.dataArray[ipos] = prtcl.position[0];
  757. pointFlower.dataArray[ipos + 1] = prtcl.position[1];
  758. pointFlower.dataArray[ipos + 2] = prtcl.position[2];
  759. ipos += 3;
  760. pointFlower.dataArray[ieuler] = prtcl.euler[0];
  761. pointFlower.dataArray[ieuler + 1] = prtcl.euler[1];
  762. pointFlower.dataArray[ieuler + 2] = prtcl.euler[2];
  763. ieuler += 3;
  764. pointFlower.dataArray[imisc] = prtcl.size;
  765. pointFlower.dataArray[imisc + 1] = prtcl.alpha;
  766. imisc += 2;
  767. }
  768.  
  769. //draw
  770. gl.enable(gl.BLEND);
  771. //gl.disable(gl.DEPTH_TEST);
  772. gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA);
  773.  
  774. var prog = pointFlower.program;
  775. useShader(prog);
  776.  
  777. gl.uniformMatrix4fv(prog.uniforms.uProjection, false, projection.matrix);
  778. gl.uniformMatrix4fv(prog.uniforms.uModelview, false, camera.matrix);
  779. gl.uniform3fv(prog.uniforms.uResolution, renderSpec.array);
  780. gl.uniform3fv(prog.uniforms.uDOF, Vector3.arrayForm(camera.dof));
  781. gl.uniform3fv(prog.uniforms.uFade, Vector3.arrayForm(pointFlower.fader));
  782.  
  783. gl.bindBuffer(gl.ARRAY_BUFFER, pointFlower.buffer);
  784. gl.bufferData(gl.ARRAY_BUFFER, pointFlower.dataArray, gl.DYNAMIC_DRAW);
  785.  
  786. gl.vertexAttribPointer(prog.attributes.aPosition, 3, gl.FLOAT, false, 0, pointFlower.positionArrayOffset * Float32Array.BYTES_PER_ELEMENT);
  787. gl.vertexAttribPointer(prog.attributes.aEuler, 3, gl.FLOAT, false, 0, pointFlower.eulerArrayOffset * Float32Array.BYTES_PER_ELEMENT);
  788. gl.vertexAttribPointer(prog.attributes.aMisc, 2, gl.FLOAT, false, 0, pointFlower.miscArrayOffset * Float32Array.BYTES_PER_ELEMENT);
  789.  
  790. // doubler
  791. for(var i = 1; i < 2; i++) {
  792. var zpos = i * -2.0;
  793. pointFlower.offset[0] = pointFlower.area.x * -1.0;
  794. pointFlower.offset[1] = pointFlower.area.y * -1.0;
  795. pointFlower.offset[2] = pointFlower.area.z * zpos;
  796. gl.uniform3fv(prog.uniforms.uOffset, pointFlower.offset);
  797. gl.drawArrays(gl.POINT, 0, pointFlower.numFlowers);
  798.  
  799. pointFlower.offset[0] = pointFlower.area.x * -1.0;
  800. pointFlower.offset[1] = pointFlower.area.y * 1.0;
  801. pointFlower.offset[2] = pointFlower.area.z * zpos;
  802. gl.uniform3fv(prog.uniforms.uOffset, pointFlower.offset);
  803. gl.drawArrays(gl.POINT, 0, pointFlower.numFlowers);
  804.  
  805. pointFlower.offset[0] = pointFlower.area.x * 1.0;
  806. pointFlower.offset[1] = pointFlower.area.y * -1.0;
  807. pointFlower.offset[2] = pointFlower.area.z * zpos;
  808. gl.uniform3fv(prog.uniforms.uOffset, pointFlower.offset);
  809. gl.drawArrays(gl.POINT, 0, pointFlower.numFlowers);
  810.  
  811. pointFlower.offset[0] = pointFlower.area.x * 1.0;
  812. pointFlower.offset[1] = pointFlower.area.y * 1.0;
  813. pointFlower.offset[2] = pointFlower.area.z * zpos;
  814. gl.uniform3fv(prog.uniforms.uOffset, pointFlower.offset);
  815. gl.drawArrays(gl.POINT, 0, pointFlower.numFlowers);
  816. }
  817.  
  818. //main
  819. pointFlower.offset[0] = 0.0;
  820. pointFlower.offset[1] = 0.0;
  821. pointFlower.offset[2] = 0.0;
  822. gl.uniform3fv(prog.uniforms.uOffset, pointFlower.offset);
  823. gl.drawArrays(gl.POINT, 0, pointFlower.numFlowers);
  824.  
  825. gl.bindBuffer(gl.ARRAY_BUFFER, null);
  826. unuseShader(prog);
  827.  
  828. gl.enable(gl.DEPTH_TEST);
  829. gl.disable(gl.BLEND);
  830. }
  831.  
  832. // effects
  833. //common util
  834. function createEffectProgram(vtxsrc, frgsrc, exunifs, exattrs) {
  835. var ret = {};
  836. var unifs = ['uResolution', 'uSrc', 'uDelta'];
  837. if(exunifs) {
  838. unifs = unifs.concat(exunifs);
  839. }
  840. var attrs = ['aPosition'];
  841. if(exattrs) {
  842. attrs = attrs.concat(exattrs);
  843. }
  844.  
  845. ret.program = createShader(vtxsrc, frgsrc, unifs, attrs);
  846. useShader(ret.program);
  847.  
  848. ret.dataArray = new Float32Array([
  849. -1.0, -1.0,
  850. 1.0, -1.0,
  851. -1.0, 1.0,
  852. 1.0, 1.0
  853. ]);
  854. ret.buffer = gl.createBuffer();
  855. gl.bindBuffer(gl.ARRAY_BUFFER, ret.buffer);
  856. gl.bufferData(gl.ARRAY_BUFFER, ret.dataArray, gl.STATIC_DRAW);
  857.  
  858. gl.bindBuffer(gl.ARRAY_BUFFER, null);
  859. unuseShader(ret.program);
  860.  
  861. return ret;
  862. }
  863.  
  864. // basic usage
  865. // useEffect(prog, srctex({'texture':texid, 'dtxArray':(f32)[dtx, dty]})); //basic initialize
  866. // gl.uniform**(...); //additional uniforms
  867. // drawEffect()
  868. // unuseEffect(prog)
  869. // TEXTURE0 makes src
  870. function useEffect(fxobj, srctex) {
  871. var prog = fxobj.program;
  872. useShader(prog);
  873. gl.uniform3fv(prog.uniforms.uResolution, renderSpec.array);
  874.  
  875. if(srctex != null) {
  876. gl.uniform2fv(prog.uniforms.uDelta, srctex.dtxArray);
  877. gl.uniform1i(prog.uniforms.uSrc, 0);
  878.  
  879. gl.activeTexture(gl.TEXTURE0);
  880. gl.bindTexture(gl.TEXTURE_2D, srctex.texture);
  881. }
  882. }
  883. function drawEffect(fxobj) {
  884. gl.bindBuffer(gl.ARRAY_BUFFER, fxobj.buffer);
  885. gl.vertexAttribPointer(fxobj.program.attributes.aPosition, 2, gl.FLOAT, false, 0, 0);
  886. gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4);
  887. }
  888. function unuseEffect(fxobj) {
  889. unuseShader(fxobj.program);
  890. }
  891.  
  892. var effectLib = {};
  893. function createEffectLib() {
  894.  
  895. var vtxsrc, frgsrc;
  896. //common
  897. var cmnvtxsrc = document.getElementById("fx_common_vsh").textContent;
  898.  
  899. //background
  900. frgsrc = document.getElementById("bg_fsh").textContent;
  901. effectLib.sceneBg = createEffectProgram(cmnvtxsrc, frgsrc, ['uTimes'], null);
  902.  
  903. // make brightpixels buffer
  904. frgsrc = document.getElementById("fx_brightbuf_fsh").textContent;
  905. effectLib.mkBrightBuf = createEffectProgram(cmnvtxsrc, frgsrc, null, null);
  906.  
  907. // direction blur
  908. frgsrc = document.getElementById("fx_dirblur_r4_fsh").textContent;
  909. effectLib.dirBlur = createEffectProgram(cmnvtxsrc, frgsrc, ['uBlurDir'], null);
  910.  
  911. //final composite
  912. vtxsrc = document.getElementById("pp_final_vsh").textContent;
  913. frgsrc = document.getElementById("pp_final_fsh").textContent;
  914. effectLib.finalComp = createEffectProgram(vtxsrc, frgsrc, ['uBloom'], null);
  915. }
  916.  
  917. // background
  918. function createBackground() {
  919. //console.log("create background");
  920. }
  921. function initBackground() {
  922. //console.log("init background");
  923. }
  924. function renderBackground() {
  925. gl.disable(gl.DEPTH_TEST);
  926.  
  927. useEffect(effectLib.sceneBg, null);
  928. gl.uniform2f(effectLib.sceneBg.program.uniforms.uTimes, timeInfo.elapsed, timeInfo.delta);
  929. drawEffect(effectLib.sceneBg);
  930. unuseEffect(effectLib.sceneBg);
  931.  
  932. gl.enable(gl.DEPTH_TEST);
  933. }
  934.  
  935. // post process
  936. var postProcess = {};
  937. function createPostProcess() {
  938. //console.log("create post process");
  939. }
  940. function initPostProcess() {
  941. //console.log("init post process");
  942. }
  943.  
  944. function renderPostProcess() {
  945. gl.enable(gl.TEXTURE_2D);
  946. gl.disable(gl.DEPTH_TEST);
  947. var bindRT = function (rt, isclear) {
  948. gl.bindFramebuffer(gl.FRAMEBUFFER, rt.frameBuffer);
  949. gl.viewport(0, 0, rt.width, rt.height);
  950. if(isclear) {
  951. gl.clearColor(0, 0, 0, 0);
  952. gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
  953. }
  954. };
  955.  
  956. //make bright buff
  957. bindRT(renderSpec.wHalfRT0, true);
  958. useEffect(effectLib.mkBrightBuf, renderSpec.mainRT);
  959. drawEffect(effectLib.mkBrightBuf);
  960. unuseEffect(effectLib.mkBrightBuf);
  961.  
  962. // make bloom
  963. for(var i = 0; i < 2; i++) {
  964. var p = 1.5 + 1 * i;
  965. var s = 2.0 + 1 * i;
  966. bindRT(renderSpec.wHalfRT1, true);
  967. useEffect(effectLib.dirBlur, renderSpec.wHalfRT0);
  968. gl.uniform4f(effectLib.dirBlur.program.uniforms.uBlurDir, p, 0.0, s, 0.0);
  969. drawEffect(effectLib.dirBlur);
  970. unuseEffect(effectLib.dirBlur);
  971.  
  972. bindRT(renderSpec.wHalfRT0, true);
  973. useEffect(effectLib.dirBlur, renderSpec.wHalfRT1);
  974. gl.uniform4f(effectLib.dirBlur.program.uniforms.uBlurDir, 0.0, p, 0.0, s);
  975. drawEffect(effectLib.dirBlur);
  976. unuseEffect(effectLib.dirBlur);
  977. }
  978.  
  979. //display
  980. gl.bindFramebuffer(gl.FRAMEBUFFER, null);
  981. gl.viewport(0, 0, renderSpec.width, renderSpec.height);
  982. gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
  983.  
  984. useEffect(effectLib.finalComp, renderSpec.mainRT);
  985. gl.uniform1i(effectLib.finalComp.program.uniforms.uBloom, 1);
  986. gl.activeTexture(gl.TEXTURE1);
  987. gl.bindTexture(gl.TEXTURE_2D, renderSpec.wHalfRT0.texture);
  988. drawEffect(effectLib.finalComp);
  989. unuseEffect(effectLib.finalComp);
  990.  
  991. gl.enable(gl.DEPTH_TEST);
  992. }
  993.  
  994. /////
  995. var SceneEnv = {};
  996. function createScene() {
  997. createEffectLib();
  998. createBackground();
  999. createPointFlowers();
  1000. createPostProcess();
  1001. sceneStandBy = true;
  1002. }
  1003.  
  1004. function initScene() {
  1005. initBackground();
  1006. initPointFlowers();
  1007. initPostProcess();
  1008.  
  1009. //camera.position.z = 17.320508;
  1010. camera.position.z = pointFlower.area.z + projection.nearfar[0];
  1011. projection.angle = Math.atan2(pointFlower.area.y, camera.position.z + pointFlower.area.z) * 180.0 / Math.PI * 2.0;
  1012. Matrix44.loadProjection(projection.matrix, renderSpec.aspect, projection.angle, projection.nearfar[0], projection.nearfar[1]);
  1013. }
  1014.  
  1015. function renderScene() {
  1016. //draw
  1017. Matrix44.loadLookAt(camera.matrix, camera.position, camera.lookat, camera.up);
  1018.  
  1019. gl.enable(gl.DEPTH_TEST);
  1020.  
  1021. //gl.bindFramebuffer(gl.FRAMEBUFFER, null);
  1022. gl.bindFramebuffer(gl.FRAMEBUFFER, renderSpec.mainRT.frameBuffer);
  1023. gl.viewport(0, 0, renderSpec.mainRT.width, renderSpec.mainRT.height);
  1024. gl.clearColor(0.005, 0, 0.05, 0);
  1025. gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
  1026.  
  1027. renderBackground();
  1028. renderPointFlowers();
  1029. renderPostProcess();
  1030. }
  1031.  
  1032. /////
  1033. function onResize(e) {
  1034. makeCanvasFullScreen(document.getElementById("sakura"));
  1035. setViewports();
  1036. if(sceneStandBy) {
  1037. initScene();
  1038. }
  1039. }
  1040.  
  1041. function setViewports() {
  1042. renderSpec.setSize(gl.canvas.width, gl.canvas.height);
  1043.  
  1044. gl.clearColor(0.2, 0.2, 0.5, 1.0);
  1045. gl.viewport(0, 0, renderSpec.width, renderSpec.height);
  1046.  
  1047. var rtfunc = function (rtname, rtw, rth) {
  1048. var rt = renderSpec[rtname];
  1049. if(rt) deleteRenderTarget(rt);
  1050. renderSpec[rtname] = createRenderTarget(rtw, rth);
  1051. };
  1052. rtfunc('mainRT', renderSpec.width, renderSpec.height);
  1053. rtfunc('wFullRT0', renderSpec.width, renderSpec.height);
  1054. rtfunc('wFullRT1', renderSpec.width, renderSpec.height);
  1055. rtfunc('wHalfRT0', renderSpec.halfWidth, renderSpec.halfHeight);
  1056. rtfunc('wHalfRT1', renderSpec.halfWidth, renderSpec.halfHeight);
  1057. }
  1058.  
  1059. function render() {
  1060. renderScene();
  1061. }
  1062.  
  1063. var animating = true;
  1064. function toggleAnimation(elm) {
  1065. animating ^= true;
  1066. if(animating) animate();
  1067. if(elm) {
  1068. elm.innerHTML = animating? "Stop":"Start";
  1069. }
  1070. }
  1071.  
  1072. function stepAnimation() {
  1073. if(!animating) animate();
  1074. }
  1075.  
  1076. function animate() {
  1077. var curdate = new Date();
  1078. timeInfo.elapsed = (curdate - timeInfo.start) / 1000.0;
  1079. timeInfo.delta = (curdate - timeInfo.prev) / 1000.0;
  1080. timeInfo.prev = curdate;
  1081.  
  1082. if(animating) requestAnimationFrame(animate);
  1083. render();
  1084. }
  1085.  
  1086. function makeCanvasFullScreen(canvas) {
  1087. var b = document.body;
  1088. var d = document.documentElement;
  1089. fullw = Math.max(b.clientWidth , b.scrollWidth, d.scrollWidth, d.clientWidth);
  1090. fullh = Math.max(b.clientHeight , b.scrollHeight, d.scrollHeight, d.clientHeight);
  1091. canvas.width = fullw;
  1092. canvas.height = fullh;
  1093. }
  1094.  
  1095. window.addEventListener('load', function(e) {
  1096. var canvas = document.getElementById("sakura");
  1097. try {
  1098. makeCanvasFullScreen(canvas);
  1099. gl = canvas.getContext('experimental-webgl');
  1100. } catch(e) {
  1101. alert("WebGL not supported." + e);
  1102. console.error(e);
  1103. return;
  1104. }
  1105.  
  1106. window.addEventListener('resize', onResize);
  1107.  
  1108. setViewports();
  1109. createScene();
  1110. initScene();
  1111.  
  1112. timeInfo.start = new Date();
  1113. timeInfo.prev = timeInfo.start;
  1114. animate();
  1115. });
  1116.  
  1117. //set window.requestAnimationFrame
  1118. (function (w, r) {
  1119. w['r'+r] = w['r'+r] || w['webkitR'+r] || w['mozR'+r] || w['msR'+r] || w['oR'+r] || function(c){ w.setTimeout(c, 1000 / 60); };
  1120. })(window, 'equestAnimationFrame');
  1121. </script>
  1122. </html>

 

本文地址:https://www.xiaoyaogzs.com/1218.html
关注我们:请关注一下我们的微信公众号:扫描二维码小姚工作室的公众号,公众号:小姚户外
版权声明:本文为原创文章,版权归 小姚 所有,欢迎分享本文,转载请保留出处!

发表评论


表情

  1. 今日新闻
    今日新闻 @回复

    文章不错支持一下吧

  2. 青衫慧博客
    青衫慧博客 @回复

    这效果还不错。试试 [赞]