【问题标题】:Rotatable 3D model in web page [closed]网页中的可旋转 3D 模型[关闭]
【发布时间】:2014-04-08 21:27:57
【问题描述】:

我有点困惑:

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

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

另外 - 如果上述情况可行,那么是否可以操纵关节,例如将膝盖抬起或肘部向内?

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

如果需要,我愿意学习新的语言来做到这一点。

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

约翰

【问题讨论】:

  • 有代码可以使用吗?
  • 无 恐怕因为我不知道从哪里开始。我不想输入数据只是为了发现我使用的技术不起作用,因此我尝试建立我需要及早使用的技术。
  • 我已经在 Twitter 上推荐了threejs.org。如果这个线程没有更好的结果,我会将其添加为答案,因为它看起来是一个理想的起点:-)
  • 请接受以下答案
  • 查看我下面给出的答案,如果有用,请将其标记为已接受。

标签: javascript css canvas vector svg


【解决方案1】:

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

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

浏览器支持在您的选择中也起着重要作用,threejs 使用画布,所以这是一个相当新的功能。您可以使用这两种解决方案,在较新的浏览器上使用threejs,在旧浏览器上使用精灵

【讨论】:

  • 感谢 Jonas,这是我的个人项目,我非常愿意学习新技能等,因此学习threejs 不会有问题。老实说,我没有见过threejs - 我得到的最近的是sprite.js。我将接受您的答案作为正确答案,因为您是回答最佳答案和替代答案的人。再次感谢,约翰
【解决方案2】:

这段代码来自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>

【讨论】:

  • 您好 Karthik,感谢您提供代码。今晚我会去学习threejs,并会剖析他们拥有的示例并慢慢建立我需要的模型。谢谢阿金
猜你喜欢
  • 2021-06-24
  • 1970-01-01
  • 2016-07-26
  • 1970-01-01
  • 2014-07-02
  • 2010-10-10
  • 2020-10-10
  • 2013-09-05
  • 1970-01-01
相关资源
最近更新 更多