آموزش Three.js

saalek110

Well-Known Member
کل بسته را هم لازم نیست از لینک زیر دانلود کنید(با زدن دکمه سبز و زدن download zip)
۳۵۶ مگا.


اون فایلهایی که نیاز دارید را دانلود کنید.
در مورد نیازهای فایل لود کننده obj file در چند پست بالاتر بحث کردیم.

ولی من هنوز با در اختیار گذاشتن همون چند تا فایل در اختیار برنامه، برنامه را امتحان نکردم. ولی احتمالا اجرا میشه.

پنج شش مگا فایلهای اصلی اش است.
اون تا فایل هم هر کدام بیست تا سی کیلو بیشتر نیست.

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

پوشه تکسچرهایش:

 
آخرین ویرایش:

saalek110

Well-Known Member
نرم افزار رایگان در کامپیوتر برای آبجکت سازی ، Blender است.

برای گوشی:

شصت مگا.

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

ولی با این هم کارهای جالبی میشه کرد.
در یوتیوب آموزش کار باهاش است. خودش هم فیلم هایی آموزشی در خودش داره.
 
آخرین ویرایش:

saalek110

Well-Known Member

گیاهان و تکسچر گیاهی ، مثل تنه درخت.

۳ گیگ.
 

saalek110

Well-Known Member
من امروز خیلی از مثالها را مرور کردم. این تکه را همشون دارند:

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

        <script type="module">

            import * as THREE from 'three';

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

            let scene, camera, renderer, exporter, mesh;

کار این تکه کد اول برنامه اینه که اول فایلهای اصلی را import می کنه ، بعدش بنا به نیاز ، از فایلهای پوشه های واقع در پوشه jsm استفاده می کند. که یک سری فایل با پسوند js هستند که کدهایی گه کارها را انجام میدهد داخل اونهاست و ما با نگاه به اون فایلها از توابع اونها استفاده می کنیم،


البته فایلهای مختلفی را import می کنند ولی همشون این import را دارند.

ولی برنامه ای که ما تا حالا کار می کردیم ، این تکه را نداره. فکر کنم بهتره قالب خود را عوض کنیم و قالب خود را با مثالهای برنامه یکی بکنیم.

ولی مجبور نیستیم داخل اون کدها کار کنیم. من بیرن بسته کار کردم و مسیر را به شکل زیر دادم.
اسم پوشه بسته را هم می بینید عوض کردم و گذاشتم three-js-master




JavaScript:
<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 { OBJLoader } from 'three/addons/loaders/OBJLoader.js';
            import { OrbitControls } from 'three/addons/controls/OrbitControls.js';

            let camera, scene, renderer;

            let object;

نمونه برنامه داخل پوشه examples است , یک طبقه بالاتر از پوشه jsm و یک طبقه پایین تر از پوشه buid
برای همین آدرس ها را در نمونه برنامه ها این جوری می دهند.

ولی من بیرون بسته کار می کنم و آدرس ها را از بالا می دهم.
 

saalek110

Well-Known Member
در برنامه اخیر که کار کردیم و کارش load فایل obj است دو تا فایل صدا زده شده ، یعنی import شده ، یکی فایل لودکننده فایل obj است و دیگری فایل کنترل است. احتمالا اینکه میشه صحنه را چرخاند و بزرگ و کوچک کردن شکل را ، توسط کنترل است.
 

saalek110

Well-Known Member

این سورس از این جهت جالبه که یک مکعب است که میشه به این طرف و اون طرف کشیدش.
فکر کنم سورس ساده ای هم باشه.
برای کلیدهای کیبورد هم قابلیتهایی تعیین کرده.

اجرایش را اینجا ببینید:


من فقط کدش را مرور کوم و هنوز باهاش کار نکردم.

اون نکته ای که در پست قبل گفتن که بهتره قالب خود را به قالب جدید تبدیل کنیم،
دنبال برنامه ساده ای با قالب جدید بودم که شاید این برنامه خوب باشه.احتمالا میشه اضافاتش را حذف کرد.


فعلا من از لینک زیر ، سورس ها را مرور می کنم:

 
آخرین ویرایش:

saalek110

Well-Known Member
پوشه jsm کلا ۱۲ مگا است. یعنی همان فایلهای js که import میشه در برنامه.
پوشه controls شامل حدود ۱۰ تا فایل است و ۲۰۰ کیلو حجمشه.
ولی پوشه examples حجمش حدود ۴۵۰ مگاست.

پس کدها نیست که حجم داره، چیزای دیگس.
مثلا پوشه textures که داخل پوشه exampless است ،حجم ۱۰۰ مگا دارد.
و پوشه مدل که داخل examples است حجم ۲۵۰ مگا دارد.
پس تکسچر و مدلها جمعا حدود ۴۰۰ مگا حجم دارد. فقط می مونه ۵۰ مگا برای باقی پوشه ها.
 
آخرین ویرایش:

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
من فایل فوق را از پوشه examples خارج کردم و کنار بسته three.js قرار دادم و آدرس ها را تنظیم کردم، این قسمت منظورمه:

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

من اسم پوشه three.js را عوض کرده ام و گذاشتم three-js-master
در کد بالا می بینید چطور به جایی که می خواستم در داخل بسته اشاره کرده ام.
داخل کد پست قبل ، مدل و تکسچری موجود نیست.
مکعب های رنگی داریم فقط. پس فقط تنظیم همون آدرس را باید می کردم.

جالبی برنامه اینه که میشه مکعب ها را با لمس تکان داد.

گه احتمالا با اون کنترلی که import کرده این کارو می کند.

یک حلقه for دارد که ۲۰۰ مکعب می ساخت ، من کردم ۱۰ تا. چون صفحه خیلی شلوغ بود.
بعد خط حلقه for می بینید که آبجکت خلق کردن است و بعدش خطوط بعدی چرخاندن راندم اشیای خلق شده است.

مربع ها روی هم سایه می اندازند. به دو خط کد بعد چرخاندن مکعب ها اگر نگاه کنید . کد سایه است ، این خطوط:

JavaScript:
object.castShadow = true;
object.receiveShadow = true;

Screenshot_۲۰۲۴-۱۰-۰۳_۲۲۵۲۰۰.jpg
 
آخرین ویرایش:

saalek110

Well-Known Member
JavaScript:
        <!DOCTYPE html>
<html lang="en">
    <head>
        <title>three.js webgl - animation - groups</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">
    </head>
    <body>

        <div id="info">
            <a href="https://threejs.org" target="_blank" rel="noopener">three.js</a> webgl - animation - groups
        </div>

        <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 Stats from 'three/addons/libs/stats.module.js';

            let stats, clock;
            let scene, camera, renderer, mixer;

            init();

            function init() {

                scene = new THREE.Scene();

                //

                camera = new THREE.PerspectiveCamera( 40, window.innerWidth / window.innerHeight, 1, 1000 );
                camera.position.set( 50, 50, 100 );
                camera.lookAt( scene.position );

                // all objects of this animation group share a common animation state

                const animationGroup = new THREE.AnimationObjectGroup();

                //

                const geometry = new THREE.BoxGeometry( 5, 5, 5 );
                const material = new THREE.MeshBasicMaterial( { transparent: true } );

                //

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

                    for ( let j = 0; j < 5; j ++ ) {

                        const mesh = new THREE.Mesh( geometry, material );

                        mesh.position.x = 32 - ( 16 * i );
                        mesh.position.y = 0;
                        mesh.position.z = 32 - ( 16 * j );

                        scene.add( mesh );
                        animationGroup.add( mesh );

                    }

                }

                // create some keyframe tracks

                const xAxis = new THREE.Vector3( 1, 0, 0 );
                const qInitial = new THREE.Quaternion().setFromAxisAngle( xAxis, 0 );
                const qFinal = new THREE.Quaternion().setFromAxisAngle( xAxis, Math.PI );
                const quaternionKF = new THREE.QuaternionKeyframeTrack( '.quaternion', [ 0, 1, 2 ], [ qInitial.x, qInitial.y, qInitial.z, qInitial.w, qFinal.x, qFinal.y, qFinal.z, qFinal.w, qInitial.x, qInitial.y, qInitial.z, qInitial.w ] );

                const colorKF = new THREE.ColorKeyframeTrack( '.material.color', [ 0, 1, 2 ], [ 1, 0, 0, 0, 1, 0, 0, 0, 1 ], THREE.InterpolateDiscrete );
                const opacityKF = new THREE.NumberKeyframeTrack( '.material.opacity', [ 0, 1, 2 ], [ 1, 0, 1 ] );

                // create clip

                const clip = new THREE.AnimationClip( 'default', 3, [ quaternionKF, colorKF, opacityKF ] );

                // apply the animation group to the mixer as the root object

                mixer = new THREE.AnimationMixer( animationGroup );

                const clipAction = mixer.clipAction( clip );
                clipAction.play();

                //

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

                //

                stats = new Stats();
                document.body.appendChild( stats.dom );

                //

                clock = new THREE.Clock();

                //

                window.addEventListener( 'resize', onWindowResize );

            }

            function onWindowResize() {

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

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

            }

            function animate() {

                const delta = clock.getDelta();

                if ( mixer ) {

                    mixer.update( delta );

                }

                renderer.render( scene, camera );

                stats.update();

            }

        </script>

    </body>
</html>
 

saalek110

Well-Known Member
در مورد تنظیم importmap ، مثل برنامه سابق عمل کردم.

در این خط،

JavaScript:
                const animationGroup = new THREE.AnimationObjectGroup();

یک انیمیشن گروپ ساخته شده. و اشیایی که با حلقه for ساخته شده ، به آن افزوده شده.

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

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

فایل stats هم import شده بود.

قبل حلقه جئومتری و متریال تنظیم شده و داخل حلقه از همان ها استفاده شده.
 
آخرین ویرایش:

saalek110

Well-Known Member
JavaScript:
        <!DOCTYPE html>
<html lang="en">
    <head>
        <title>three.js webgl - lights - spot light</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">
    </head>
    <body>

        <div id="info">
            <a href="https://threejs.org" target="_blank" rel="noopener">three.js</a> - SpotLights<br/>
            by <a href="http://master-domain.com" target="_blank" rel="noopener">Master James</a>
        </div>

        <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 TWEEN from 'three/addons/libs/tween.module.js';
            import { OrbitControls } from 'three/addons/controls/OrbitControls.js';

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

            const camera = new THREE.PerspectiveCamera( 35, window.innerWidth / window.innerHeight, 0.1, 100 );

            const controls = new OrbitControls( camera, renderer.domElement );

            const scene = new THREE.Scene();

            const matFloor = new THREE.MeshPhongMaterial( { color: 0x808080 } );
            const matBox = new THREE.MeshPhongMaterial( { color: 0xaaaaaa } );

            const geoFloor = new THREE.PlaneGeometry( 100, 100 );
            const geoBox = new THREE.BoxGeometry( 0.3, 0.1, 0.2 );

            const mshFloor = new THREE.Mesh( geoFloor, matFloor );
            mshFloor.rotation.x = - Math.PI * 0.5;
            const mshBox = new THREE.Mesh( geoBox, matBox );

            const ambient = new THREE.AmbientLight( 0x444444 );

            const spotLight1 = createSpotlight( 0xFF7F00 );
            const spotLight2 = createSpotlight( 0x00FF7F );
            const spotLight3 = createSpotlight( 0x7F00FF );

            let lightHelper1, lightHelper2, lightHelper3;

            function init() {

                renderer.shadowMap.enabled = true;
                renderer.shadowMap.type = THREE.PCFSoftShadowMap;

                camera.position.set( 4.6, 2.2, - 2.1 );

                spotLight1.position.set( 1.5, 4, 4.5 );
                spotLight2.position.set( 0, 4, 3.5 );
                spotLight3.position.set( - 1.5, 4, 4.5 );

                lightHelper1 = new THREE.SpotLightHelper( spotLight1 );
                lightHelper2 = new THREE.SpotLightHelper( spotLight2 );
                lightHelper3 = new THREE.SpotLightHelper( spotLight3 );

                mshFloor.receiveShadow = true;
                mshFloor.position.set( 0, - 0.05, 0 );

                mshBox.castShadow = true;
                mshBox.receiveShadow = true;
                mshBox.position.set( 0, 0.5, 0 );

                scene.add( mshFloor );
                scene.add( mshBox );
                scene.add( ambient );
                scene.add( spotLight1, spotLight2, spotLight3 );
                scene.add( lightHelper1, lightHelper2, lightHelper3 );

                document.body.appendChild( renderer.domElement );
                window.addEventListener( 'resize', onWindowResize );

                controls.target.set( 0, 0.5, 0 );
                controls.maxPolarAngle = Math.PI / 2;
                controls.minDistance = 1;
                controls.maxDistance = 10;
                controls.update();

            }

            function createSpotlight( color ) {

                const newObj = new THREE.SpotLight( color, 10 );

                newObj.castShadow = true;
                newObj.angle = 0.3;
                newObj.penumbra = 0.2;
                newObj.decay = 2;
                newObj.distance = 50;

                return newObj;

            }

            function onWindowResize() {

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

            }

            function tween( light ) {

                new TWEEN.Tween( light ).to( {
                    angle: ( Math.random() * 0.7 ) + 0.1,
                    penumbra: Math.random() + 1
                }, Math.random() * 3000 + 2000 )
                    .easing( TWEEN.Easing.Quadratic.Out ).start();

                new TWEEN.Tween( light.position ).to( {
                    x: ( Math.random() * 3 ) - 1.5,
                    y: ( Math.random() * 1 ) + 1.5,
                    z: ( Math.random() * 3 ) - 1.5
                }, Math.random() * 3000 + 2000 )
                    .easing( TWEEN.Easing.Quadratic.Out ).start();

            }

            function updateTweens() {

                tween( spotLight1 );
                tween( spotLight2 );
                tween( spotLight3 );

                setTimeout( updateTweens, 5000 );

            }

            function animate() {

                TWEEN.update();

                if ( lightHelper1 ) lightHelper1.update();
                if ( lightHelper2 ) lightHelper2.update();
                if ( lightHelper3 ) lightHelper3.update();

                renderer.render( scene, camera );

            }

            init();
            updateTweens();

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

saalek110

Well-Known Member
باز مثل برنامه های قبلی ، importmap را تنظیم کردم.

در برنامه بالا ، tween را import کرده.

حالا tween چیه؟
در سایت زیر:



این طوری نوشته:

A tween (from in-between) is a concept that allows you to change the values of the properties of an object smoothly.
یعنی tween که از between گرفته شده به معنی ((بین)) پراپرتی یک آبجکت را به آرامی تغییر می دهد. Smoothly فکر کنم یعنی به نرمی. بدون سختی و مشکل هم معنی می دهد. ولی اینجا فکر کنم حرکت نرم منظور است.

در برنامه بالا نورها ، نرم حرکت می کنند.

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

مثال برای spot light helper:
JavaScript:
const spotLight = new THREE.SpotLight( 0xffffff );
spotLight.position.set( 10, 10, 10 );
scene.add( spotLight );

const spotLightHelper = new THREE.SpotLightHelper( spotLight );
scene.add( spotLightHelper );

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

منبع:


در این برنامه احتمالا ، tween منظورش بوده. ولی هلپر نور را هم دیدیم. فکر کنم هلپر برای تشخیص شعاع های نوری است.
 
آخرین ویرایش:

saalek110

Well-Known Member
سالک: من در مثالهای پوشه examples ، تصادفی یک فایل را باز می کنم و در تاپیک توضیح می دهم ، بخاطر همین ، انسجام نداره کار. شما سعی کن ، چیزهای مجهول را رها کنید و فقط مرور کنید تا بتونیم بعدا به یک جای با انسجام برسیم.

مرور کدها کمک می کند ، وارد حال و هوای three.js بشویم. ولی مسلما یک آموزش حساب کتاب دار خیلی خوبه.
 

saalek110

Well-Known Member
محتوای SpotLightHelper.js:


JavaScript:
import { Vector3 } from '../math/Vector3.js';
import { Object3D } from '../core/Object3D.js';
import { LineSegments } from '../objects/LineSegments.js';
import { LineBasicMaterial } from '../materials/LineBasicMaterial.js';
import { Float32BufferAttribute } from '../core/BufferAttribute.js';
import { BufferGeometry } from '../core/BufferGeometry.js';

const _vector = /*@__PURE__*/ new Vector3();

class SpotLightHelper extends Object3D {

    constructor( light, color ) {

        super();

        this.light = light;

        this.matrixAutoUpdate = false;

        this.color = color;

        this.type = 'SpotLightHelper';

        const geometry = new BufferGeometry();

        const positions = [
            0, 0, 0,     0, 0, 1,
            0, 0, 0,     1, 0, 1,
            0, 0, 0,    - 1, 0, 1,
            0, 0, 0,     0, 1, 1,
            0, 0, 0,     0, - 1, 1
        ];

        for ( let i = 0, j = 1, l = 32; i < l; i ++, j ++ ) {

            const p1 = ( i / l ) * Math.PI * 2;
            const p2 = ( j / l ) * Math.PI * 2;

            positions.push(
                Math.cos( p1 ), Math.sin( p1 ), 1,
                Math.cos( p2 ), Math.sin( p2 ), 1
            );

        }

        geometry.setAttribute( 'position', new Float32BufferAttribute( positions, 3 ) );

        const material = new LineBasicMaterial( { fog: false, toneMapped: false } );

        this.cone = new LineSegments( geometry, material );
        this.add( this.cone );

        this.update();

    }

    dispose() {

        this.cone.geometry.dispose();
        this.cone.material.dispose();

    }

    update() {

        this.light.updateWorldMatrix( true, false );
        this.light.target.updateWorldMatrix( true, false );

        // update the local matrix based on the parent and light target transforms
        if ( this.parent ) {

            this.parent.updateWorldMatrix( true );

            this.matrix
                .copy( this.parent.matrixWorld )
                .invert()
                .multiply( this.light.matrixWorld );

        } else {

            this.matrix.copy( this.light.matrixWorld );

        }

        this.matrixWorld.copy( this.light.matrixWorld );

        const coneLength = this.light.distance ? this.light.distance : 1000;
        const coneWidth = coneLength * Math.tan( this.light.angle );

        this.cone.scale.set( coneWidth, coneWidth, coneLength );

        _vector.setFromMatrixPosition( this.light.target.matrixWorld );

        this.cone.lookAt( _vector );

        if ( this.color !== undefined ) {

            this.cone.material.color.set( this.color );

        } else {

            this.cone.material.color.copy( this.light.color );

        }

    }

}


export { SpotLightHelper };
 

saalek110

Well-Known Member
خواستم کمی هم با کدهای درون فایلهای جاوا اسکریپتی که import می کنیم آشنا شویم.
می بینید که فایل بالا ، تعداد خطوط کمی دارد. همچنین چندین فایل دیگر را import کرده.
 

saalek110

Well-Known Member
JavaScript:
import * as THREE from 'three';

const scene = new THREE.Scene();
const camera = new THREE.PerspectiveCamera( 75, window.innerWidth / window.innerHeight, 0.1, 1000 );

const renderer = new THREE.WebGLRenderer();
renderer.setSize( window.innerWidth, window.innerHeight );
document.body.appendChild( renderer.domElement );

ایجاد صحنه یا scene .
می بینید که three را ایمپورت کرده و با فایلهای داخل پوشه jsm کاری نداشته.
اینکه خود فایلهای hree چه کارهایی انجام می دهند و فایلهای داخل پوشه jsm چه کاری انجام میدهند ، یک بحثی است که شاید بعدا به آن پرداختیم.

در سایت فوق گفته در three چند نوع camera داریم و اجازه دهید نوع PerspectiveCamera را در اینجا برگزینیم.


منبع:
 

saalek110

Well-Known Member
پارامتر اول این دوربینfield of view یا fov است.
که به درجه است.

پارمتر دوم aspect ratio است. عرض تقسیم بر طول. سایت گفته وقتی فیلم قدیمی را بر تلویزیون عریض می اندازیم squished میشه. معنی این کلمه را دقیق نمی دونم ، شاید فشرده میشه یا لهیده میشه. یا برعکس کشیده میشه. خلاصه خواسته بگه نسبت عرض به طول چیه.

پارامترهای سوم و چهارم: The next two attributes are the near and far clipping plane
صفحات دور و نزدیک . یعنی هر چیزی که دورتر از صفحه دوره یا نزدیکتره از صفحه نزدیکه باشه ، رندر نمیشه و گفته شما نگران این چیزها نباشید.
 

saalek110

Well-Known Member
بعدش این کد را گذاشته:


JavaScript:
const geometry = new THREE.BoxGeometry( 1, 1, 1 );
const material = new THREE.MeshBasicMaterial( { color: 0x00ff00 } );
const cube = new THREE.Mesh( geometry, material );
scene.add( cube );

camera.position.z = 5;

بعدش این کد:


JavaScript:
function animate() {
    renderer.render( scene, camera );
}
renderer.setAnimationLoop( animate );

قسمت رندر است.‌
یک حلقه ایجاد می کنه برای رندر. ۶۰ بار بر ثانیه.

کدهای بالا را کنار هم بزاریم یک مکعب را نشون می دهد.
کد زیر باعث حرکتش میشه:
JavaScript:
cube.rotation.x += 0.01;
cube.rotation.y += 0.01;

داخل تابع animate بزارید.
 

saalek110

Well-Known Member
HTML:
<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="utf-8">
        <title>My first three.js app</title>
        <style>
            body { margin: 0; }
        </style>
    </head>
    <body>
        <script type="module" src="/main.js"></script>
    </body>
</html>

JavaScript:
import * as THREE from 'three';

const scene = new THREE.Scene();
const camera = new THREE.PerspectiveCamera( 75, window.innerWidth / window.innerHeight, 0.1, 1000 );

const renderer = new THREE.WebGLRenderer();
renderer.setSize( window.innerWidth, window.innerHeight );
renderer.setAnimationLoop( animate );
document.body.appendChild( renderer.domElement );

const geometry = new THREE.BoxGeometry( 1, 1, 1 );
const material = new THREE.MeshBasicMaterial( { color: 0x00ff00 } );
const cube = new THREE.Mesh( geometry, material );
scene.add( cube );

camera.position.z = 5;

function animate() {

    cube.rotation.x += 0.01;
    cube.rotation.y += 0.01;

    renderer.render( scene, camera );

}

دوو فایل بالا که اولی html است و دومی فایل js با هم برنامه را می سازند.
قبلا در تاپیک اینها را دیده بودید، یک مروری کردیم باز.
 

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

بالا