آموزش Three.js

saalek110

Well-Known Member
JavaScript:
<script type="importmap">
{
  "imports": {
    "three": "./path/to/three.module.js"
  }
}
</script>
کد:

JavaScript:
<script type="module">
import * as THREE from 'three';
 
...
 
</script>

نوع اسکریپت
اولی importmap است دومی ماژول.

برای import کردن three باید نوع اسکریپت ماژول باشد.

میگه اول آدرس فقط باید به یکی از دو صورت باشد:

JavaScript:
Note that path specifier can start only with ./ or ../.

نقطه یا دو نقطه.

این جوری هم میشه نوشت:

JavaScript:
<script type="importmap">
{
  "imports": {
    "three": "https://cdn.jsdelivr.net/npm/three@<version>/build/three.module.js",
    "three/addons/": "https://cdn.jsdelivr.net/npm/three@<version>/examples/jsm/"
  }
}
</script>

یعنی داخل importmap می توانیم cdn استفاده کنیم.
 

saalek110

Well-Known Member
فایل منیجر ورژن ۱۰ ، برای کار در لوکال منتشر شد.
من خودم الان با ksweb در لوکال کار می کنم.
باهاش می توانید فایلهای html پوشه example را اجرا کنید و کدهای اونها را نگاه کنید.


 

saalek110

Well-Known Member
سالک: یک چیزایی نقل قول کردیم و چند تا سورس از مثالهای پوشه examples مرور کردیم.

حالا من می خوام اون برنامه گردش در چمن را که ۵ تا دکمه داشت را ادامه بدهم.

یک سورس بود که یک سری مکعب می ریخت روی صفحه که با انگشت میشد تکونشون داد...
می خوام برنامه گردش در چمن را روی اون پیاده کنم. یعنی آبجکتهای سنگ و درخت و چمن و آسمان را درش وارد کنم.

ولی یک مشکل برخورد کردم. کد زیر را ببینید:
JavaScript:
    const geometry_stone = new THREE.BoxGeometry();
      const geometry_stone2 = new THREE.BoxBufferGeometry();

فرقشون در اون کلمه buffer است . ولی دومی برنامه را مختل می کنه. دلیلش را نمی دونم. فعلا از اولی استفاده می کنم تا بعدا معلوم بشه چرا.
 

saalek110

Well-Known Member
JavaScript:
  //-------------------- stone ------------
      const geometry_stone = new THREE.BoxGeometry(20,20,20);
const texture_stone = new THREE.TextureLoader().load(   'textures/stone.jpg' );

const material_stone = new THREE.MeshBasicMaterial( { map: texture_stone } );
   const mesh_stone = new THREE.Mesh( geometry_stone, material_stone );
   
    mesh_stone.position.x = -150;
    mesh_stone.position.y = -100;
    mesh_stone.position.z = 5500;
    scene.add( mesh_stone );


کلمه const را جلوی همه چی گذاشتم ...تا .....بالاخره کدهای بالا را خطا نداد.
کدهای بالا یک مکعب تکسچردار است. ولی هنوز مکعب را در برنامه ندیدم. شاید جلوی دوربین نیست. باید سایز و مختصاتش را عوض کنم.

با عقب و جلو کردن دوربین و تغییر سایز و محل بلوک سیمانی ، آوردمش جلوی دوربین. عکس:

Screenshot_۲۰۲۴-۱۰-۰۴_۱۲۴۹۴۶.jpg

رنگش سفید ، خوب معلوم نیست.
تکسچرش را عوض می کنم.

Screenshot_۲۰۲۴-۱۰-۰۴_۱۲۵۴۳۸.jpg

حالا بهتر معلومه.
 
آخرین ویرایش:

saalek110

Well-Known Member
دکمه هایم را قبل تگ بادی بسته گذاشتم ولی دکمه ها رفت بالای صفحه.کدش:

HTML:
  <center>
<img src="textures/buttons/left.png" height="90" size="90" alt="Img" onclick="myFunction('4')">
 <img src="textures/buttons/up.png" height="90" size="90" alt="Img" onclick="myFunction('1')">
<img src="textures/buttons/stop.png" height="90" width="90" alt="Img" onclick="myFunction('3')">
<img src="textures/buttons/down.png" height="90" size="90" alt="Img" onclick="myFunction('2')">
<img src="textures/buttons/right.png" height="90" size="90" alt="Img" onclick="myFunction('5')">  
      </center>

قبلا در تاپیک عکس های دکمه را برای دانلود گذاشتم.

Screenshot_۲۰۲۴-۱۰-۰۴_۱۳۰۴۴۲.jpg

در عکس بالا می بینید دکمه ها رفته بالای صفحه، ولی من انتهای کدها گذاشتم دکمه ها را. فعلا مهم نیست ، شاید بعدا از خود three.js ابزار دکمه پیدا کردیم.
 

saalek110

Well-Known Member
تابع خود را هم اضافه کردم:در قبل بسته شدن اسکریپت اضافه کردم.
JavaScript:
function myFunction(x) {
   if (x==1) {
     flag=0;
 if(my_control==0     && flag==0)    {   my_control=-20;    flag=1; }
 if(my_control==-20   && flag==0)    {   my_control=-40;    flag=1; }
if(my_control==-40   && flag==0)    {   my_control=-60;    flag=1; }
if(my_control==-60   && flag==0)    {   my_control=-80;    flag=1; }
if(my_control==-80   && flag==0)    {   my_control=-100;    flag=1; }
}//x=1

if (x==2) { my_control=20; }
if (x==3) { my_control=0; }

if (x==4) {  rotation +=0.2618;   }
if (x==5) { rotation -=0.2618;    }
 
}  // function

ولی این را کجا درج کنم؟!! :
JavaScript:
camera.rotation.y=rotation;
camera.position.x += Math.sin(rotation) * my_control;
camera.position.z += Math.cos(rotation) * my_control;

در برنامه قبلی ، داخل تابع animate درج شده بود. ولی این برنامه تابع animate نداره.
 
آخرین ویرایش:

saalek110

Well-Known Member
برنامه اصلی اینه:
JavaScript:
                <!DOCTYPE html>
<html lang="en">
    <head>
        <title>three.js webgl - drag controls</title>
        <meta charset="utf-8">
        <meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
        <link type="text/css" rel="stylesheet" href="main.css">
        <style>
            body {
                background-color: #f0f0f0;
                color: #444;
            }
            a {
                color: #08f;
            }
        </style>
    </head>
    <body>

        
        <script type="importmap">
            {
                "imports": {
                    "three": "./three-js-master/build/three.module.js",
                    "three/addons/": "./three-js-master/examples/jsm/"
                }
            }
        </script>

        <script type="module">

            import * as THREE from 'three';

            import { DragControls } from 'three/addons/controls/DragControls.js';

            let container;
            let camera, scene, renderer;
            let controls, group;
            let enableSelection = false;

            const objects = [];

            const mouse = new THREE.Vector2(), raycaster = new THREE.Raycaster();

            init();

            function init() {

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

                camera = new THREE.PerspectiveCamera( 70, window.innerWidth / window.innerHeight, 0.1, 500 );
                camera.position.z = 25;

                scene = new THREE.Scene();
                scene.background = new THREE.Color( 0xf0f0f0 );

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

                const light = new THREE.SpotLight( 0xffffff, 10000 );
                light.position.set( 0, 25, 50 );
                light.angle = Math.PI / 9;

                light.castShadow = true;
                light.shadow.camera.near = 10;
                light.shadow.camera.far = 100;
                light.shadow.mapSize.width = 1024;
                light.shadow.mapSize.height = 1024;

                scene.add( light );

                group = new THREE.Group();
                scene.add( group );

                const geometry = new THREE.BoxGeometry();

                for ( let i = 0; i < 10; i ++ ) {

                    const object = new THREE.Mesh( geometry, new THREE.MeshLambertMaterial( { color: Math.random() * 0xffffff } ) );

                    object.position.x = Math.random() * 30 - 15;
                    object.position.y = Math.random() * 15 - 7.5;
                    object.position.z = Math.random() * 20 - 10;

                    object.rotation.x = Math.random() * 2 * Math.PI;
                    object.rotation.y = Math.random() * 2 * Math.PI;
                    object.rotation.z = Math.random() * 2 * Math.PI;

                    object.scale.x = Math.random() * 2 + 1;
                    object.scale.y = Math.random() * 2 + 1;
                    object.scale.z = Math.random() * 2 + 1;

                    object.castShadow = true;
                    object.receiveShadow = true;

                    scene.add( object );

                    objects.push( object );

                }

                renderer = new THREE.WebGLRenderer( { antialias: true } );
                renderer.setPixelRatio( window.devicePixelRatio );
                renderer.setSize( window.innerWidth, window.innerHeight );
                renderer.shadowMap.enabled = true;
                renderer.shadowMap.type = THREE.PCFShadowMap;

                container.appendChild( renderer.domElement );

                controls = new DragControls( [ ... objects ], camera, renderer.domElement );
                controls.rotateSpeed = 2;
                controls.addEventListener( 'drag', render );

                //

                window.addEventListener( 'resize', onWindowResize );

                document.addEventListener( 'click', onClick );
                window.addEventListener( 'keydown', onKeyDown );
                window.addEventListener( 'keyup', onKeyUp );

                render();

            }

            function onWindowResize() {

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

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

                render();

            }

            function onKeyDown( event ) {

                enableSelection = ( event.keyCode === 16 ) ? true : false;
            
                if ( event.keyCode === 77 ) {

                    controls.touches.ONE = ( controls.touches.ONE === THREE.TOUCH.PAN ) ? THREE.TOUCH.ROTATE : THREE.TOUCH.PAN;
            
                }

            }

            function onKeyUp() {

                enableSelection = false;

            }

            function onClick( event ) {

                event.preventDefault();

                if ( enableSelection === true ) {

                    const draggableObjects = controls.objects;
                    draggableObjects.length = 0;

                    mouse.x = ( event.clientX / window.innerWidth ) * 2 - 1;
                    mouse.y = - ( event.clientY / window.innerHeight ) * 2 + 1;

                    raycaster.setFromCamera( mouse, camera );

                    const intersections = raycaster.intersectObjects( objects, true );

                    if ( intersections.length > 0 ) {

                        const object = intersections[ 0 ].object;

                        if ( group.children.includes( object ) === true ) {

                            object.material.emissive.set( 0x000000 );
                            scene.attach( object );

                        } else {

                            object.material.emissive.set( 0xaaaaaa );
                            group.attach( object );

                        }

                        controls.transformGroup = true;
                        draggableObjects.push( group );

                    }

                    if ( group.children.length === 0 ) {

                        controls.transformGroup = false;
                        draggableObjects.push( ...objects );

                    }

                }

                render();

            }

            function render() {

                renderer.render( scene, camera );

            }

        </script>

    </body>
</html>
 

saalek110

Well-Known Member
داخل رویداد کلیک گذاشتم کدهای دو پست قبل را ولی کار نکرد.
گویا اینجا به بن بست خوردم.

متغیرهای لازم را هم بالای برنامه تعریف کردم.ولی کار نکرد.
ولی همین که بلوک را توانستم وارد برنامه کنم خوبه.
 

saalek110

Well-Known Member
در سورس زیر با لمس و کشیدن در صحنه می رویم جلو:

JavaScript:
        <!DOCTYPE html>
<html lang="en">
    <head>
        <title>three.js webgl - map controls</title>
        <meta charset="utf-8">
        <meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
        <link type="text/css" rel="stylesheet" href="main.css">
        <style>
            body {
                background-color: #ccc;
                color: #000;
            }

            a {
                color: #f00;
            }
        </style>
    </head>

    <body>
        <div id="info">
            <a href="https://threejs.org" target="_blank" rel="noopener">three.js</a> - map controls
        </div>

        <script type="importmap">
            {
                "imports": {
                    "three": "../build/three.module.js",
                    "three/addons/": "./jsm/"
                }
            }
        </script>

        <script type="module">

            import * as THREE from 'three';

            import { GUI } from 'three/addons/libs/lil-gui.module.min.js';

            import { MapControls } from 'three/addons/controls/MapControls.js';

            let camera, controls, scene, renderer;

            init();
            //render(); // remove when using animation loop

            function init() {

                scene = new THREE.Scene();
                scene.background = new THREE.Color( 0xcccccc );
                scene.fog = new THREE.FogExp2( 0xcccccc, 0.002 );

                renderer = new THREE.WebGLRenderer( { antialias: true } );
                renderer.setPixelRatio( window.devicePixelRatio );
                renderer.setSize( window.innerWidth, window.innerHeight );
                renderer.setAnimationLoop( animate );
                document.body.appendChild( renderer.domElement );

                camera = new THREE.PerspectiveCamera( 60, window.innerWidth / window.innerHeight, 1, 1000 );
                camera.position.set( 0, 200, - 400 );

                // controls

                controls = new MapControls( camera, renderer.domElement );

                //controls.addEventListener( 'change', render ); // call this only in static scenes (i.e., if there is no animation loop)

                controls.enableDamping = true; // an animation loop is required when either damping or auto-rotation are enabled
                controls.dampingFactor = 0.05;

                controls.screenSpacePanning = false;

                controls.minDistance = 100;
                controls.maxDistance = 500;

                controls.maxPolarAngle = Math.PI / 2;

                // world

                const geometry = new THREE.BoxGeometry();
                geometry.translate( 0, 0.5, 0 );
                const material = new THREE.MeshPhongMaterial( { color: 0xeeeeee, flatShading: true } );

                for ( let i = 0; i < 500; i ++ ) {

                    const mesh = new THREE.Mesh( geometry, material );
                    mesh.position.x = Math.random() * 1600 - 800;
                    mesh.position.y = 0;
                    mesh.position.z = Math.random() * 1600 - 800;
                    mesh.scale.x = 20;
                    mesh.scale.y = Math.random() * 80 + 10;
                    mesh.scale.z = 20;
                    mesh.updateMatrix();
                    mesh.matrixAutoUpdate = false;
                    scene.add( mesh );

                }

                // lights

                const dirLight1 = new THREE.DirectionalLight( 0xffffff, 3 );
                dirLight1.position.set( 1, 1, 1 );
                scene.add( dirLight1 );

                const dirLight2 = new THREE.DirectionalLight( 0x002288, 3 );
                dirLight2.position.set( - 1, - 1, - 1 );
                scene.add( dirLight2 );

                const ambientLight = new THREE.AmbientLight( 0x555555 );
                scene.add( ambientLight );

                //

                window.addEventListener( 'resize', onWindowResize );


                const gui = new GUI();
                gui.add( controls, 'zoomToCursor' );
                gui.add( controls, 'screenSpacePanning' );

            }

            function onWindowResize() {

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

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

            }

            function animate() {

                controls.update(); // only required if controls.enableDamping = true, or if controls.autoRotate = true

                render();

            }

            function render() {

                renderer.render( scene, camera );

            }

        </script>

    </body>
</html>
 

saalek110

Well-Known Member
سورس پست قبل ،عنوانش هم map control است:

Screenshot_۲۰۲۴-۱۰-۰۴_۱۳۳۰۲۴.jpg

اگر دو انگشتی لمس کنیم می توانیم زاویه را هم تغییر دهیم.
دقیقا اون چیزی که من می حوام نیست ولی بد هم نیست.
کنترل جالبی است کلا.

حالا کلی سورس دیگه هم هست.
 

saalek110

Well-Known Member
با لمس مکعب خلق میشه:
JavaScript:
        <!DOCTYPE html>
<html lang="en">
    <head>
        <title>three.js webgl - interactive - voxel painter</title>
        <meta charset="utf-8">
        <meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
        <link type="text/css" rel="stylesheet" href="main.css">
        <style>
            body {
                background-color: #f0f0f0;
                color: #444;
            }
            a {
                color: #08f;
            }
        </style>
    </head>
    <body>

        <div id="info">
            <a href="https://threejs.org" target="_blank" rel="noopener">three.js</a> - voxel painter - webgl<br>
            <strong>click</strong>: add voxel, <strong>shift + click</strong>: remove voxel
        </div>

        <script type="importmap">
            {
                "imports": {
                    "three": "../build/three.module.js",
                    "three/addons/": "./jsm/"
                }
            }
        </script>

        <script type="module">

            import * as THREE from 'three';

            let camera, scene, renderer;
            let plane;
            let pointer, raycaster, isShiftDown = false;

            let rollOverMesh, rollOverMaterial;
            let cubeGeo, cubeMaterial;

            const objects = [];

            init();
            render();

            function init() {

                camera = new THREE.PerspectiveCamera( 45, window.innerWidth / window.innerHeight, 1, 10000 );
                camera.position.set( 500, 800, 1300 );
                camera.lookAt( 0, 0, 0 );

                scene = new THREE.Scene();
                scene.background = new THREE.Color( 0xf0f0f0 );

                // roll-over helpers

                const rollOverGeo = new THREE.BoxGeometry( 50, 50, 50 );
                rollOverMaterial = new THREE.MeshBasicMaterial( { color: 0xff0000, opacity: 0.5, transparent: true } );
                rollOverMesh = new THREE.Mesh( rollOverGeo, rollOverMaterial );
                scene.add( rollOverMesh );

                // cubes

                const map = new THREE.TextureLoader().load( 'textures/square-outline-textured.png' );
                map.colorSpace = THREE.SRGBColorSpace;
                cubeGeo = new THREE.BoxGeometry( 50, 50, 50 );
                cubeMaterial = new THREE.MeshLambertMaterial( { color: 0xfeb74c, map: map } );

                // grid

                const gridHelper = new THREE.GridHelper( 1000, 20 );
                scene.add( gridHelper );

                //

                raycaster = new THREE.Raycaster();
                pointer = new THREE.Vector2();

                const geometry = new THREE.PlaneGeometry( 1000, 1000 );
                geometry.rotateX( - Math.PI / 2 );

                plane = new THREE.Mesh( geometry, new THREE.MeshBasicMaterial( { visible: false } ) );
                scene.add( plane );

                objects.push( plane );

                // lights

                const ambientLight = new THREE.AmbientLight( 0x606060, 3 );
                scene.add( ambientLight );

                const directionalLight = new THREE.DirectionalLight( 0xffffff, 3 );
                directionalLight.position.set( 1, 0.75, 0.5 ).normalize();
                scene.add( directionalLight );

                renderer = new THREE.WebGLRenderer( { antialias: true } );
                renderer.setPixelRatio( window.devicePixelRatio );
                renderer.setSize( window.innerWidth, window.innerHeight );
                document.body.appendChild( renderer.domElement );

                document.addEventListener( 'pointermove', onPointerMove );
                document.addEventListener( 'pointerdown', onPointerDown );
                document.addEventListener( 'keydown', onDocumentKeyDown );
                document.addEventListener( 'keyup', onDocumentKeyUp );

                //

                window.addEventListener( 'resize', onWindowResize );

            }

            function onWindowResize() {

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

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

                render();

            }

            function onPointerMove( event ) {

                pointer.set( ( event.clientX / window.innerWidth ) * 2 - 1, - ( event.clientY / window.innerHeight ) * 2 + 1 );

                raycaster.setFromCamera( pointer, camera );

                const intersects = raycaster.intersectObjects( objects, false );

                if ( intersects.length > 0 ) {

                    const intersect = intersects[ 0 ];

                    rollOverMesh.position.copy( intersect.point ).add( intersect.face.normal );
                    rollOverMesh.position.divideScalar( 50 ).floor().multiplyScalar( 50 ).addScalar( 25 );

                    render();

                }

            }

            function onPointerDown( event ) {

                pointer.set( ( event.clientX / window.innerWidth ) * 2 - 1, - ( event.clientY / window.innerHeight ) * 2 + 1 );

                raycaster.setFromCamera( pointer, camera );

                const intersects = raycaster.intersectObjects( objects, false );

                if ( intersects.length > 0 ) {

                    const intersect = intersects[ 0 ];

                    // delete cube

                    if ( isShiftDown ) {

                        if ( intersect.object !== plane ) {

                            scene.remove( intersect.object );

                            objects.splice( objects.indexOf( intersect.object ), 1 );

                        }

                        // create cube

                    } else {

                        const voxel = new THREE.Mesh( cubeGeo, cubeMaterial );
                        voxel.position.copy( intersect.point ).add( intersect.face.normal );
                        voxel.position.divideScalar( 50 ).floor().multiplyScalar( 50 ).addScalar( 25 );
                        scene.add( voxel );

                        objects.push( voxel );

                    }

                    render();

                }

            }

            function onDocumentKeyDown( event ) {

                switch ( event.keyCode ) {

                    case 16: isShiftDown = true; break;

                }

            }

            function onDocumentKeyUp( event ) {

                switch ( event.keyCode ) {

                    case 16: isShiftDown = false; break;

                }

            }

            function render() {

                renderer.render( scene, camera );

            }

        </script>

    </body>
</html>

Screenshot_۲۰۲۴-۱۰-۰۴_۱۳۴۸۱۱.jpg
 

saalek110

Well-Known Member
من الان در گوشی ام ، خیلی از این سورس ها با کیبورد و ماوس کار می کنه.

شاید گاهی بهتر باشه به جای گشتن میان سورس ها ، در گوگل سرچ کنیم.
 

جدیدترین ارسال ها

بالا