آموزش Three.js

saalek110

Well-Known Member
سالک: اینکه three.js مقداری یا همش برپایه webgl است یک بحث است.
اون اقا یا خانم هم در ۳ پست قبل می گفت اگر webgl شروع می کردید ، shader ها اولین چیزهایی بود که باید کار می کردید.

من نمی خوام اینجا وارد بحث webgl یا shader بشم ، ولی بد نیست گاهی به اطراف خود هم نگاهی بیاندازیم.
ما اینجا three.js کار می کنیم. کاری نداریم بر پایه webgl است یا هر چیز دیگر. ولی داشتن مقداری اطلاعات کمک می کنه محیط کار خود را بهتر درک کنیم.

پس کمی در مورد shader ااطلاعات کسب کردیم.
 

saalek110

Well-Known Member
بسته فوق ، یک پوشه داره به نام mathbox

نتیجه اجرای یک از اونها عکس زیر است:

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

اولش داریم:
JavaScript:
    <script src="dat.gui.js"></script>

کلش هم اینه:
JavaScript:
<!doctype html>
<html lang="en">
<head>
    <title>DAT.GUI</title>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
    <script src="dat.gui.js"></script>
</head>
<body>

<script>

var gui = new dat.GUI();

// Note: variables used by dat.gui do not need to be declared within an object;
//  they can be global variables, in which case replace the object name ("parameters" in this example)
//  by "this" when adding the controls to the gui object below.

var parameters =
{
    a: 200, // numeric
    b: 200, // numeric slider
    c: "Hello, GUI!", // string
    d: false, // boolean (checkbox)
    e: "#ff8800", // color (hex)
    f: function() { alert("Hello!") },
    g: function() { alert( parameters.c ) },
    v : 0,    // dummy value, only type is important
    w: "...", // dummy value, only type is important
    x: 0, y: 0, z: 0
};

gui.add( parameters, 'a' ).name('Number');
gui.add( parameters, 'b' ).min(128).max(256).step(16).name('Slider');
gui.add( parameters, 'c' ).name('String');
gui.add( parameters, 'd' ).name('Boolean');

gui.addColor( parameters, 'e' ).name('Color');

var numberList = [1, 2, 3];
gui.add( parameters, 'v', numberList ).name('List');

var stringList = ["One", "Two", "Three"];
gui.add( parameters, 'w', stringList ).name('List');

gui.add( parameters, 'f' ).name('Say "Hello!"');
gui.add( parameters, 'g' ).name("Alert Message");

var folder1 = gui.addFolder('Coordinates');
folder1.add( parameters, 'x' );
folder1.add( parameters, 'y' );
folder1.close();
gui.open();

</script>

</body>
</html>
 

saalek110

Well-Known Member
پنجره Gui برای دسترسی به اعداد داخل برنامه:


استفاده از برنامه بالا در برنامه خودمان:

سالک:شاید شما هم پیش خودتون گفته باشید ، اینو به برنامه ام اضافه کنم ، خوب من هم همین فکر را کردم و این کار را انجام دادم. اون فایل را پیدا کردم و گذاشتم کنار برنامه ام و کدهای برنامه را وارد برنامه خود کردم.هر چی وسط تگ های script بود را کپی کردم بردم برنامه خودم.

نتیجه اینکه اون پنجره سیاه اومد روی برنامه من.

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


و وقتی در اون پنجره number را تغییر می دادم. در برنامه هم مقدار number تغییر می کرد. البته اسم کاملش را باید بنویسید:
JavaScript:
alert(parameters.a);

یعنی کلمه parameters باید قبلش بیاید.
کد بالا را کجا بنویسیم؟ خیلی جاها میشه نوشت ولی من یک تابع ساختم که که با تابع setinterval هر ۱۰ ثانیه اجرا میشه ، اونجا نوشتم. قبلا در تاپیک کدش را گذاشتم.

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


در انتهایش اگر ضربه بزنیم بسته میشه و دوباره اگر بزنیم باز میشه.
 
آخرین ویرایش:

saalek110

Well-Known Member
جالا یک لحظه برگردیم به بحث قبلی:

یک نقلی کردیم از اون آقا در مورد shader ....
اجازه دهید چند خط دیگه بخونیم:

A shader is a program written in GLSL that is sent to the GPU. They are used to position each vertex of a geometry and to colorize each visible pixel of that geometry. The term "pixel" isn't accurate because each point in the render doesn't necessarily match each pixel of the screen and this is why we prefer to use the term "fragment" so don't be surprised if you see both terms.

Then we send a lot of data to the shader such as the vertices coordinates, the mesh transformation, information about the camera and its field of view, parameters like the color, the textures, the lights, the fog, etc. The GPU then processes all of this data following the shader instructions, and our
geometry appears in the render.
میگه shader یک برنامه است که با GLSL نوشته شده. که به GPU ارسال شده.
که هر ورتکس از جئومتری را مشخص می کند و هر پیکلس جئومتری را کالورایز می کند. احتمالا یعنی رنگ می کند.

سپس ما همه چیز را به shader می فرستیم.

سالک: حالا من خلاصه ترجمه کردم.اینم لینکش:



سالک: من یک مقدار کدهای پوشه shader در پوشه js این بسته قدیمی را نگاه کردم..بعضی جاهاش شبیه زبان سی است ، مثلا کلمه main اومده و کلا حس و حال کدهای زبان سی را به من منتقل می کنه. حالا شاید کس دیگر چنین حسی پیدا نکند و حس من کاذب باش. پس گفتم GLSL را سرچ کنم ببینم چیه.
 
آخرین ویرایش:

saalek110

Well-Known Member
OpenGL Shading Language (GLSL) is a high-level shading language with a syntax based on the C programming language. It was created by the OpenGL ARB (OpenGL Architecture Review Board) to give developers more direct control of the graphics pipeline without having to use ARB assembly language or hardware-specific languages.


سالک: انگار حس من درست می گفت. اولین زبانهایی که من کار کردم اسمبلی و سی بود. اسمبلی را در فروم گفتمان کار کروم. الان دیگه این فروم وجود نداره. اولین زبانی بود که آموزش دادم اسمبلی بود. بعدش سی پلاس کار کردم. بعدا سی شارپ و دلفی و php کار کردم.

در بالا گفته شده GLSL سینتکس زبان سی دارد. High level shading language است یعنی زبان سطح بالای shader نویسی . به وسیله فلان شرکت که در متن بالا گفته ایجاد شد تا به دولوپرها ، کنترل مستقیم بیشتر به گرافیک پیپ لاین بدهد ، بدون نیاز به ARB assembly یا زبانهای مختص سخت افزار.

پس GLSL یک راه راحت بوده و قبلش اون ARB assembly بوده.

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

خلاصه پس این شد که shader با زبان GLSL نوشته شده و GLSL هم یک زبانی شبیه سی است که به گرافیک پیپ لاین دست اندازی می کند و نیاز به زبانهای بدتر را برطرف کرده ، مثل ARB اسمبلی.

فکر نکنم بخواهید بفهمید گرافیک پیپ لاین چیه. می خواهید؟ دیگه دیر شد برای جواب دادن....


در گرافیک سه‌بعدی رایانه‌ای پایپ لاین گرافیک (به انگلیسی: graphics pipeline یا rendering pipeline) به سلسله‌ای از مراحل که برای ساختن صفحات ۲بعدی و برای نمایان کردن صحنه‌های ۳ بعدی استفاده می‌شود گویند. به زبان ساده وقتی یک نگاره ۳بعدی مانند تصاویری از یک بازی رایانه‌ای در رایانه ایجاد می‌گردد، پایپ لاین گرافیک به مجموعه پردازش‌هایی که این تصویر را بر نمایشگر قابل دیدن می‌سازد گویند.


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

saalek110

Well-Known Member

گویا dat gui مدت طولانی استفاده شده ، جایگزین امروزی اون فکر کنم اسمش lil gui است.

در بسته قبلی که برای ۸ سال پیش بود dat gui را داشت و من در پست زدم و به برنامه خودم هم افزودم و عکس گذاشتم. چند پست قبل.


حالا تاریخ این بسته برای دو سال پیش است. دکمه سبز را بزنید و دانلود زیپ را بزنید.

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

در پوشه تست اون یک برنامه است که وقتی اجرا میشه اینها را می نویسد:
JavaScript:
Tests completed in 1339 milliseconds.
258 tests of 258 passed, 0 failed.

Color Math: rgb_to_hex (0, 1, 1)Rerun
Color Math: component_from_hex (0, 3, 3)Rerun
Color Math: hex_with_component (0, 3, 3)Rerun
Color Math: rgb_to_hsv (0, 9, 9)Rerun
Color Math: hsv_to_rgb (0, 6, 6)Rerun
Color Interpretations: CSS Strings (0, 20, 20)Rerun
Color Interpretations: Other (0, 36, 36)Rerun
Color Objects: Creation (0, 8, 8)Rerun
Color Objects: RGB Modification (0, 8, 8)Rerun
Color Objects: RGB Modification (0, 8, 8)Rerun
Color Objects: Setting RGB, Modifying HSV (0, 4, 4)Rerun
Color Objects: Setting HSV, Modifying RGB (0, 4, 4)Rerun
Color Objects: Grayscale Hue (0, 2, 2)Rerun
Color Objects: Black Hue (0, 1, 1)Rerun
Controller: Retrieves values (0, 4, 4)Rerun
Controller: Sets values (0, 1, 1)Rerun
BooleanController: Acknowledges original values (0, 2, 2)Rerun
BooleanController: Modifies values (starting true) (0, 6, 6)Rerun
BooleanController: Modifies values (starting false) (0, 6, 6)Rerun
OptionController: Populates with string array (0, 6, 6)Rerun
OptionController: Populates with map (0, 3, 3)Rerun
OptionController: Acknowledges original value (0, 1, 1)Rerun
OptionController: Modifies values (0, 2, 2)Rerun
StringController: Acknowledges original value (0, 1, 1)Rerun
StringController: Modifies values (0, 1, 1)Rerun
NumberController: Constraints (0, 3, 3)Rerun
NumberControllerBox: Acknowledges original value (0, 1, 1)Rerun
NumberControllerBox: Modifies value (0, 2, 2)Rerun
NumberControllerBox: Handles invalid input (0, 2, 2)Rerun
NumberControllerBox: Handles drag (0, 1, 1)Rerun
NumberControllerSlider: Acknowledges original value (0, 1, 1)Rerun
NumberControllerSlider: Modifies values (0, 5, 5)Rerun
ColorController: Get Color (0, 1, 1)Rerun
Controller Events: onChange (0, 6, 6)Rerun
Controller Events: onFinishChange (0, 6, 6)Rerun
GUI Appearance: Auto placement (0, 8, 8)Rerun
GUI Appearance: Auto placement scroll (0, 0, 0)Rerun
GUI Appearance: close/open button position (0, 3, 3)Rerun
GUI Appearance: Folders (0, 8, 8)Rerun
GUI Controller Methods: options (0, 20, 20)Rerun
GUI Controller Methods: name (0, 2, 2)Rerun
GUI Controller Methods: listen (0, 0, 0)Rerun
GUI Controller Methods: remove (0, 2, 2)Rerun
GUI Controller Methods: removeFolder (0, 2, 2)Rerun
GUI Controller Methods: min, max & step (0, 10, 10)Rerun
GUI Controller Augmentation: Adds NumberControllerBox to sliders (0, 1, 1)Rerun
GUI Controller Augmentation: Clickable rows for BooleanControllers (0, 3, 3)Rerun
GUI Controller Augmentation: Clickable rows for FunctionControllers (0, 3, 3)Rerun
GUI Saving: Remembering values (0, 4, 4)Rerun
GUI Saving: Presets (0, 18, 18)Rerun

لینک زیر برای رنگ روشن آن است. فایل css دارد:
 
آخرین ویرایش:

saalek110

Well-Known Member
من حین ساخت دنیای خود ، کدهایش را اینجا میگم.

اگر بخواهید یک مکعب جلوی شما خلق بشود ، بسته به زاویه نگاه شما دارد. مثلا اگر به سمت شمال نگاه کنید مکعب باید در سمت شما شما ایجاد شود و با یک فاصله از دوربین. و اگر به شرق نگاه کنید ، مکعب باید در سمت شرق شما ایجاد شود ، با یک فاصله. در برنامه من اون فاصله را فعلا ۲۰ گرفتم.

JavaScript:
    mesh.position.x = camera.position.x+Math.sin(rotation)*-20;
    mesh.position.y = camera.position.y-1;
    mesh.position.z = camera.position.z+Math.cos(rotation)*-20;

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

باقی کد را دیگه ننوشتم. از کدهای دیگر کمی کنید. شامل ایجاد جئومتری و ایجاد تکسچر و ایجاد متریال و ایجاد شی .
یادتون هست که شی از جئومتری و ماتریال ساخته میشد.
من فقط کد مکان نشستن شی را گفتم. کد افزودن به صحنه یا scene هم فراموش نشود.

الان در برنامه من با زدن یک دکمه ، جلوی دید او یک مکعب خلق می شود.
در مورد ساخت دکمه ها و کدش قبلا صحبت کردیم. از همون کدها من کپی کردم برای دکمه های جدید.

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

saalek110

Well-Known Member
یک برنامه به نام حصار کشی ، چند پست قبل داشتیم ، که با حلقه یک سری آبجکت ساخت ،
در اخر ، ابجکت ها را در متغیر می ریخت.

من همین کارو کردم. و بعد توانستم با آوردن اسم متغیر و شماره ای که داخل آرایه ذخیره شده بود مقدار x آبجکت را تغییر دهم. شی هایی که به طور خودکار تولید می شود را داخل آرایه می ریزند تا قابل حرکت دادن باشد و کارهای دیگر هن بشود با آنها کرد.

در گام بعد خواستم ببینم شی قبلی را هم میشه حرکت داد ، پس نوشتم:

JavaScript:
st[ct-1].position.x+=1;

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

saalek110

Well-Known Member
خیابان کشی:

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

saalek110

Well-Known Member
نکته خیلی مهم:

اگر برنامه بزرگ است ، روی کپی برنامه اصلی کار کنید ، تا اگر خطایی ایجاد شد که نمی شود پیدا کرد ، کپی را دیلت کنید و یک کپی دیگر بگیرید و روی اون کار کنید.


این کار خیلی راحت تر از اینه که دقایق زیادی برای پیدا کردن خطا صرف کنید.

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

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

saalek110

Well-Known Member
نمایش مختصات بازیکن بالای برنامه:


قبلا گفتم چطوری تابعی بسازید که هر چند ثانیه اجرا بشود ، با setintervel در اول init

من بعد body یعنی اول برنامه یک پراگراف ساختم. این طوری:


HTML:
    <p id="p1">hello</p>

بعد در تابع تایمر این را نوشتم:

JavaScript:
       let q1 = document.getElementById("p1");
              q1.innerHTML ="welcome";

اسم q1 ساختگی و دلخواه است.
این کار باعث شد متن پاراگراف عوض بشه.

بعدش به کد زیر تبدیل کردم:


JavaScript:
              q1.innerHTML =camera.position.x;

که x دوربین را بالای برنامه نمایش می دهد.

شاید بشه در تابع animate هم نوشت ولی تابع animate فرکانس اجرایش خیلی بالاست و به نظر من نباید یک پروسسی که هر دو ثانیه نیاز به اجرا داره را در تابع animate بیاندازیم. چون یک پردازش اضافه با سرعت تکرار بالاست و حیفه مشغولیت بی خودی برای سیستم ایجاد کنیم. تایمر کد بالا را میشه یک ثانیه یا نیم ثانیه یا حتی چند ثانیه تنظیم کرد. بنا به نیاز اون کار است. مثلا اگر گاهگاهی می خواهید ببینید کجای زمین هستید ، ده ثانیه هم خوبه. ولی برای بعضی کارها خوب باید زودتر اعلام بشه. این دیگه به موقعیت و نیاز شما بستگی دارد.

من مدتها قبل یک بازی دیدم که با همین ساخت تایمر ، افتادن بلوک ها را مدیریت می کرد. یعنی هر نیم ثانیه بررسی می کرد زیر بلوک خالی هست یا نه، اگر خالی بود سقوطش می داد. این جوری ازهدر رفتن سیستم با چک پشت سر هم و با فرکانس بالا جلوگیری کرده بود.
 
آخرین ویرایش:

saalek110

Well-Known Member
یک نکته هم در مورد بازی سازی بگم..

نباید همه اشیای بازی را نمایش داد ، چون فشار بیخودی است.
اون اشایی را اجرا کنید که اطراف بازیکن است.
در یک سایت سه بعدی که بودم ، دورها را نمیشد دید ، باید می رفتی جلو تا ببینی اون جلو چیه. البته آزاردهنده بود چون خوب قضیه اجرا نشده بود.
مثلا یک کوه باید کلیاتش اجرا بشه ، چون کوه از دور دیدن داره. از نزدیک که میشه زمین.
بعضی بازی سازها بهتر این را اجرا کرده اند.
یک بازی ماشین بود ، باز ار یک فاصلهوای بیشتر را نمایش نمی داد و انگار اشیا از تاریکی بیرون می آمدند ، جوری بود که به جای اینکه حواس آدم به بازی باشه ، به یهو پدیدار شدن اشیا نگاه می کردی.
 

saalek110

Well-Known Member
لامبرت متریال و بیسیک متریال



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

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

چمن هم لامبرت است. اثر منبع نور را روی چمن و مکعب سمت راستی می بینید.

JavaScript:
light.intensity = 0.5;
light.color.setHex( 0xff0000 );

شدت و رنگ نور ، را در کد بالا می بینیم.

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

saalek110

Well-Known Member
کد چرخش:

JavaScript:
    mesh.rotateZ(Math.PI/180 * 90);

کد بالا برای چرخش ۹۰ درجه ای است.
محیط دایره 2pr بود. مساحت pr^2 پی * آر به توان ۲.
ما اینجا با محیط کار داریم نه مساحت. پس اگر ۲p محیط بود ، نصف محیط میشه p و اگر تقسیم بر ۱۸۰ کنیم میشه درجه. در فرمول بالا نصف محیط را تقسیم بر ۱۸۰ کرده تا درجه بدست بیاید. ولی اگر یادتون باشه از ریاضی ، پی تقسیم بر دو همان ۹۰ درجه بود. در فرمول بالا ، هم ۹۰ را با ۱۸۰ ساده کنی ، یعنی هر دو را تقسیم بر ۹۰کنیم ، همون p/2 میشه. اون Z را اگر بزارید به جاش X یا Y میشه چرخش در جهات دیگر.



----------------------
برای چرخش ۹۰ درجه ، میشه ۶ تا ۱۵ درجه در نظر گرفت ، یعنی با ۶ بار دکمه زدن ، بشود ۹۰ درجه ، و ۱۵ درجه میشه یک ششم ۹۰ درجه که میشه عدد پی تقسیم بر ۱۲.چون ۹۰ درجه عدد پی تقسیم بر ۲ بود.

این ۶ بار دکمه زدن برای چرخش ۹۰ درجه را از یک محیط ۳ بعدی یادمه و بهش عادت کرده بودم. ولی نمیگم ایده آل است یا بد. فقط یک تصمیم بوده در یک طراحی.
 
آخرین ویرایش:

saalek110

Well-Known Member
نرم افزارهای اسکن مدل در گوگل استور....
یک شی را از هر طرف فیلم یا عکس می گیریم. مدل سه بعدی آن تهیه می شود.
 

saalek110

Well-Known Member
من در اون محیط سه بعدی که دارم می سازم ، مشغول ذخیره آبجکت ها در دیتابیس هستم.
به نظرم ستون های جدول آبجکت ها، برای مختصات و سایز آبجکت ها باید float باشه نه int.
چون برای چیدن دقیق تر و سایز دقیق تر اجسام ، اعداد اعشاری است.
 

saalek110

Well-Known Member
تغییر سایز یک شکل ، مثلا دو برابر کردن:

JavaScript:
mesh.scale.x = 500;

برای ابعاد دیگر به جای x حروف y و z را بگذارید.



منبع:
 
آخرین ویرایش:

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

بالا