网页中的可旋转3D模型

时间:2014-03-06 10:09:19

标签: javascript css canvas vector svg

我有点窘迫:

我想创建一个人体的3D模型,将其嵌入网页并让用户旋转它。

我考虑了一些建模库,CSS,SVG等(我从来没有使用过HTML5 Canvas)但老实说我不确定这是否可行。

另外 - 如果上述情况可能,那么是否可以操纵关节,例如膝盖向上或肘部进入?

我的主要想法是在SVG中构建模型并让模型通过Javascript以36度的步长旋转,然后可以从那里操纵关节。

如果需要,我愿意学习新语言。

提前致谢,希望有人能帮助我。即使告诉我这是不可能的。

约翰

2 个答案:

答案 0 :(得分:1)

艰难而美丽的方式:THREEJS。 http://threejs.org/ 简单方法:创建一个图像,每个框架将其设置为容器中的背景,然后相应地更改背景位置(这将允许仅在一个轴上旋转,并且不允许关节操作)。

我建议你学习三个(如果你有足够的时间)他们的例子很棒而且不是那么难。

浏览器支持在您的选择中也起着重要作用,threejs使用canvas,因此它是一个非常新的功能。您可以使用这两种解决方案,在较新的浏览器上使用threejs,使用精灵来使用糟糕的旧版本

答案 1 :(得分:1)

此代码来自three.js,这对此问题非常有用。

<!doctype html>
<html lang="en">
    <head>
        <title>three.js webgl - cloth simulation</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 {
                font-family: Monospace;
                background-color: #000;
                color: #000;
                margin: 0px;
                overflow: hidden;
            }

            #info {
                text-align: center;
                padding: 10px;
                z-index: 10;
                width: 100%;
                position: absolute;
            }

            a {
                text-decoration: underline;
                cursor: pointer;
            }

            #stats { position: absolute; top:0; left: 0 }
            #stats #fps { background: transparent !important }
            #stats #fps #fpsText { color: #aaa !important }
            #stats #fps #fpsGraph { display: none }
        </style>
    </head>

    <body>
        <div id="info">Simple Cloth Simulation<br/>
            Verlet integration with Constrains relaxation<br/>
            Toggle: <a onclick="rotate = !rotate;">Camera</a> |
            <a onclick="wind = !wind;">Wind</a> |
            <a onclick="sphere.visible = !sphere.visible;">Ball</a> |
            <a onclick="togglePins();">Pins</a>
        </div>

        <script src="../build/three.min.js"></script>

        <script src="js/Detector.js"></script>
        <script src="js/libs/stats.min.js"></script>

        <script src="js/Cloth.js"></script>

        <script type="x-shader/x-fragment" id="fragmentShaderDepth">

            uniform sampler2D texture;
            varying vec2 vUV;

            vec4 pack_depth( const in float depth ) {

                const vec4 bit_shift = vec4( 256.0 * 256.0 * 256.0, 256.0 * 256.0, 256.0, 1.0 );
                const vec4 bit_mask  = vec4( 0.0, 1.0 / 256.0, 1.0 / 256.0, 1.0 / 256.0 );
                vec4 res = fract( depth * bit_shift );
                res -= res.xxyz * bit_mask;
                return res;

            }

            void main() {

                vec4 pixel = texture2D( texture, vUV );

                if ( pixel.a < 0.5 ) discard;

                gl_FragData[ 0 ] = pack_depth( gl_FragCoord.z );

            }
        </script>

        <script type="x-shader/x-vertex" id="vertexShaderDepth">

            varying vec2 vUV;

            void main() {

                vUV = 0.75 * uv;

                vec4 mvPosition = modelViewMatrix * vec4( position, 1.0 );

                gl_Position = projectionMatrix * mvPosition;

            }

        </script>

        <script>

            /* testing cloth simulation */

            var pinsFormation = [];
            var pins = [6];

            pinsFormation.push( pins );

            pins = [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ];
            pinsFormation.push( pins );

            pins = [ 0 ];
            pinsFormation.push( pins );

            pins = []; // cut the rope ;)
            pinsFormation.push( pins );

            pins = [ 0, cloth.w ]; // classic 2 pins
            pinsFormation.push( pins );

            pins = pinsFormation[ 1 ];


            function togglePins() {

                pins = pinsFormation[ ~~( Math.random() * pinsFormation.length ) ];

            }

            if ( ! Detector.webgl ) Detector.addGetWebGLMessage();

            var container, stats;
            var camera, scene, renderer;

            var clothGeometry;
            var sphere;
            var object, arrow;

            var rotate = true;

            init();
            animate();

            function init() {

                container = document.createElement( 'div' );
                document.body.appendChild( container );

                // scene

                scene = new THREE.Scene();

                scene.fog = new THREE.Fog( 0xcce0ff, 500, 10000 );

                // camera

                camera = new THREE.PerspectiveCamera( 30, window.innerWidth / window.innerHeight, 1, 10000 );
                camera.position.y = 50;
                camera.position.z = 1500;
                scene.add( camera );

                // lights

                var light, materials;

                scene.add( new THREE.AmbientLight( 0x666666 ) );

                light = new THREE.DirectionalLight( 0xdfebff, 1.75 );
                light.position.set( 50, 200, 100 );
                light.position.multiplyScalar( 1.3 );

                light.castShadow = true;
                //light.shadowCameraVisible = true;

                light.shadowMapWidth = 2048;
                light.shadowMapHeight = 2048;

                var d = 300;

                light.shadowCameraLeft = -d;
                light.shadowCameraRight = d;
                light.shadowCameraTop = d;
                light.shadowCameraBottom = -d;

                light.shadowCameraFar = 1000;
                light.shadowDarkness = 0.5;

                scene.add( light );

                light = new THREE.DirectionalLight( 0x3dff0c, 0.35 );
                light.position.set( 0, -1, 0 );

                scene.add( light );

                // cloth material

                var clothTexture = THREE.ImageUtils.loadTexture( 'textures/patterns/circuit_pattern.png' );
                clothTexture.wrapS = clothTexture.wrapT = THREE.RepeatWrapping;
                clothTexture.anisotropy = 16;

                var clothMaterial = new THREE.MeshPhongMaterial( { alphaTest: 0.5, ambient: 0xffffff, color: 0xffffff, specular: 0x030303, emissive: 0x111111, shiness: 10, map: clothTexture, side: THREE.DoubleSide } );

                // cloth geometry
                clothGeometry = new THREE.ParametricGeometry( clothFunction, cloth.w, cloth.h );
                clothGeometry.dynamic = true;
                clothGeometry.computeFaceNormals();

                var uniforms = { texture:  { type: "t", value: clothTexture } };
                var vertexShader = document.getElementById( 'vertexShaderDepth' ).textContent;
                var fragmentShader = document.getElementById( 'fragmentShaderDepth' ).textContent;

                // cloth mesh

                object = new THREE.Mesh( clothGeometry, clothMaterial );
                object.position.set( 0, 0, 0 );
                object.castShadow = true;
                object.receiveShadow = true;
                scene.add( object );

                object.customDepthMaterial = new THREE.ShaderMaterial( { uniforms: uniforms, vertexShader: vertexShader, fragmentShader: fragmentShader } );

                // sphere

                var ballGeo = new THREE.SphereGeometry( ballSize, 20, 20 );
                var ballMaterial = new THREE.MeshPhongMaterial( { color: 0xffffff } );

                sphere = new THREE.Mesh( ballGeo, ballMaterial );
                sphere.castShadow = true;
                sphere.receiveShadow = true;
                scene.add( sphere );

                // arrow

                arrow = new THREE.ArrowHelper( new THREE.Vector3( 0, 1, 0 ), new THREE.Vector3( 0, 0, 0 ), 50, 0xff0000 );
                arrow.position.set( -200, 0, -200 );
                // scene.add( arrow );

                // ground

                var initColor = new THREE.Color( 0x497f13 );
                var initTexture = THREE.ImageUtils.generateDataTexture( 1, 1, initColor );

                var groundMaterial = new THREE.MeshPhongMaterial( { color: 0xffffff, specular: 0x111111, map: initTexture } );

                var groundTexture = THREE.ImageUtils.loadTexture( "textures/terrain/grasslight-big.jpg", undefined, function() { groundMaterial.map = groundTexture } );
                groundTexture.wrapS = groundTexture.wrapT = THREE.RepeatWrapping;
                groundTexture.repeat.set( 25, 25 );
                groundTexture.anisotropy = 16;

                var mesh = new THREE.Mesh( new THREE.PlaneGeometry( 20000, 20000 ), groundMaterial );
                mesh.position.y = -250;
                mesh.rotation.x = - Math.PI / 2;
                mesh.receiveShadow = true;
                scene.add( mesh );

                // poles

                var poleGeo = new THREE.BoxGeometry( 5, 375, 5 );
                var poleMat = new THREE.MeshPhongMaterial( { color: 0xffffff, specular: 0x111111, shiness: 100 } );

                var mesh = new THREE.Mesh( poleGeo, poleMat );
                mesh.position.x = -125;
                mesh.position.y = -62;
                mesh.receiveShadow = true;
                mesh.castShadow = true;
                scene.add( mesh );

                var mesh = new THREE.Mesh( poleGeo, poleMat );
                mesh.position.x = 125;
                mesh.position.y = -62;
                mesh.receiveShadow = true;
                mesh.castShadow = true;
                scene.add( mesh );

                var mesh = new THREE.Mesh( new THREE.BoxGeometry( 255, 5, 5 ), poleMat );
                mesh.position.y = -250 + 750/2;
                mesh.position.x = 0;
                mesh.receiveShadow = true;
                mesh.castShadow = true;
                scene.add( mesh );

                var gg = new THREE.BoxGeometry( 10, 10, 10 );
                var mesh = new THREE.Mesh( gg, poleMat );
                mesh.position.y = -250;
                mesh.position.x = 125;
                mesh.receiveShadow = true;
                mesh.castShadow = true;
                scene.add( mesh );

                var mesh = new THREE.Mesh( gg, poleMat );
                mesh.position.y = -250;
                mesh.position.x = -125;
                mesh.receiveShadow = true;
                mesh.castShadow = true;
                scene.add( mesh );

                //

                renderer = new THREE.WebGLRenderer( { antialias: true } );
                renderer.setSize( window.innerWidth, window.innerHeight );
                renderer.setClearColor( scene.fog.color );

                container.appendChild( renderer.domElement );

                renderer.gammaInput = true;
                renderer.gammaOutput = true;

                renderer.shadowMapEnabled = true;

                //

                stats = new Stats();
                container.appendChild( stats.domElement );

                //

                window.addEventListener( 'resize', onWindowResize, false );

                sphere.visible = !true

            }

            //

            function onWindowResize() {

                camera.aspect = window.innerWidth / window.innerHeight;
                camera.updateProjectionMatrix();

                renderer.setSize( window.innerWidth, window.innerHeight );

            }

            //

            function animate() {

                requestAnimationFrame( animate );

                var time = Date.now();

                windStrength = Math.cos( time / 7000 ) * 20 + 40;
                windForce.set( Math.sin( time / 2000 ), Math.cos( time / 3000 ), Math.sin( time / 1000 ) ).normalize().multiplyScalar( windStrength );
                arrow.setLength( windStrength );
                arrow.setDirection( windForce );

                simulate(time);
                render();
                stats.update();

            }

            function render() {

                var timer = Date.now() * 0.0002;

                var p = cloth.particles;

                for ( var i = 0, il = p.length; i < il; i ++ ) {

                    clothGeometry.vertices[ i ].copy( p[ i ].position );

                }

                clothGeometry.computeFaceNormals();
                clothGeometry.computeVertexNormals();

                clothGeometry.normalsNeedUpdate = true;
                clothGeometry.verticesNeedUpdate = true;

                sphere.position.copy( ballPosition );

                if ( rotate ) {

                    camera.position.x = Math.cos( timer ) * 1500;
                    camera.position.z = Math.sin( timer ) * 1500;

                }

                camera.lookAt( scene.position );

                renderer.render( scene, camera );

            }

        </script>
    </body>
</html>