更多有趣示例 尽在 知屋安砖社区
示例
HTML
<!--
Visit this project on GitHub at https://github.com/enesser/low-poly-clouds-webgl
-->
CSS
body {
background-color: #000;
color: #fff;
font: 14px "Lucida Grande", Helvetica, Arial, sans-serif;
margin: 0;
overflow: hidden;
padding: 0px;
position: relative;
}
a {
color: #00b7ff;
}
JS
'use strict';
/* global dat: true */
var LowPolyCloudWebGLDemo = LowPolyCloudWebGLDemo || {};
/**
* Create an instance of configurable settings for the demo.
* You can allow or disallow a GUI for these settings with the query string "ui=true/false", ie: http://localhost:3000?ui=false
* @return {object} Scene settings
*/
LowPolyCloudWebGLDemo.settings = function() {
/**
* Default sun color
* @type {String}
*/
const sunColor = '#fcd2a8',
/**
* Default sun intensity
* @type {Number}
*/
sunIntensity = 0.53,
/**
* Default ambient light color
* @type {String}
*/
ambientLight = '#8c8c8c',
/**
* Default sky color
* @type {String}
*/
skyColor = '#67b4e7',
/**
* Default show wireframe state for sky
* @type {Boolean}
*/
skyWireframe = false,
/**
* Default cloud color
* @type {String}
*/
cloudsColor = '#ffffff',
/**
* Default cloud opacity
* @type {Number}
*/
cloudsOpacity = 0.79,
/**
* Default show wireframe state for clouds
* @type {Boolean}
*/
cloudsWireframe = false,
/**
* Default cloud base velocity
* @type {Number}
*/
cloudsBaseVelocity = 0.008,
/**
* Project URL
* @type {String}
*/
homepage = 'https://github.com/enesser/low-poly-clouds-webgl';
let gui = new dat.GUI({
width: 360
});
gui.close();
/**
* Settings schema business object
* @type {Object}
*/
let settingsSchema = {
/**
* Reset settings to default
*/
reset: function() {
this.sunColor = sunColor;
this.sunIntensity = sunIntensity;
this.ambientLight = ambientLight;
this.skyColor = skyColor;
this.skyWireframe = skyWireframe;
this.cloudsColor = cloudsColor;
this.cloudsOpacity = cloudsOpacity;
this.cloudsWireframe = cloudsWireframe;
this.cloudsBaseVelocity = cloudsBaseVelocity;
for (let folder in gui.__folders) {
for (let i in gui.__folders[folder].__controllers) {
gui.__folders[folder].__controllers[i].updateDisplay();
}
}
},
/**
* Go to home page
*/
homepage: function() {
window.open(homepage, '_blank');
}
};
/**
* Bind settings schema object to dat.gui interface.
* @param {object} settingsSchema
*/
function bindSettingsSchemaToUi(settingsSchema) {
let sunFolder = gui.addFolder('Sun');
sunFolder.addColor(settingsSchema, 'sunColor');
sunFolder.add(settingsSchema, 'sunIntensity').min(-10).max(50);
sunFolder.addColor(settingsSchema, 'ambientLight');
let skyFolder = gui.addFolder('Sky');
skyFolder.addColor(settingsSchema, 'skyColor');
skyFolder.add(settingsSchema, 'skyWireframe');
let cloudsFolder = gui.addFolder('Clouds');
cloudsFolder.addColor(settingsSchema, 'cloudsColor');
cloudsFolder.add(settingsSchema, 'cloudsOpacity').min(0).max(1);
cloudsFolder.add(settingsSchema, 'cloudsWireframe');
cloudsFolder.add(settingsSchema, 'cloudsBaseVelocity').min(0).max(3);
gui.add(settingsSchema, 'reset');
gui.add(settingsSchema, 'homepage');
}
settingsSchema.reset();
bindSettingsSchemaToUi(settingsSchema);
return settingsSchema;
};
/* global console, THREE: true */
/**
* Create an instance of world, represents the ThreeJS model with meshes and materials.
* You can load high or low quality textures with the query string "quality=high/low", ie: http://localhost:3000?quality=low
* @return {object} world model
*/
LowPolyCloudWebGLDemo.world = function() {
const pathWorldModel = 'https://s3-us-west-2.amazonaws.com/s.cdpn.io/168282/low-poly-clouds.obj';
const pathWorldMaterial = 'https://s3-us-west-2.amazonaws.com/s.cdpn.io/168282/low-poly-clouds.mtl';
/**
* Represents the ThreeJS model of world with meshes and materials.
* @type {Object}
*/
let worldObject = {
/**
* Are textures and materials loaded yet?
* @type {Boolean}
*/
isLoaded: false,
/**
* Texture and materials loading progress
* @type {Number}
*/
percentLoaded: 0,
/**
* Sky background mesh
* @type {[type]}
*/
background: null,
/**
* Sky background material
* @type {[type]}
*/
backgroundMaterial: null,
/**
* Cloud material
* @type {[type]}
*/
cloudsMaterial: null,
/**
* Cloud meshes
* @type {Array}
*/
clouds: []
};
/**
* Load materials and textures, then map them to the object.
* @param {object} worldObject Target object to map.
*/
function mapMaterialsTexturesToObject(worldObject) {
let loader = new THREE.OBJMTLLoader();
loader.load(pathWorldModel, pathWorldMaterial, (o) => {
const cloudBaseSize = 1.8;
worldObject.clouds = [];
worldObject.background = o.children.find(child => child.name === 'Plane_Plane.003');
worldObject.background.receiveShadow = true;
worldObject.backgroundMaterial = worldObject.background.children[1].material;
worldObject.backgroundMaterial.depthWrite = false;
worldObject.backgroundMaterial.receiveShadow = true;
for (let cloudTemplate of[
o.children.find(child => child.name === 'Cloud2_Icosphere.011'),
o.children.find(child => child.name === 'Cloud1_Icosphere.005')
]) {
worldObject.cloudsMaterial = cloudTemplate.children[1].material;
cloudTemplate.position.setY(cloudTemplate.position.y - 10);
for (let i = 0; i < 8; i++) {
let cloud = cloudTemplate.clone();
//randomly size clouds
let cloudSize = cloudBaseSize + (Math.random() * 1.2);
cloud.scale.set(cloudSize, cloudSize, cloudSize);
//randomly place clouds
let posXFlip = (Math.floor(Math.random() * 2) + 1) % 2 === 0 ? 1 : -1;
let posYFlip = (Math.floor(Math.random() * 2) + 1) % 2 === 0 ? 1 : -1;
let posX = cloud.position.x + (Math.random() * 50);
let posY = posYFlip > 0 ? cloud.position.y + (Math.random() * 3) : cloud.position.y - (Math.random() * 3);
cloud.position.setX(posX * posXFlip);
cloud.position.setY(posY);
cloud.position.setZ(cloud.position.z + (Math.random() * 3));
//give cloud random velocity accelerator
cloud.velocityAccelerator = (Math.random() * 0.008);
//add cloud to the array
worldObject.clouds.push(cloud);
}
}
worldObject.cloudsMaterial.transparent = true;
worldObject.cloudsMaterial.depthWrite = false;
worldObject.isLoaded = true;
},
/**
* Successful load
* @param {object} xhr XmlHttpRequest
*/
(xhr) => {
if (xhr.lengthComputable) {
worldObject.percentLoaded = xhr.loaded / xhr.total * 100;
}
},
/**
* Error loading world materials and textures
* @param {object} xhr XmlHttpRequest
*/
(xhr) => {
console.error('Error loading world materials and textures', xhr);
});
}
mapMaterialsTexturesToObject(worldObject);
return worldObject;
};
/* global window, THREE: true */
/**
* Entry point for Low Poly Cloud WebGL Demo
* @param {object} window
*/
((window, document) => {
window.onload = () => {
let scene,
camera,
renderer,
directionalLightColor,
directionalLight,
ambientLightColor,
ambientLight,
settings,
world,
windowHalfX = window.innerWidth / 2,
windowHalfY = window.innerHeight / 2;
/**
* Initialize scene
*/
(function init() {
//setup scene and perspective camera with a fov of 45, a near plane at 1, and a far plane at 1000
scene = new THREE.Scene();
camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 1, 1000);
camera.position.set(0, 4, 64);
camera.lookAt(scene.position);
//setup renderer with antialiasing enabled
renderer = new THREE.WebGLRenderer({
antialias: true
});
renderer.setPixelRatio(window.devicePixelRatio);
renderer.setSize(window.innerWidth, window.innerHeight);
//add rendering div to the DOM
let container = document.createElement('div');
document.body.appendChild(container);
container.appendChild(renderer.domElement);
//create the sun
directionalLightColor = new THREE.Color();
directionalLight = new THREE.DirectionalLight(directionalLightColor);
directionalLight.position.set(-20, 9.7, 14);
scene.add(directionalLight);
//create ambient lighting
ambientLightColor = new THREE.Color();
ambientLight = new THREE.AmbientLight(ambientLightColor);
scene.add(ambientLight);
//import settings
settings = LowPolyCloudWebGLDemo.settings();
//import the world, but don't add it to the scene until the model is finished loading
world = LowPolyCloudWebGLDemo.world();
world.isAddedToScene = false;
//update renderer and camera aspect to the new size of the drawing area on window resize
window.addEventListener('resize', () => {
windowHalfX = window.innerWidth / 2;
windowHalfY = window.innerHeight / 2;
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize(window.innerWidth, window.innerHeight);
}, false);
})();
/**
* Render method, called each time a frame is rendered
*/
(function render() {
//update sun with settings
directionalLight.intensity = settings.sunIntensity;
directionalLightColor.setStyle(settings.sunColor);
directionalLight.color = directionalLightColor;
//update ambient lighting with settings
ambientLightColor.setStyle(settings.ambientLight);
ambientLight.color = ambientLightColor;
//when world model is fully loaded (including materials and textures)
if (world.isLoaded) {
//add the world to the scene only when it's fully loaded
if (!world.isAddedToScene) {
scene.add(world.background);
for (let cloud of world.clouds) {
scene.add(cloud);
}
world.isAddedToScene = true;
}
//adjust sky
world.backgroundMaterial.color.setStyle(settings.skyColor);
world.backgroundMaterial.wireframe = settings.skyWireframe;
//adjust clouds
world.cloudsMaterial.color.setStyle(settings.cloudsColor);
world.cloudsMaterial.opacity = settings.cloudsOpacity;
world.cloudsMaterial.wireframe = settings.cloudsWireframe;
//move clouds
for (let cloud of world.clouds) {
let newX = cloud.position.x + (settings.cloudsBaseVelocity + cloud.velocityAccelerator);
if (newX > 60) {
newX = -60;
}
cloud.position.setX(newX);
}
}
//render the scene and loop for next frame update
renderer.render(scene, camera);
requestAnimationFrame(render);
})();
};
})(window, document);