WebGL太阳系
一、实验内容:
完成一个太阳系场景,其中至少有三个球体,一个表示太阳,一个表示地球,一个表示月亮;地球不停地绕太阳旋转,月亮绕地球旋转,星球本身有自转。可添加纹理,纹理自行从网络搜寻。画上星球运动的轨道线,并加上适当的光照效果。提交代码(如有纹理则需要提交纹理图片)和文档,要求简要说明功能点和实现方法;
评分标准:
- 星球的自转和公转运动准确;(30分)
- 光照效果合理;(30分)
- 场景丰富美观,可自由增加其他物体和光照,如飞船等;(20分)
- 编码规范,文档说明准确清楚;(20分)
二、实验说明:
所有实验是通过 Visual Studio Code引入p5.js包编写,所以首先要去p5.js官网下载相关包,或是在联网状态下把html中引入包的代码改成例如<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.1.9/p5.js"></script>等。
三、实验代码:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8"> <title>sun</title> <script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.4.0/p5.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.4.0/addons/p5.sound.js"></script> </head> <body> <script src="sketch.js"></script> </body> </html>
let x0 = 0, y0 = 0, z0 = 0,//初始化太阳坐标 x1 = 0, y1 = 0, z1 = 0,//初始化地球坐标 x2 = 0, y2 = 0, z2 = 0;//初始化月球坐标 let revolutionAngle = 20; // 公转角度 let rotationAngle = 0; // 自转角度 let revolutionRadius = 300; //公转半径 let sun, earth, moon; //加载贴图 let stars = []; // 繁星 let camX, camY, camZ = 700; // 视口照相机位置 function preload() { sun = loadImage("picture/sun.png"); earth = loadImage("picture/earth.png"); moon = loadImage("picture/moon.png"); sound = loadSound("sound/sound.mp3"); } function setup() { let cnv = createCanvas(windowWidth, windowHeight, WEBGL); cnv.mousePressed(canvasPressed);//点击鼠标事件播放声音 //创造繁星 for (let i = 0; i < 300; i++) { stars.push({ x: 0, y: 0, offset: Math.random() * 360, orbit: (Math.random() + 0.01) * max(width, height), radius: Math.random() * 2, vx: Math.floor(Math.random() * 10) - 5, vy: Math.floor(Math.random() * 10) - 5, }); } } function draw() { clear(); background(0); setLight(); drawSun(); drawEarth(); drawMoon(); drawStars(); // 照相机位置 camX = (mouseX - width / 2) / 10; camY = (mouseY - height / 2) / 10; camera(camX, camY-300 , camZ+1000, 0, 0, 0, 0, 1, 0); noStroke(); rotationAngle += 0.01; } function drawSun() { push(); translate(x0, x0, z0); fill(0, 255, 255); texture(sun); pointLight(255, 255, 255, 0, 0, 100000); rotateY(rotationAngle / 5); sphere(200); pop(); // 地球轨道 push(); translate(x0, y0, z0); rotateX((PI / 180) * 90); fill(240); torus(800, 0.7, 240); pop(); } function drawEarth() { x1 = x0 + 800 * cos(revolutionAngle); z1 = z0 + 800 * sin(revolutionAngle); push(); translate(x1, y1, z1); rotateY(rotationAngle); texture(earth); sphere(40); pop(); // 月球轨道 push(); translate(x1, y1, z1); rotateX((PI / 180) * 90); fill(240); torus(60, 0.7, 240); pop(); revolutionAngle += 0.005; } function drawMoon() { x2 = x1 + 60 * cos(revolutionAngle * 5); z2 = z1 + 60 * sin(revolutionAngle * 5); push(); translate(x2, y2, z2); rotateY(-rotationAngle); texture(moon); sphere(10); pop(); } function drawStars() { colorMode(RGB, 255, 255, 255, 1); for (let i = 0; i < stars.length; i++) { let s = stars[i]; push(); translate(s.x - width / 2, s.y - height / 3, -1000); sphere(5); pop(); } update(); } function update() { let originX = width / 2; let originY = height / 2; for (let i = 0; i < stars.length; i++) { let s = stars[i]; let rad = (frameCount * (1 / (s.orbit * 2 + s.offset)) + s.offset) % TAU; s.x = originX + cos(rad) * (s.orbit * 2); s.y = originY + sin(rad) * s.orbit; } } function setLight() { pointLight(255,255,255,0,0,0,500); // let dirX = -(mouseX - width / 2); // let dirY = -(mouseY - height / 2); ambientLight(0); //directionalLight(255, 255, 255, dirX, dirY, -250); } function mouseWheel(event) { if (event.deltaY > 0) { camZ += 10; } else { camZ -= 10; } } function canvasPressed() { if (sound.isPlaying()) { sound.pause(); } else { sound.play(); } }
四、实验结果:
编辑
编辑
编辑