<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>HTML5 Three.js WebGL 悬浮的3D泡沫和方块</title>
<style>
body {
margin: 0;
}
</style>
</head>
<body>
<script src="js/three.r73.js"></script>
<!-- skybox shaders -->
<script type="application/x-glsl" id="sky-vertex">
varying vec2 vUV;
void main() {
vUV = uv;
vec4 pos = vec4(position, 1.0);
gl_Position = projectionMatrix * modelViewMatrix * pos;
}
</script>
<script type="application/x-glsl" id="sky-fragment">
uniform sampler2D texture;
varying vec2 vUV;
void main() {
vec4 sample = texture2D(texture, vUV);
gl_FragColor = vec4(sample.xyz, sample.w);
}
</script>
<!-- /skybox shaders -->
<!-- bubble shaders -->
<script type="x-shader/x-vertex" id="bubble-vertex">
uniform float mRefractionRatio;
uniform float mBias;
uniform float mScale;
uniform float mPower;
varying vec3 vReflect;
varying vec3 vRefract[3];
varying float vReflectionFactor;
void main() {
vec4 mvPosition = modelViewMatrix * vec4( position, 1.0 );
vec4 worldPosition = modelMatrix * vec4( position, 1.0 );
vec3 worldNormal = normalize( mat3( modelMatrix[0].xyz, modelMatrix[1].xyz, modelMatrix[2].xyz ) * normal );
vec3 I = worldPosition.xyz - cameraPosition;
vReflect = reflect( I, worldNormal );
vRefract[0] = refract( normalize( I ), worldNormal, mRefractionRatio );
vRefract[1] = refract( normalize( I ), worldNormal, mRefractionRatio * 0.99 );
vRefract[2] = refract( normalize( I ), worldNormal, mRefractionRatio * 0.98 );
vReflectionFactor = mBias + mScale * pow( 1.0 + dot( normalize( I ), worldNormal ), mPower );
gl_Position = projectionMatrix * mvPosition;
}
</script>
<script type="x-shader/x-fragment" id="bubble-fragment">
uniform samplerCube tCube;
varying vec3 vReflect;
varying vec3 vRefract[3];
varying float vReflectionFactor;
void main() {
vec4 reflectedColor = textureCube( tCube, vec3( -vReflect.x, vReflect.yz ) );
vec4 refractedColor = vec4( 1.0 );
refractedColor.r = textureCube( tCube, vec3( -vRefract[0].x, vRefract[0].yz ) ).r;
refractedColor.g = textureCube( tCube, vec3( -vRefract[1].x, vRefract[1].yz ) ).g;
refractedColor.b = textureCube( tCube, vec3( -vRefract[2].x, vRefract[2].yz ) ).b;
gl_FragColor = mix( refractedColor, reflectedColor, clamp( vReflectionFactor, 0.0, 1.0 ) );
}
</script>
<!-- /bubble shaders -->
<script src="js/THREEx.WindowResize.js"></script>
<script src="js/OrbitControls.js"></script>
<script src="js/Stats.js"></script>
<script>
var soap = {
scene: null,
camera: null,
renderer: null,
container: null,
controls: null,
clock: null,
stats: null,
bSphere: null,
bSphereCamera: null,
init: function() { // Initialization
// create main scene
this.scene = new THREE.Scene();
var SCREEN_WIDTH = window.innerWidth,
SCREEN_HEIGHT = window.innerHeight;
// prepare camera
var VIEW_ANGLE = 45,
ASPECT = SCREEN_WIDTH / SCREEN_HEIGHT,
NEAR = 1,
FAR = 1000;
this.camera = new THREE.PerspectiveCamera(VIEW_ANGLE, ASPECT, NEAR, FAR);
this.scene.add(this.camera);
this.camera.position.set(0, 0, 300);
this.camera.lookAt(new THREE.Vector3(0, 0, 0));
// prepare renderer
this.renderer = new THREE.WebGLRenderer({
antialias: true,
alpha: false
});
this.renderer.setSize(SCREEN_WIDTH, SCREEN_HEIGHT);
this.renderer.setClearColor(0xffffff);
this.renderer.shadowMapEnabled = true;
this.renderer.shadowMapSoft = true;
// prepare container
this.container = document.createElement('div');
document.body.appendChild(this.container);
this.container.appendChild(this.renderer.domElement);
// events
THREEx.WindowResize(this.renderer, this.camera);
// prepare controls (OrbitControls)
this.controls = new THREE.OrbitControls(this.camera, this.renderer.domElement);
this.controls.target = new THREE.Vector3(0, 0, 0);
this.controls.maxDistance = 700;
// prepare clock
this.clock = new THREE.Clock();
// prepare stats
this.stats = new Stats();
this.stats.domElement.style.position = 'absolute';
this.stats.domElement.style.left = '50px';
this.stats.domElement.style.bottom = '50px';
this.stats.domElement.style.zIndex = 1;
this.container.appendChild(this.stats.domElement);
// add point light
var spLight = new THREE.PointLight(0xffffff, 1.75, 1000);
spLight.position.set(-100, 200, 200);
this.scene.add(spLight);
// add simple cube
var cube = new THREE.Mesh(new THREE.CubeGeometry(40, 10, 40), new THREE.MeshLambertMaterial({
color: 0xff0000 * Math.random()
}));
cube.position.set(75, 0, 0);
this.scene.add(cube);
// add spherical skybox
this.drawSphericalSkybox();
// add bubble object
this.drawBubbleObject();
},
drawSphericalSkybox: function() {
// prepare ShaderMaterial
var uniforms = {
texture: {
type: 't',
value: THREE.ImageUtils.loadTexture('img/skybox.jpg')
}
};
var skyMaterial = new THREE.ShaderMaterial({
uniforms: uniforms,
vertexShader: document.getElementById('sky-vertex').textContent,
fragmentShader: document.getElementById('sky-fragment').textContent
});
// create Mesh with sphere geometry and add to the scene
var skyBox = new THREE.Mesh(new THREE.SphereGeometry(250, 160, 40), skyMaterial);
skyBox.scale.set(-1, 1, 1);
skyBox.eulerOrder = 'XZY';
skyBox.renderDepth = 500.0;
this.scene.add(skyBox);
},
drawBubbleObject: function() {
// create additional camera
this.bSphereCamera = new THREE.CubeCamera(0.1, 1000, 1000);
this.scene.add(this.bSphereCamera);
// prepare custom ShaderMaterial
var uniforms = {
"mRefractionRatio": {
type: "f",
value: 1.02
},
"mBias": {
type: "f",
value: 0.1
},
"mPower": {
type: "f",
value: 2.0
},
"mScale": {
type: "f",
value: 1.0
},
"tCube": {
type: "t",
value: this.bSphereCamera.renderTarget
} // textureCube }
};
// create custom material for the shader
var customMaterial = new THREE.ShaderMaterial({
uniforms: uniforms,
vertexShader: document.getElementById('bubble-vertex').textContent,
fragmentShader: document.getElementById('bubble-fragment').textContent
});
// create spherical mesh
this.bSphere = new THREE.Mesh(new THREE.SphereGeometry(50, 32, 32), customMaterial);
this.bSphere.position.set(-75, 0, 0);
this.scene.add(this.bSphere);
this.bSphereCamera.position = this.bSphere.position;
}
};
// Animate the scene
function animate() {
requestAnimationFrame(animate);
render();
update();
}
// Update controls and stats
function update() {
soap.controls.update(soap.clock.getDelta());
soap.stats.update();
}
// Render the scene
function render() {