提交 d22bb22d 编写于 作者: M Mr.doob

Examples: Removed OculusControls/OculusRihtEffect. Use WebVR instead.

Builds for all OS now available:
https://drive.google.com/folderview?id=0BzudLt22BqGRbW9WTHMtOWMzNjQ#list
上级 36565aa8
......@@ -209,7 +209,6 @@
"webgl_custom_attributes_particles3",
"webgl_decals",
"webgl_effects_anaglyph",
"webgl_effects_oculusrift",
"webgl_effects_parallaxbarrier",
"webgl_effects_stereo",
"webgl_effects_vr",
......@@ -386,7 +385,6 @@
"misc_animation_keys",
"misc_controls_deviceorientation",
"misc_controls_fly",
"misc_controls_oculusrift",
"misc_controls_orbit",
"misc_controls_pointerlock",
"misc_controls_trackball",
......
/**
* @author possan / http://possan.se/
*
* Oculus headtracking control
* - use together with the oculus-rest project to get headtracking
* coordinates from the rift: http://github.com/possan/oculus-rest
*/
THREE.OculusControls = function ( object ) {
this.object = object;
this.target = new THREE.Vector3( 0, 0, 0 );
this.enabled = true;
this.headquat = new THREE.Quaternion();
this.loadAjaxJSON = function ( url, callback ) {
var xhr = new XMLHttpRequest();
xhr.onreadystatechange = function () {
if ( xhr.readyState === xhr.DONE ) {
if ( xhr.status === 200 || xhr.status === 0 ) {
if ( xhr.responseText ) {
var json = JSON.parse( xhr.responseText );
callback( json );
}
}
}
};
xhr.open( "GET", url, true );
xhr.withCredentials = false;
xhr.send( null );
};
this.gotCoordinates = function( r ) {
this.headquat.set(r.quat.x, r.quat.y, r.quat.z, r.quat.w);
this.queuePoll();
}
this.pollOnce = function() {
this.loadAjaxJSON('http://localhost:50000', bind(this, this.gotCoordinates));
}
this.queuePoll = function() {
setTimeout(bind(this, this.pollOnce), 10);
}
this.update = function( delta ) {
if ( this.enabled === false ) return;
this.object.quaternion.multiply(this.headquat);
};
function bind( scope, fn ) {
return function () {
fn.apply( scope, arguments );
};
};
this.connect = function() {
this.queuePoll();
};
};
/**
* @author troffmo5 / http://github.com/troffmo5
*
* Effect to render the scene in stereo 3d side by side with lens distortion.
* It is written to be used with the Oculus Rift (http://www.oculusvr.com/) but
* it works also with other HMD using the same technology
*/
THREE.OculusRiftEffect = function ( renderer, options ) {
// worldFactor indicates how many units is 1 meter
var worldFactor = (options && options.worldFactor) ? options.worldFactor: 1.0;
// Specific HMD parameters
var HMD = (options && options.HMD) ? options.HMD: {
// DK1
/*
hResolution: 1280,
vResolution: 800,
hScreenSize: 0.14976,
vScreenSize: 0.0936,
interpupillaryDistance: 0.064,
lensSeparationDistance: 0.064,
eyeToScreenDistance: 0.041,
distortionK : [1.0, 0.22, 0.24, 0.0],
chromaAbParameter: [ 0.996, -0.004, 1.014, 0.0]
*/
// DK2
hResolution: 1920,
vResolution: 1080,
hScreenSize: 0.12576,
vScreenSize: 0.07074,
interpupillaryDistance: 0.0635,
lensSeparationDistance: 0.0635,
eyeToScreenDistance: 0.041,
distortionK : [1.0, 0.22, 0.24, 0.0],
chromaAbParameter: [ 0.996, -0.004, 1.014, 0.0]
};
this.HMD = HMD;
// Perspective camera
var pCamera = new THREE.PerspectiveCamera();
pCamera.matrixAutoUpdate = false;
pCamera.target = new THREE.Vector3();
// Orthographic camera
var oCamera = new THREE.OrthographicCamera( -1, 1, 1, -1, 1, 1000 );
oCamera.position.z = 1;
// pre-render hooks
this.preLeftRender = function() {};
this.preRightRender = function() {};
renderer.autoClear = false;
var emptyColor = new THREE.Color("black");
// Render target
var RTParams = { minFilter: THREE.LinearFilter, magFilter: THREE.NearestFilter, format: THREE.RGBAFormat };
var renderTarget = new THREE.WebGLRenderTarget( 640, 800, RTParams );
var RTMaterial = new THREE.ShaderMaterial( {
uniforms: {
"texid": { type: "t", value: renderTarget },
"scale": { type: "v2", value: new THREE.Vector2(1.0,1.0) },
"scaleIn": { type: "v2", value: new THREE.Vector2(1.0,1.0) },
"lensCenter": { type: "v2", value: new THREE.Vector2(0.0,0.0) },
"hmdWarpParam": { type: "v4", value: new THREE.Vector4(1.0,0.0,0.0,0.0) },
"chromAbParam": { type: "v4", value: new THREE.Vector4(1.0,0.0,0.0,0.0) }
},
vertexShader: [
"varying vec2 vUv;",
"void main() {",
" vUv = uv;",
" gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );",
"}"
].join("\n"),
fragmentShader: [
"uniform vec2 scale;",
"uniform vec2 scaleIn;",
"uniform vec2 lensCenter;",
"uniform vec4 hmdWarpParam;",
'uniform vec4 chromAbParam;',
"uniform sampler2D texid;",
"varying vec2 vUv;",
"void main()",
"{",
" vec2 uv = (vUv*2.0)-1.0;", // range from [0,1] to [-1,1]
" vec2 theta = (uv-lensCenter)*scaleIn;",
" float rSq = theta.x*theta.x + theta.y*theta.y;",
" vec2 rvector = theta*(hmdWarpParam.x + hmdWarpParam.y*rSq + hmdWarpParam.z*rSq*rSq + hmdWarpParam.w*rSq*rSq*rSq);",
' vec2 rBlue = rvector * (chromAbParam.z + chromAbParam.w * rSq);',
" vec2 tcBlue = (lensCenter + scale * rBlue);",
" tcBlue = (tcBlue+1.0)/2.0;", // range from [-1,1] to [0,1]
" if (any(bvec2(clamp(tcBlue, vec2(0.0,0.0), vec2(1.0,1.0))-tcBlue))) {",
" gl_FragColor = vec4(0.0, 0.0, 0.0, 1.0);",
" return;}",
" vec2 tcGreen = lensCenter + scale * rvector;",
" tcGreen = (tcGreen+1.0)/2.0;", // range from [-1,1] to [0,1]
" vec2 rRed = rvector * (chromAbParam.x + chromAbParam.y * rSq);",
" vec2 tcRed = lensCenter + scale * rRed;",
" tcRed = (tcRed+1.0)/2.0;", // range from [-1,1] to [0,1]
" gl_FragColor = vec4(texture2D(texid, tcRed).r, texture2D(texid, tcGreen).g, texture2D(texid, tcBlue).b, 1);",
"}"
].join("\n")
} );
var mesh = new THREE.Mesh( new THREE.PlaneBufferGeometry( 2, 2 ), RTMaterial );
// Final scene
var finalScene = new THREE.Scene();
finalScene.add( oCamera );
finalScene.add( mesh );
var left = {}, right = {};
var distScale = 1.0;
this.setHMD = function(v) {
HMD = v;
// Compute aspect ratio and FOV
var aspect = HMD.hResolution / (2*HMD.vResolution);
// Fov is normally computed with:
// THREE.Math.radToDeg( 2*Math.atan2(HMD.vScreenSize,2*HMD.eyeToScreenDistance) );
// But with lens distortion it is increased (see Oculus SDK Documentation)
var r = -1.0 - (4 * (HMD.hScreenSize/4 - HMD.lensSeparationDistance/2) / HMD.hScreenSize);
distScale = (HMD.distortionK[0] + HMD.distortionK[1] * Math.pow(r,2) + HMD.distortionK[2] * Math.pow(r,4) + HMD.distortionK[3] * Math.pow(r,6));
var fov = THREE.Math.radToDeg(2*Math.atan2(HMD.vScreenSize*distScale, 2*HMD.eyeToScreenDistance));
// Compute camera projection matrices
var proj = (new THREE.Matrix4()).makePerspective( fov, aspect, 0.3, 10000 );
var h = 4 * (HMD.hScreenSize/4 - HMD.interpupillaryDistance/2) / HMD.hScreenSize;
left.proj = ((new THREE.Matrix4()).makeTranslation( h, 0.0, 0.0 )).multiply(proj);
right.proj = ((new THREE.Matrix4()).makeTranslation( -h, 0.0, 0.0 )).multiply(proj);
// Compute camera transformation matrices
left.tranform = (new THREE.Matrix4()).makeTranslation( -worldFactor * HMD.interpupillaryDistance/2, 0.0, 0.0 );
right.tranform = (new THREE.Matrix4()).makeTranslation( worldFactor * HMD.interpupillaryDistance/2, 0.0, 0.0 );
// Compute Viewport
left.viewport = [0, 0, HMD.hResolution/2, HMD.vResolution];
right.viewport = [HMD.hResolution/2, 0, HMD.hResolution/2, HMD.vResolution];
// Distortion shader parameters
var lensShift = 4 * (HMD.hScreenSize/4 - HMD.lensSeparationDistance/2) / HMD.hScreenSize;
left.lensCenter = new THREE.Vector2(lensShift, 0.0);
right.lensCenter = new THREE.Vector2(-lensShift, 0.0);
RTMaterial.uniforms['hmdWarpParam'].value = new THREE.Vector4(HMD.distortionK[0], HMD.distortionK[1], HMD.distortionK[2], HMD.distortionK[3]);
RTMaterial.uniforms['chromAbParam'].value = new THREE.Vector4(HMD.chromaAbParameter[0], HMD.chromaAbParameter[1], HMD.chromaAbParameter[2], HMD.chromaAbParameter[3]);
RTMaterial.uniforms['scaleIn'].value = new THREE.Vector2(1.0,1.0/aspect);
RTMaterial.uniforms['scale'].value = new THREE.Vector2(1.0/distScale, 1.0*aspect/distScale);
// Create render target
if ( renderTarget ) renderTarget.dispose();
renderTarget = new THREE.WebGLRenderTarget( HMD.hResolution * distScale / 2, HMD.vResolution * distScale, RTParams );
RTMaterial.uniforms[ "texid" ].value = renderTarget;
}
this.getHMD = function() {return HMD};
this.setHMD(HMD);
this.setSize = function ( width, height ) {
left.viewport = [width/2 - HMD.hResolution/2, height/2 - HMD.vResolution/2, HMD.hResolution/2, HMD.vResolution];
right.viewport = [width/2, height/2 - HMD.vResolution/2, HMD.hResolution/2, HMD.vResolution];
renderer.setSize( width, height );
};
this.render = function ( scene, camera ) {
var cc = renderer.getClearColor().clone();
// Clear
renderer.setClearColor(emptyColor);
renderer.clear();
renderer.setClearColor(cc);
// camera parameters
if (camera.matrixAutoUpdate) camera.updateMatrix();
// Render left
this.preLeftRender();
pCamera.projectionMatrix.copy(left.proj);
pCamera.matrix.copy(camera.matrix).multiply(left.tranform);
pCamera.matrixWorldNeedsUpdate = true;
renderer.setViewport(left.viewport[0], left.viewport[1], left.viewport[2], left.viewport[3]);
RTMaterial.uniforms['lensCenter'].value = left.lensCenter;
renderer.render( scene, pCamera, renderTarget, true );
renderer.render( finalScene, oCamera );
// Render right
this.preRightRender();
pCamera.projectionMatrix.copy(right.proj);
pCamera.matrix.copy(camera.matrix).multiply(right.tranform);
pCamera.matrixWorldNeedsUpdate = true;
renderer.setViewport(right.viewport[0], right.viewport[1], right.viewport[2], right.viewport[3]);
RTMaterial.uniforms['lensCenter'].value = right.lensCenter;
renderer.render( scene, pCamera, renderTarget, true );
renderer.render( finalScene, oCamera );
};
this.dispose = function() {
if ( RTMaterial ) {
RTMaterial.dispose();
}
if ( renderTarget ) {
renderTarget.dispose();
}
};
};
<!DOCTYPE html>
<html lang="en">
<head>
<title>three.js webgl - controls - oculus rift</title>
<meta charset="utf-8">
<style>
body {
margin: 0px;
background-color: #000000;
overflow: hidden;
}
#info {
position: absolute;
top: 0px; width: 100%;
color: #ffffff;
padding: 5px;
font-family:Monospace;
font-size:13px;
font-weight: bold;
text-align:center;
}
a {
color: #ff8800;
}
</style>
</head>
<body>
<div id="info">
<a href="http://threejs.org" target="_blank">three.js</a> - headtracking demo for oculus rift. requires <a href="https://github.com/possan/oculus-rest/" target="_blank">oculus-rest</a> to get headtracking coordinates working.<br />
(left click: forward, a/s/w/d/r/f: move, h: hide text)
</div>
<script src="../build/three.min.js"></script>
<script src="js/ImprovedNoise.js"></script>
<script src="js/effects/OculusRiftEffect.js"></script>
<script src="js/controls/FirstPersonControls.js"></script>
<script src="js/controls/OculusControls.js"></script>
<script>
var camera, scene, renderer;
var realcamera;
var guiVisible = true;
var mesh, effect, controls, oculuscontrol;
var meshes = [];
var meshparent = [];
var meshparent2 = [];
var cols = 50;
var rows = 30;
var tot = cols * rows;
var clock = new THREE.Clock();
var perlin;
init();
animate();
function init() {
renderer = new THREE.WebGLRenderer();
renderer.setPixelRatio( window.devicePixelRatio );
renderer.setSize( window.innerWidth, window.innerHeight );
perlin = new ImprovedNoise();
camera = new THREE.PerspectiveCamera( 90, window.innerWidth / window.innerHeight, 1, 5000 );
camera.position.x = 200;
camera.position.y = 250;
camera.position.z = -200;
scene = new THREE.Scene();
effect = new THREE.OculusRiftEffect( renderer, { worldScale: 1 } );
effect.setSize( window.innerWidth, window.innerHeight );
controls = new THREE.FirstPersonControls( camera );
controls.movementSpeed = 4000;
controls.lookSpeed = 3.0;
controls.lookVertical = true;
oculuscontrol = new THREE.OculusControls( camera );
document.body.appendChild( renderer.domElement );
var hemiLight = new THREE.HemisphereLight( 0xffffff, 0xffffff, 0.6 );
hemiLight.color.setHSL( 0.6, 1, 0.6 );
hemiLight.groundColor.setHSL( 0.095, 1, 0.75 );
hemiLight.position.set( 0, 500, 0 );
scene.add( hemiLight );
var geometry = new THREE.BoxGeometry( 100, 100, 200 );
var texture = THREE.ImageUtils.loadTexture( 'textures/crate.gif' );
texture.anisotropy = renderer.getMaxAnisotropy();
var material = new THREE.MeshPhongMaterial( { color: 0xffffff, specular: 0xffffff, shininess: 20, shading: THREE.FlatShading, map: texture } );
for (var i=0; i<tot; i++) {
meshparent2[i] = new THREE.Object3D();
scene.add( meshparent2[i] );
meshparent[i] = new THREE.Object3D();
meshparent[i].position.y = 50;
meshparent[i].position.x = -50;
meshparent2[i].add( meshparent[i] );
mesh = new THREE.Mesh( geometry, material );
meshparent[i].add( mesh );
meshes.push(mesh);
}
window.addEventListener( 'resize', onWindowResize, false );
document.addEventListener('keydown', keyPressed, false);
oculuscontrol.connect();
}
function onWindowResize() {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
realcamera.aspect = window.innerWidth / window.innerHeight;
realcamera.updateProjectionMatrix();
effect.setSize( window.innerWidth, window.innerHeight );
controls.handleResize();
}
function keyPressed(event) {
if (event.keyCode === 72) { // H
guiVisible = !guiVisible;
document.getElementById('info').style.display = guiVisible ? "block" : "none";
}
}
function animate() {
requestAnimationFrame( animate );
var t = clock.getElapsedTime();
for (var i=0; i<meshes.length; i++) {
var c = Math.floor(i % cols);
var r = Math.floor(i / cols);
meshparent2[i].rotation.y = (c * 3.142 * 2 / cols);
meshparent[i].rotation.x = ((r+10) * 3.142 * 2 / (rows+20));
meshes[i].position.z = 1400 - 1350 * perlin.noise(c*8/cols,r*8/rows,t/2);
}
controls.update( clock.getDelta() );
oculuscontrol.update( clock.getDelta() );
effect.render( scene, camera );
}
</script>
</body>
</html>
<!DOCTYPE html>
<html lang="en">
<head>
<title>three.js webgl - effects - oculus rift</title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
<style>
body {
color: rgb(168, 148, 0);
font-family:Monospace;
font-size:13px;
text-align:center;
background-color: #000000;
margin: 0px;
overflow: hidden;
}
#info {
position: absolute;
top: 0px; width: 100%;
padding: 5px;
}
a {
color: #a06851;
}
#oldie {
background:rgb(100,0,0) !important;
color:#fff !important;
margin-top:10em !important;
}
#oldie a { color:#fff }
</style>
</head>
<body>
<div id="container"><br /><br /><br /><br /><br />Generating world...</div>
<div id="info"><a href="http://threejs.org" target="_blank">three.js</a> - effects - oculus rift. featuring <a href="http://painterlypack.net/" target="_blank">painterly pack</a><br />(left click: forward, right click: backward, h: hide text)</div>
<script src="../build/three.min.js"></script>
<script src="js/controls/FirstPersonControls.js"></script>
<script src="js/ImprovedNoise.js"></script>
<script src="js/Detector.js"></script>
<script src="js/effects/OculusRiftEffect.js"></script>
<script src="js/libs/stats.min.js"></script>
<script src="js/wip/TypedGeometry.js"></script>
<script src="js/wip/IndexedTypedGeometry.js"></script>
<script src="js/wip/PlaneTypedGeometry.js"></script>
<script>
if ( ! Detector.webgl ) {
Detector.addGetWebGLMessage();
document.getElementById( 'container' ).innerHTML = "";
}
var container, stats;
var camera, controls, scene, renderer;
var mesh;
var worldWidth = 128, worldDepth = 128,
worldHalfWidth = worldWidth / 2, worldHalfDepth = worldDepth / 2,
data = generateHeight( worldWidth, worldDepth );
var clock = new THREE.Clock();
init();
animate();
function init() {
container = document.getElementById( 'container' );
camera = new THREE.PerspectiveCamera( 60, window.innerWidth / window.innerHeight, 1, 20000 );
camera.position.y = getY( worldHalfWidth, worldHalfDepth ) * 100 + 100;
controls = new THREE.FirstPersonControls( camera );
controls.movementSpeed = 1000;
controls.lookSpeed = 0.125;
controls.lookVertical = true;
scene = new THREE.Scene();
// sides
var matrix = new THREE.Matrix4();
var pxGeometry = new THREE.PlaneTypedGeometry( 100, 100 );
pxGeometry.uvs[ 1 ] = 0.5;
pxGeometry.uvs[ 3 ] = 0.5;
pxGeometry.applyMatrix( matrix.makeRotationY( Math.PI / 2 ) );
pxGeometry.applyMatrix( matrix.makeTranslation( 50, 0, 0 ) );
var nxGeometry = new THREE.PlaneTypedGeometry( 100, 100 );
nxGeometry.uvs[ 1 ] = 0.5;
nxGeometry.uvs[ 3 ] = 0.5;
nxGeometry.applyMatrix( matrix.makeRotationY( - Math.PI / 2 ) );
nxGeometry.applyMatrix( matrix.makeTranslation( - 50, 0, 0 ) );
var pyGeometry = new THREE.PlaneTypedGeometry( 100, 100 );
pyGeometry.uvs[ 5 ] = 0.5;
pyGeometry.uvs[ 7 ] = 0.5;
pyGeometry.applyMatrix( matrix.makeRotationX( - Math.PI / 2 ) );
pyGeometry.applyMatrix( matrix.makeTranslation( 0, 50, 0 ) );
var pzGeometry = new THREE.PlaneTypedGeometry( 100, 100 );
pzGeometry.uvs[ 1 ] = 0.5;
pzGeometry.uvs[ 3 ] = 0.5;
pzGeometry.applyMatrix( matrix.makeTranslation( 0, 0, 50 ) );
var nzGeometry = new THREE.PlaneTypedGeometry( 100, 100 );
nzGeometry.uvs[ 1 ] = 0.5;
nzGeometry.uvs[ 3 ] = 0.5;
nzGeometry.applyMatrix( matrix.makeRotationY( Math.PI ) );
nzGeometry.applyMatrix( matrix.makeTranslation( 0, 0, -50 ) );
//
var geometry = new THREE.TypedGeometry( worldWidth * worldDepth * 2 * 5 ); // 2 triangles, 5 possible sides
for ( var z = 0; z < worldDepth; z ++ ) {
for ( var x = 0; x < worldWidth; x ++ ) {
var h = getY( x, z );
matrix.makeTranslation(
x * 100 - worldHalfWidth * 100,
h * 100,
z * 100 - worldHalfDepth * 100
);
var px = getY( x + 1, z );
var nx = getY( x - 1, z );
var pz = getY( x, z + 1 );
var nz = getY( x, z - 1 );
geometry.merge( pyGeometry, matrix );
if ( ( px != h && px != h + 1 ) || x == 0 ) {
geometry.merge( pxGeometry, matrix );
}
if ( ( nx != h && nx != h + 1 ) || x == worldWidth - 1 ) {
geometry.merge( nxGeometry, matrix );
}
if ( ( pz != h && pz != h + 1 ) || z == worldDepth - 1 ) {
geometry.merge( pzGeometry, matrix );
}
if ( ( nz != h && nz != h + 1 ) || z == 0 ) {
geometry.merge( nzGeometry, matrix );
}
}
}
geometry.computeBoundingSphere();
var texture = THREE.ImageUtils.loadTexture( 'textures/minecraft/atlas.png' );
texture.magFilter = THREE.NearestFilter;
texture.minFilter = THREE.LinearMipMapLinearFilter;
var mesh = new THREE.Mesh( geometry, new THREE.MeshLambertMaterial( { map: texture } ) );
scene.add( mesh );
var ambientLight = new THREE.AmbientLight( 0xcccccc );
scene.add( ambientLight );
var directionalLight = new THREE.DirectionalLight( 0xffffff, 2 );
directionalLight.position.set( 1, 1, 0.5 ).normalize();
scene.add( directionalLight );
renderer = new THREE.WebGLRenderer();
renderer.setClearColor( 0xbfd1e5 );
renderer.setPixelRatio( window.devicePixelRatio );
renderer.setSize( window.innerWidth, window.innerHeight );
// Here is the effect for the Oculus Rift
// worldScale 100 means that 100 Units == 1m
effect = new THREE.OculusRiftEffect( renderer, {worldScale: 100} );
effect.setSize( window.innerWidth, window.innerHeight );
container.innerHTML = "";
container.appendChild( renderer.domElement );
stats = new Stats();
stats.domElement.style.position = 'absolute';
stats.domElement.style.top = '0px';
container.appendChild( stats.domElement );
// GUI
window.addEventListener( 'resize', onWindowResize, false );
document.addEventListener( 'keydown', keyPressed, false );
guiVisible = true;
}
function onWindowResize() {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
effect.setSize( window.innerWidth, window.innerHeight );
controls.handleResize();
}
function keyPressed (event) {
if (event.keyCode === 72) { // H
guiVisible = !guiVisible;
document.getElementById('info').style.display = guiVisible ? "block" : "none";
stats.domElement.style.display = guiVisible ? "block" : "none";
}
}
function generateHeight( width, height ) {
var data = [], perlin = new ImprovedNoise(),
size = width * height, quality = 2, z = Math.random() * 100;
for ( var j = 0; j < 4; j ++ ) {
if ( j == 0 ) for ( var i = 0; i < size; i ++ ) data[ i ] = 0;
for ( var i = 0; i < size; i ++ ) {
var x = i % width, y = ( i / width ) | 0;
data[ i ] += perlin.noise( x / quality, y / quality, z ) * quality;
}
quality *= 4
}
return data;
}
function getY( x, z ) {
return ( data[ x + z * worldWidth ] * 0.2 ) | 0;
}
//
function animate() {
requestAnimationFrame( animate );
render();
stats.update();
}
function render() {
controls.update( clock.getDelta() );
effect.render( scene, camera );
}
</script>
</body>
</html>
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册