news 2026/4/18 11:22:40

【3D圣诞树[特殊字符]】HTML代码实现

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
【3D圣诞树[特殊字符]】HTML代码实现

这是之前的文章:3D动态圣诞树代码
优化:
1、增加圣诞树顶端五角星⭐️;
2、增加“树木”亮度。

<!DOCTYPEhtml><htmllang="zh-CN"><head><metacharset="UTF-8"><metaname="viewport"content="width=device-width, initial-scale=1.0"><title>3D圣诞树</title><style>*{box-sizing:border-box;}body{margin:0;height:100vh;overflow:hidden;display:flex;align-items:center;justify-content:center;background:#161616;color:#c5a880;font-family:sans-serif;}</style></head><body><scriptsrc="https://cdn.jsdelivr.net/npm/three@0.115.0/build/three.min.js"></script><scriptsrc="https://cdn.jsdelivr.net/npm/three@0.115.0/examples/js/postprocessing/EffectComposer.js"></script><scriptsrc="https://cdn.jsdelivr.net/npm/three@0.115.0/examples/js/postprocessing/RenderPass.js"></script><scriptsrc="https://cdn.jsdelivr.net/npm/three@0.115.0/examples/js/postprocessing/ShaderPass.js"></script><scriptsrc="https://cdn.jsdelivr.net/npm/three@0.115.0/examples/js/shaders/CopyShader.js"></script><scriptsrc="https://cdn.jsdelivr.net/npm/three@0.115.0/examples/js/shaders/LuminosityHighPassShader.js"></script><scriptsrc="https://cdn.jsdelivr.net/npm/three@0.115.0/examples/js/postprocessing/UnrealBloomPass.js"></script><script>const{PI,sin,cos}=Math;constTAU=2*PI;// 工具函数constmap=(value,sMin,sMax,dMin,dMax)=>{returndMin+((value-sMin)/(sMax-sMin))*(dMax-dMin);};constrange=(n,m=0)=>Array(n).fill(m).map((i,j)=>i+j);constrand=(max,min=0)=>min+Math.random()*(max-min);constrandInt=(max,min=0)=>Math.floor(min+Math.random()*(max-min));constrandChoise=(arr)=>arr[randInt(arr.length)];constpolar=(ang,r=1)=>[r*cos(ang),r*sin(ang)];// 全局变量letscene,camera,renderer;letstep=0;constuniforms={time:{type:"f",value:0.0},step:{type:"f",value:0.0},};constparams={exposure:0.6,bloomStrength:0.4,bloomThreshold:0.2,bloomRadius:0.2,};letcomposer;consttotalPoints=4000;// 页面加载完成后直接初始化window.addEventListener('DOMContentLoaded',()=>{init();});// 初始化函数functioninit(){// 创建场景scene=newTHREE.Scene();scene.fog=newTHREE.Fog(0x0a0a0a,20,100);// 创建渲染器renderer=newTHREE.WebGLRenderer({antialias:true});renderer.setPixelRatio(window.devicePixelRatio);renderer.setSize(window.innerWidth,window.innerHeight);renderer.setClearColor(0x0a0a0a);document.body.appendChild(renderer.domElement);// 创建相机camera=newTHREE.PerspectiveCamera(60,window.innerWidth/window.innerHeight,1,1000);camera.position.set(0,-2,25);camera.rotation.set(0.1,0,0);// 稍微向下看,能更好地看到树顶// 移除音频相关代码,只保留基本功能// 添加场景元素addGround(scene,uniforms);addSnow(scene,uniforms);addChristmasTree(scene,uniforms,totalPoints,[0,0,0]);// 后期处理constrenderScene=newTHREE.RenderPass(scene,camera);constbloomPass=newTHREE.UnrealBloomPass(newTHREE.Vector2(window.innerWidth,window.innerHeight),1.5,0.4,0.85);bloomPass.threshold=params.bloomThreshold;bloomPass.strength=params.bloomStrength;bloomPass.radius=params.bloomRadius;composer=newTHREE.EffectComposer(renderer);composer.addPass(renderScene);composer.addPass(bloomPass);// 添加事件监听器addEventListeners();animate();}// 动画循环functionanimate(time){step=(step+1)%1000;uniforms.time.value=time;uniforms.step.value=step;// 旋转主圣诞树consttree=scene.children.find(child=>child.name==='mainTree');if(tree){tree.rotation.y+=0.005;}// 为SVG五角星添加动态效果conststar=scene.children.find(child=>child.name==='treeStar');if(star){// 缓慢旋转star.rotation.z+=0.008;// 闪烁效果star.material.opacity=0.85+0.15*Math.sin(time*0.005);}composer.render();requestAnimationFrame(animate);}// 添加圣诞树functionaddChristmasTree(scene,uniforms,totalPoints,treePosition,scale=1){// 顶点着色器constvertexShader=`attribute float mIndex; varying vec3 vColor; varying float opacity; float norm(float value, float min, float max ){ return (value - min) / (max - min); } float lerp(float norm, float min, float max){ return (max - min) * norm + min; } float map(float value, float sourceMin, float sourceMax, float destMin, float destMax){ return lerp(norm(value, sourceMin, sourceMax), destMin, destMax); } void main() { vColor = color; vec3 p = position; // 移除音频可视化效果,使用固定点大小 vec4 mvPosition = modelViewMatrix * vec4(p, 1.0); float sizeMapped = 4.0; // 进一步减小点大小以降低亮度 // 根据距离设置透明度 opacity = map(mvPosition.z, -200.0, 15.0, 0.0, 1.0); // 设置点大小 gl_PointSize = sizeMapped * (100.0 / -mvPosition.z); gl_Position = projectionMatrix * mvPosition; }`;// 片段着色器constfragmentShader=`varying vec3 vColor; varying float opacity; uniform sampler2D pointTexture; void main() { gl_FragColor = vec4(vColor, opacity); gl_FragColor = gl_FragColor * texture2D(pointTexture, gl_PointCoord); }`;// 创建材质constshaderMaterial=newTHREE.ShaderMaterial({uniforms:{...uniforms,pointTexture:{value:newTHREE.TextureLoader().load(`https://assets.codepen.io/3685267/spark1.png`),},},vertexShader,fragmentShader,blending:THREE.AdditiveBlending,depthTest:false,transparent:true,vertexColors:true,});// 创建几何体constgeometry=newTHREE.BufferGeometry();constpositions=[];constcolors=[];constsizes=[];constphases=[];constmIndexs=[];constcolor=newTHREE.Color();// 生成圣诞树形状的粒子for(leti=0;i<totalPoints;i++){constt=Math.random();consty=map(t,0,1,-8,10)*scale;constang=map(t,0,1,0,6*TAU)+(TAU/2)*(i%2);constradius=map(t,0,1,5,0)*scale;const[z,x]=polar(ang,radius);constmodifier=map(t,0,1,1,0);positions.push(x+rand(-0.3*modifier,0.3*modifier)*scale);positions.push(y+rand(-0.3*modifier,0.3*modifier)*scale);positions.push(z+rand(-0.3*modifier,0.3*modifier)*scale);// 圣诞树颜色:大部分为绿色系,随机添加红色小光球点缀lethue,saturation,lightness;if(Math.random()<0.05){// 5%的概率生成红色小光球hue=0.0;// 红色saturation=1.0;// 高饱和度lightness=0.3;// 适中亮度}else{// 其余95%保持绿色系hue=map(t,0,1,0.2,0.35);// 绿色到深绿色saturation=0.7;lightness=0.1;// 进一步降低饱和度和亮度}color.setHSL(hue,saturation,lightness);colors.push(color.r,color.g,color.b);phases.push(rand(1000));sizes.push(1);constmIndex=map(i,0,totalPoints,1.0,0.0);mIndexs.push(mIndex);}// 设置几何体属性geometry.setAttribute("position",newTHREE.Float32BufferAttribute(positions,3).setUsage(THREE.DynamicDrawUsage));geometry.setAttribute("color",newTHREE.Float32BufferAttribute(colors,3));geometry.setAttribute("size",newTHREE.Float32BufferAttribute(sizes,1));geometry.setAttribute("phase",newTHREE.Float32BufferAttribute(phases,1));geometry.setAttribute("mIndex",newTHREE.Float32BufferAttribute(mIndexs,1));// 创建粒子系统consttree=newTHREE.Points(geometry,shaderMaterial);tree.name=treePosition[0]===0&&treePosition[2]===0?'mainTree':'tree';// 设置位置const[px,py,pz]=treePosition;tree.position.set(px,py,pz);// 添加到场景scene.add(tree);// 在圣诞树顶端添加SVG五角星addSvgStar(scene,treePosition,scale);}// 添加Canvas绘制的五角星functionaddSvgStar(scene,position,scale=1){// 使用Canvas绘制五角星constcreateStarCanvas=()=>{constcanvas=document.createElement('canvas');canvas.width=128;canvas.height=128;constctx=canvas.getContext('2d');// 绘制五角星ctx.fillStyle='#FFD700';// 金色填充ctx.strokeStyle='#FFA500';// 橙色边框ctx.lineWidth=2;// 计算五角星顶点constcenterX=canvas.width/2;constcenterY=canvas.height/2;constradius1=50;// 外半径constradius2=25;// 内半径ctx.beginPath();for(leti=0;i<5;i++){constangle1=(i*Math.PI*2/5)-Math.PI/2;constx1=centerX+Math.cos(angle1)*radius1;consty1=centerY+Math.sin(angle1)*radius1;constangle2=((i+0.5)*Math.PI*2/5)-Math.PI/2;constx2=centerX+Math.cos(angle2)*radius2;consty2=centerY+Math.sin(angle2)*radius2;if(i===0){ctx.moveTo(x1,y1);}else{ctx.lineTo(x1,y1);}ctx.lineTo(x2,y2);}ctx.closePath();ctx.fill();ctx.stroke();returncanvas;};// 从Canvas创建纹理conststarCanvas=createStarCanvas();conststarTexture=newTHREE.CanvasTexture(starCanvas);// 创建精灵材质conststarMaterial=newTHREE.SpriteMaterial({map:starTexture,transparent:true,opacity:1.0,blending:THREE.AdditiveBlending,// 增加发光效果depthTest:false,// 禁用深度测试,确保五角星始终可见depthWrite:false// 不写入深度缓冲区});// 创建精灵conststar=newTHREE.Sprite(starMaterial);// 设置大小star.scale.set(2.5*scale,2.5*scale,1);// 增大五角星的大小,使其更明显// 设置位置在树顶const[x,y,z]=position;star.position.set(x,y+10.7*scale,z);star.name='treeStar';// 添加到场景scene.add(star);}// 添加雪花效果functionaddSnow(scene,uniforms){// 顶点着色器constvertexShader=`attribute float size; attribute float phase; attribute float phaseSecondary; varying vec3 vColor; varying float opacity; uniform float time; uniform float step; float norm(float value, float min, float max ){ return (value - min) / (max - min); } float lerp(float norm, float min, float max){ return (max - min) * norm + min; } float map(float value, float sourceMin, float sourceMax, float destMin, float destMax){ return lerp(norm(value, sourceMin, sourceMax), destMin, destMax); } void main() { float t = time * 0.0006; vColor = color; vec3 p = position; // 雪花飘落动画 p.y = map(mod(phase + step, 1000.0), 0.0, 1000.0, 25.0, -8.0); p.x += sin(t + phase) * 0.1; p.z += sin(t + phaseSecondary) * 0.1; // 根据距离设置透明度 opacity = map(p.z, -150.0, 15.0, 0.0, 1.0); vec4 mvPosition = modelViewMatrix * vec4(p, 1.0); gl_PointSize = size * (100.0 / -mvPosition.z); gl_Position = projectionMatrix * mvPosition; }`;// 片段着色器constfragmentShader=`uniform sampler2D pointTexture; varying vec3 vColor; varying float opacity; void main() { gl_FragColor = vec4(vColor, opacity); gl_FragColor = gl_FragColor * texture2D(pointTexture, gl_PointCoord); }`;// 创建雪花粒子集functioncreateSnowSet(sprite){consttotalPoints=300;constshaderMaterial=newTHREE.ShaderMaterial({uniforms:{...uniforms,pointTexture:{value:newTHREE.TextureLoader().load(sprite),},},vertexShader,fragmentShader,blending:THREE.AdditiveBlending,depthTest:false,transparent:true,vertexColors:true,});constgeometry=newTHREE.BufferGeometry();constpositions=[];constcolors=[];constsizes=[];constphases=[];constphaseSecondaries=[];constcolor=newTHREE.Color();// 生成雪花粒子for(leti=0;i<totalPoints;i++){const[x,y,z]=[rand(25,-25),0,rand(15,-150)];positions.push(x);positions.push(y);positions.push(z);// 雪花颜色color.set(randChoise(["#ffffff","#f0f8ff","#e6f3ff","#d9ecff"]));colors.push(color.r,color.g,color.b);phases.push(rand(1000));phaseSecondaries.push(rand(1000));sizes.push(rand(4,2));}// 设置几何体属性geometry.setAttribute("position",newTHREE.Float32BufferAttribute(positions,3));geometry.setAttribute("color",newTHREE.Float32BufferAttribute(colors,3));geometry.setAttribute("size",newTHREE.Float32BufferAttribute(sizes,1));geometry.setAttribute("phase",newTHREE.Float32BufferAttribute(phases,1));geometry.setAttribute("phaseSecondary",newTHREE.Float32BufferAttribute(phaseSecondaries,1));// 创建粒子系统constmesh=newTHREE.Points(geometry,shaderMaterial);scene.add(mesh);}// 不同形状的雪花纹理constsprites=["https://assets.codepen.io/3685267/snowflake1.png","https://assets.codepen.io/3685267/snowflake2.png","https://assets.codepen.io/3685267/snowflake3.png","https://assets.codepen.io/3685267/snowflake4.png","https://assets.codepen.io/3685267/snowflake5.png",];// 创建多个雪花粒子集sprites.forEach((sprite)=>{createSnowSet(sprite);});}// 添加地面functionaddGround(scene,uniforms){// 顶点着色器constvertexShader=`attribute float size; attribute vec3 customColor; varying vec3 vColor; void main() { vColor = customColor; vec4 mvPosition = modelViewMatrix * vec4(position, 1.0); gl_PointSize = size * (300.0 / -mvPosition.z); gl_Position = projectionMatrix * mvPosition; }`;// 片段着色器constfragmentShader=`uniform sampler2D pointTexture; varying vec3 vColor; void main() { gl_FragColor = vec4(vColor, 1.0); gl_FragColor = gl_FragColor * texture2D(pointTexture, gl_PointCoord); }`;// 创建材质constshaderMaterial=newTHREE.ShaderMaterial({uniforms:{...uniforms,pointTexture:{value:newTHREE.TextureLoader().load(`https://assets.codepen.io/3685267/spark1.png`),},},vertexShader,fragmentShader,blending:THREE.AdditiveBlending,depthTest:false,transparent:true,vertexColors:true,});// 创建几何体constgeometry=newTHREE.BufferGeometry();constpositions=[];constcolors=[];constsizes=[];constcolor=newTHREE.Color();// 生成地面粒子for(leti=0;i<3000;i++){const[x,y,z]=[rand(-25,25),0,rand(-150,15)];positions.push(x);positions.push(y-8);// 地面位置positions.push(z);// 地面颜色color.set(randChoise(["#2d5016","#3a621a","#4a7c1f","#5b9925"]));colors.push(color.r,color.g,color.b);sizes.push(1);}geometry.setAttribute("position",newTHREE.Float32BufferAttribute(positions,3).setUsage(THREE.DynamicDrawUsage));geometry.setAttribute("customColor",newTHREE.Float32BufferAttribute(colors,3));geometry.setAttribute("size",newTHREE.Float32BufferAttribute(sizes,1));// 创建粒子系统constplane=newTHREE.Points(geometry,shaderMaterial);scene.add(plane);}// 添加事件监听器functionaddEventListeners(){document.addEventListener("keydown",(e)=>{const{x,y,z}=camera.position;console.log(`camera.position.set(${x},${y},${z})`);const{x:a,y:b,z:c}=camera.rotation;console.log(`camera.rotation.set(${a},${b},${c})`);});// 窗口大小调整window.addEventListener("resize",()=>{constwidth=window.innerWidth;constheight=window.innerHeight;camera.aspect=width/height;camera.updateProjectionMatrix();renderer.setSize(width,height);composer.setSize(width,height);},false);}</script></body></html>
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/4/18 7:57:45

NVIDIA NeMo和NIM是用于开发和部署大模型

使用NVIDIA的NeMo和NIM开发大语言模型&#xff0c;主要涉及**模型训练/微调&#xff08;NeMo&#xff09;**和**模型部署与推理&#xff08;NIM&#xff09;**两大方向。一、核心工具定位 1. NeMo Framework 定位&#xff1a;用于训练和微调大语言模型的全栈框架包含数据预处理…

作者头像 李华
网站建设 2026/4/18 7:03:48

终极wired-elements手绘风格组件开发指南

终极wired-elements手绘风格组件开发指南 【免费下载链接】wired-elements 项目地址: https://gitcode.com/gh_mirrors/wir/wired-elements 想要为你的Web应用添加独特的手绘风格界面吗&#xff1f;wired-elements正是你需要的解决方案&#xff01;这是一个基于Web Com…

作者头像 李华
网站建设 2026/4/18 10:41:48

开拓者:正义之怒多职业兼职深度攻略

你是否曾在游戏中遇到这样的困境&#xff1a;明明选择了多个职业&#xff0c;却发现角色强度不升反降&#xff1f;或者看着复杂的职业树&#xff0c;不知道该在哪个等级转换&#xff1f;别担心&#xff0c;今天我们就来聊聊如何科学规划你的角色成长路线。 【免费下载链接】-Wo…

作者头像 李华
网站建设 2026/4/17 13:19:30

Mamba选择性状态空间:序列建模的下一代智能计算范式

Mamba选择性状态空间&#xff1a;序列建模的下一代智能计算范式 【免费下载链接】mamba 项目地址: https://gitcode.com/GitHub_Trending/ma/mamba 在人工智能技术快速演进的今天&#xff0c;序列建模领域正面临前所未有的计算瓶颈。传统RNN的串行计算如同单车道高速公…

作者头像 李华
网站建设 2026/4/12 23:23:04

AutoGPT代码生成与测试全流程自动化实践

AutoGPT代码生成与测试全流程自动化实践 在现代软件开发中&#xff0c;一个再熟悉不过的场景是&#xff1a;开发者花费数小时查阅文档、编写函数、设计测试用例&#xff0c;只为实现一个看似简单的功能——比如“写个快速排序并确保它能处理各种边界情况”。这个过程不仅重复性…

作者头像 李华
网站建设 2026/4/18 0:07:47

Tiled地图渲染引擎深度解析:从架构设计到性能优化的完整指南

Tiled地图渲染引擎深度解析&#xff1a;从架构设计到性能优化的完整指南 【免费下载链接】tiled 项目地址: https://gitcode.com/gh_mirrors/til/tiled Tiled地图编辑器作为业界领先的2D地图制作工具&#xff0c;其核心渲染引擎采用了高度模块化的设计理念&#xff0c;…

作者头像 李华