Three.js: المادة: تمت الإضافة onBeforeCompile ()

تم إنشاؤها على ٩ يونيو ٢٠١٧  ·  75تعليقات  ·  مصدر: mrdoob/three.js

على مر السنين ، كان طلب الميزة المشتركة هو القدرة على تعديل المواد المدمجة. أدركت اليوم أنه يمكن تنفيذه بطريقة مماثلة لـ Object3D 's onBeforeRender() .

https://github.com/mrdoob/three.js/commit/e55898c27a843f69a47e602761c60d9bbe91ee35

يضيف WebGLPrograms onBeforeCompile.toString() إلى تجزئة البرنامج حتى لا يؤثر ذلك على المواد المضمنة الأخرى المستخدمة في المشهد.

فيما يلي مثال على الميزة قيد التشغيل:

http://rawgit.com/mrdoob/three.js/dev/examples/webgl_materials_modified.html

material.onBeforeCompile = function ( shader ) {

    // console.log( shader )

    shader.uniforms.time = { value: 0 };

    shader.vertexShader = 'uniform float time;\n' + shader.vertexShader;
    shader.vertexShader = shader.vertexShader.replace(
        '#include <begin_vertex>',
        'vec3 transformed = vec3( position.x + sin( time + position.y ) / 2.0, position.y, position.z );'
    );

    materialShader = shader;

};

لا يمكننا العبث برمز التظليل فحسب ، بل يمكننا إضافة زي موحد مخصص.

if ( materialShader ) {

    materialShader.uniforms.time.value = performance.now() / 1000;

}

هل هو مبتذل جدا؟

/ سم مكعبWestLangleybhoustontschw

Enhancement

التعليق الأكثر فائدة

mrdoob أعتقد أنه من الصعب (أو من المستحيل) إجراء تسلسل للمواد المخترقة باستخدام .onBeforeCompile() . هل تعتقد أنه يجب على المستخدمين استخدام ShaderMaterial إذا كانوا يريدون مواد مضمنة معدلة كاملة الوظائف (تصيير ، نسخ ، استنساخ ، تسلسل ، وما إلى ذلك)؟

لم أتوقع (اعتبر) استخدام onBeforeCompile() متسلسلًا ...

ال 75 كومينتر

يبدو من الاختراق بعض الشيء أن تطلب معالجة سلسلة مخصصة عندما يقوم WebGLProgram.js بالفعل بالكثير من المعالجة. هناك حالة استخدام ذات صلة ، وهي إضافة # تضمين جديد بدلاً من تجاوز العناصر الموجودة. يمكنك القيام بذلك اليوم عن طريق تعديل THREE.ShaderLib في وقت التشغيل ، لكنه يبدو متسخًا بنفس القدر.

ربما يكون الحل الأفضل لكليهما هو السماح لك بتوفير ShaderLib مخصص لمادة ، والذي من شأنه تجاوز / زيادة القطع المدمجة دون التلاعب اليدوي بالوتار ودون إزعاجها بشكل دائم. هذا لا يمنع ربط onBeforeCompile للاستخدامات الأخرى ، لكنه يبدو أكثر انسجامًا مع ما يحاول مثالك القيام به.

ومع ذلك ، فإن تركيبة التظليل القائمة على التضمينات الخام ستكون دائمًا هشة للغاية من إصدار إلى آخر. إذا كنت لا تمانع في تضمين كل الشفرة الهيكلية (مثل meshphong_vert.glsl ) ، فيمكنك بالفعل توسيع المواد المضمنة بشيء مثل هذا:

export class MyPhongMaterial extends ShaderMaterial {
  constructor({ color, radius, map, normalMap, emissiveMap }) {
    super();
    this.vertexShader = "...."
    this.fragmentShader = "....";
    this.uniforms = UniformsUtils.clone(ShaderLib.phong.uniforms);

    this.isMeshPhongMaterial = true;
    this.lights = true;

    this.uniforms.time = { value: 1 };
    //...
  }
}

في جميع الحالات ، عليك الاعتماد على التنظيم الداخلي للتظليل المدمج حتى لا تتغير كثيرًا من إصدار إلى آخر. كل تضمين هو بالفعل وظيفة مقنعة ، مع توقيع غير محدد. أظن أنه سيكون أكثر نظافة ويمكن صيانته على كلا الجانبين لتوفير مستوى الوظيفة بدلاً من تجاوزات مستوى التضمين.

اعتقدت اليوم ..

لطيف - جيد! اعتقدت ذلك أيضًا في 10 فبراير عندما قدمت طلب السحب هذا:

https://github.com/mrdoob/three.js/pull/10791

يبدو أن الاختلاف الوحيد هو أنك تفعل ذلك من خلال رد الاتصال؟ لقد دخلت في الحجة غير المستخدمة في WebGLRenderer.

أحب استخدام هذا على سبيل المثال لجعل threejs تعمل مع الخرائط العادية ، لكنني ربطت بعض المشكلات التي يبدو أنها ستكون تافهة لحلها مع هذا.

يمكنك إلقاء نظرة على فرعي وتأخذ هذا في جولة أو التحقق من هذا المثال البسيط للغاية (فقط اختبر تشوهًا مخصصًا مع الإضاءة / الظلال وما إلى ذلك ، ويضيف بعض الزي الرسمي).

http://dusanbosnjak.com/test/webGL/three-material-shader-override/webgl_materials_shader_override.html

ربما يكون الحل الأفضل لكليهما هو السماح لك بتوفير ShaderLib مخصص لمادة ، والذي من شأنه تجاوز / زيادة القطع المدمجة دون التلاعب اليدوي بالوتار ودون إزعاجها بشكل دائم.

يلخص بالضبط ما يحدث في: https://github.com/mrdoob/three.js/pull/10791 أتمنى لو كان بإمكاني كتابة أوصاف أفضل :)


يجب أن أعترف أنني لا أعرف ما يحدث هنا. أعتقد أنني أعرف شخصًا تخلى عن المساهمة في ثلاثة ، ولم أفهم ذلك بعد ذلك ، لكنني الآن أجده محبطًا نوعًا ما.

محبط في الغالب لأنني أواجه ديجا فو عندما قرأت الفقرة الأولى:

... طريقة مشابهة لـ Object3D's onBeforeRender ().

حدث نفس الشيء بالضبط مع onBeforeRender() https://github.com/mrdoob/three.js/pull/9738 ، عندما استغرق الأمر عامًا من الإقناع للحصول على الميزة.

Jeez ، مرتين ، مع نفس المطور؟ من الواضح أنني أفعل شيئًا خاطئًا هنا ، لكن ماذا؟ كانت المرة الأولى التي يتم فيها إيداع ملفات الإنشاء ، ولم أكن أعرف ماذا أفعل ، وتم نسيانها للتو. لكن هذه المرة كنت على رأس طلب السحب هذا ، هناك صراع في الوقت الحالي ولكن تم حله بسهولة ، ولم تكن هناك صراعات لأشهر.

لا تفهموني بشكل خاطئ ، لا أعتقد أنه من الغرور في الأعمال هنا ، أعتقد أنني أريد فقط تشغيل الأفكار من قبل الناس والحصول على ردود الفعل. unconed من الواضح أنك على دراية بالمشكلة وربما تكون قد جربت أشياء مختلفة. ما الذي ربما تسبب في فقدان مستخدم مثلك للعلاقات العامة الأخرى؟

شعرت بالرضا عن shaderlib لكل مادة ، لكنني وجدت وظيفة واحدة في العارض التي بدت / قارنت التظليل بالكامل كسلاسل لاكتشاف التخزين المؤقت ، ولم أشعر بكل هذا الرضا حيال ذلك. أتمنى لو كان هناك بعض الملاحظات ...

هل كان المثال معيبا؟ قد يجعل الرأس الأمر أكثر وضوحًا مما يحدث من كرة سبايك المجردة ، لكن المثال بأكمله يعمل مع الظلال التي تغطي المزيد من الأرض. إنه ثقيل لسبب ما ، لكنني أعتقد أنه بسبب الخطيئة / cos في العديد من verts.

أعتقد أنك إذا بدأت من جديد ... على الرغم من أن مجموعة أدوات المشهد مروعة للغاية ، إلا أن واجهة برمجة التطبيقات هذه رائعة حقًا:

https://developer.apple.com/documentation/scenekit/scnshadable

على الرغم من أنه موثق بشكل فظيع ، لا يمكنني العثور على الجزء الأكثر أهمية ، لكنهم في الأساس لديهم خطافات مجردة في العديد من مراحل التظليل المختلفة.

في وقت سابق من هذا العام ، قدمت طلب سحب يبدو أنه يفعل شيئًا مشابهًا إن لم يكن نفس الشيء بالضبط:

https://github.com/mrdoob/three.js/pull/10791

يبدو أن الاختلاف الوحيد هو أنك تفعل ذلك من خلال رد الاتصال؟ لقد دخلت في الحجة غير المستخدمة في WebGLRenderer.

نأسف لعدم تمكننا من رعاية تلك العلاقات العامة حتى الآنpailhead. أعتقد أن الميزة الرئيسية لنهجي هي أنها تتطلب 3 خطوط جديدة فقط.

بعد قولي هذا ، سأقضي الآن بعض الوقت في دراسة اقتراحاتك والاقتراحات غير المعلنة .

هذا بالتأكيد يشعر بمزيد من الأناقة ، ثلاثة أسطر فقط. كنت أتبع نمطًا مختلفًا في النمط الآخر. كان سيقول أنه قد يكون أكثر تفصيلاً قليلاً ، لكن ليس متأكدًا. أعتقد أن الميزة الوحيدة للميزة الأخرى هي أنه كان من الجيد الذهاب قبل بضعة أشهر :)

Jeez ، مرتين ، مع نفس المطور؟ من الواضح أنني أفعل شيئًا خاطئًا هنا ، لكن ماذا؟

اسف بشأن ذلك. الشيء الوحيد الذي يمكنني التفكير فيه هو أنني ربما غمرتني. ربما مناقشة طويلة أو علاقات عامة معقدة من شأنها أن تستهلك الكثير من طاقاتي ، لذلك قررت تركها لوقت لاحق والانتقال إلى علاقات عامة أبسط.

ليس فقط أنت @ pailhead. bhouston كان لديه الكثير من العلاقات العامة مثل هذا ، حتى WestLangley و @ Mugen87.

مرة أخرى ، ليس الأمر أنني لا أحب العلاقات العامة ، هو أن العلاقات العامة تتطلب بعض الاهتمام الذي لا يمكنني تقديمه في ذلك الوقت. خير مثال على ذلك هو Instancing PR. تمكنت من إيجاد الوقت لقراءتها ، وأجريت تجربتي الخاصة واقترحت التبسيط. آمل أن أتمكن من إعادة النظر فيه قريبًا.

من الصعب إدارة كل هذا وإعطاء كل العلاقات العامة الاهتمام الذي تستحقه.

هل كان المثال معيبا؟ قد يجعل الرأس الأمر أكثر وضوحًا مما يحدث من كرة سبايك المجردة ، لكن المثال بأكمله يعمل مع الظلال التي تغطي المزيد من الأرض. إنه ثقيل لسبب ما ، لكنني أعتقد أنه بسبب الخطيئة / cos في العديد من verts.

الآن ذكرته ... نعم ، يعمل بسرعة 10 إطارات في الثانية على جهاز MacBook Pro جديد عند التكبير 😮

أعتقد أنه من الظلال والراند وجيب التمام والخطيئة وأشياء أخرى ، لكن يبدو أن الأمر يتطلب الكثير من الضربات.

في كلتا الحالتين ، أنا مندهش من أنك سحبت هذا في ثلاثة أسطر ، لقد ركزت كثيرًا على كيفية تحويل المعلمات المادية إلى زي موحد واتباع هذا النمط. الفرق هو أنني أقدم قاموسًا بديلاً يشبه القاموس ShaderLib ، لذا فإن #include <> يجلب كودًا مختلفًا. تقوم بإزالة التضمين قبل حدوث ذلك ، واستبداله بـ glsl. أعتقد أنه إذا قمت بإرجاع نوع من الغلاف حول التظليل ، فربما يكون بناء الجملة هذا أنظف (فقط قم بتوفير اسم القطعة + glsl ، بدلاً من replace() . ولكن قد ينتهي به الأمر إلى أن يبدو أكثر مثل الآخر .

سيكون من الرائع حقًا الحصول على هذا ، لم أعمل مع العديد من المحركات ثلاثية الأبعاد ، ولكن يبدو أن مجموعة الوحدة والمشهد لديها شيء من هذا القبيل.

تضمين التغريدة

أعتقد أن إحدى الفوائد من onBeforeCompile() هي أن خصائص المواد تظل دون تغيير. لذلك يبدو الأمر أشبه بتوسيع المواد المدمجة.

export class MyMeshPhongMaterial extends MeshPhongMaterial {
  constructor( parameters ) {
    super( parameters );
    this.onBeforeCompile = function ( shader ) {
      shader.vertexShader = shader.vertexShader.replace(
        '#include <begin_vertex>',
        'vec3 transformed = vec3( position.x + sin( position.y ) / 2.0, position.y, position.z );'
      );
    };
  }
}

var material = new MyMeshPhongMaterial();
material.color.setRGB( 1, 0, 0 ); // this still works

العبث بـ ShaderLib أمر صعب بالفعل. يجب أن تكون إضافة خطافات غير متغيرة إلى الأبد قابلة للتنفيذ على الرغم من:

    #include <begin_vertex>
    % vertex %
    #include <morphtarget_vertex>
    #include <skinning_vertex>
    % transformed_vertex %
    #include <project_vertex>
    % projected_vertex %

سيصبح رمز الاستبدال كالتالي:

this.onBeforeCompile = function ( shader ) {
  shader.vertexShader = shader.vertexShader.replace(
    '% vertex %',
    'transformed.x += sin( position.y ) / 2.0;'
  );
);

سنقوم بعد ذلك بإزالة أي خطاف لم يتم استخدامه قبل التجميع ، بالطبع.

إليك ما يبدو عليه مقارنةً بـ ShaderChunks لكل حالة

//given some material
var material = new THREE.MeshNormalMaterial();

//and some shader snippet
var myShader = [
    'float theta = sin( time + position.y ) / 2.0;',
    'float c = cos( theta );',
    'float s = sin( theta );',
    'mat3 m = mat3( c, 0, s, 0, 1, 0, -s, 0, c );',
    'vec3 transformed = vec3( position ) * m;', //and making assumptions about THREE's shader framework
    'vNormal = vNormal * m;'
].join( '\n' );

https://github.com/mrdoob/three.js/pull/10791 مثل Material.defines النهج:

material.shaderIncludes = {

        begin_vertex: myShader,

    //uv_pars_vertex: [
    //  THREE.ShaderChunk['uv_pars_vertex'], //this doesn't have to be
    //  "uniform float time;",
    //].join('\n')
};

material.shaderUniforms = { time: { value: 0, type: 'f' || 'float' } }; //because this could just inject it in the right place (but needs type)

_إنه فقط قاموس لأسماء المقاطع وكائن الزي الرسمي. يتماشى التلاعب بالأوتار هنا مع عبارة "أريد إعادة استخدام هذه القطعة ، والقيام بشيء فوقها" _

هذا العلاقات العامة:

material.onBeforeCompile = function ( shader ) {

    shader.uniforms.time = { value: 0 };

    shader.vertexShader = 'uniform float time;\n' + shader.vertexShader; //this feels hacky

    shader.vertexShader = shader.vertexShader.replace( //this is more verbose
        '#include <begin_vertex>',
        myShader
    );

};

أعتقد أن إحدى الفوائد من onBeforeCompile () هي أن خصائص المواد تظل دون تغيير.

إنه يعمل بنفس الطريقة في العلاقات العامة الأخرى ، لذلك أعتقد أنه لا يهم كيف يتم ذلك.


ربما تكون إحدى الفوائد غير ذات الصلة التي يمكنني التفكير فيها هي أنه يمكنك الاحتفاظ بمنطق معالجة المادة في نفس الكتلة وعلى نفس المستوى. إذا كان لديك جزء من التعليمات البرمجية يتغير لونه في مكان ما ، وقمت لاحقًا بإضافة GLSL مخصص إلى تلك المادة ، يمكنك إضافة الرمز لتغيير الزي مع اللون. (تخطي جدار النص)


إذا كان uv_pars_vertex محيرًا ، أعتقد أن السؤال الجيد الذي يجب طرحه هو:

"أين يمكنني حقن وظيفة GLSL المخصصة الخاصة بي ، مثل float rand( vec2) ؟"

ثم قد يكون هذا منطقيًا https://github.com/mrdoob/three.js/pull/11050


يمكن أن تكون حجة أخرى - بافتراض أنك تعرف GLSL ، بافتراض أنك تعرف إطار تظليل THREE ، لا يزال عليك أن تكون مبدعًا وتفكر في المكان الذي تضخ فيه ماذا. كان علي أن أفكر قليلاً وأبحث في معظم التظليل لمعرفة أن uv_pars_vertex هو مكان مناسب للقيام بتمديد المواد الخاص بي.

سيكون من الأفضل الانتقال من شيء كهذا إلى تجريد ، لديك خطافات lightingPhase ، objectTransformation ، perspectiveTransformation إلخ. أو على الأقل قطعة وهمية guaranteedToBeAboveMainButBelowCommonsAndExtensionCalls تضمينها في كل برنامج تظليل. يبدو أنك ستفعل ذلك بـ % vertex % ؟ لكني لست على دراية بهذا النحو.

هذه العلاقات العامة ، كما هي ، تبدو وكأنها تسير في الاتجاه المعاكس. علاوة على معرفة المكان الذي تريد النقر عليه ، تحتاج أيضًا إلى أن تكون واضحًا وتتلاعب بالسلاسل ، وتكرر بعض الأعمال التي يقوم بها العارض بالفعل نيابة عنك. أيضا ، إذا قمت بطرح سؤال آخر بالإضافة إلى السؤال الأول

كيف يمكنني استخدام دالة معلنة في جزء المشاعات داخل الوظيفة التي أقوم بحقنها؟

قد تجد نفسك تقوم بمزيد من التلاعب بالخيوط بدلاً من مجرد تقديم الزي الرسمي إلى التظليل بأكمله.

كان علي أن أفكر قليلاً وأن أنظر في معظم التظليل لمعرفة أن uv_pars_vertex هو مكان مناسب للقيام بتمديد المواد الخاص بي.

لا أعتقد أن هناك طريقة للتغلب على ذلك ما لم نفرط في الهندسة. الفكرة مع % vertex % هي محاولة المساعدة في ذلك قليلاً عن طريق تسمية الخطافات وإخبارك إلى حد ما بالحالة التي تقوم بحقن الكود فيها ، ولكن سيكون من الصعب توثيق المتغيرات المتوفرة في أي نقطة .

نحن نفتح بابًا للسماح باختراق المواد المدمجة ، لكن لا أعتقد أنه يمكننا تقديم "الدعم" المناسب. يجب أن يدرك المستخدم أن الاحتمالات قد تنكسر الأشياء.

حاولت معالجته في العلاقات العامة الأخرى. أضفت خطافًا وهميًا على الأقل للوظائف والاختلافات والسمات والزي الرسمي. يحدث الكثير من منطق GLSL بالفعل على الهياكل ، وقد وثقت مجموعة المشهد كل متغير (لا يمكن العثور على نفس التوثيق بعد الآن).

من المحتمل أن تحتاج إلى إعادة هيكلة بينما نمضي قدمًا ولكن شيئًا ما على غرار هذه الخطوط:

#ifdef PHASE_FOO

#include <shader_foo> 
//someGlobalStruct.mvPosition = modelViewMatrix * myLogic( transformed );
//if there is glsl provided for phase "foo" document that it should operate on "transformed" 
//and that it should return "mvPosition" 
#end including <shader_foo>

#else 

  //default
  #ifdef USE_SKINNING

    vec4 mvPosition = modelViewMatrix * skinned;

  #else

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

  #endif

#ifdef PHASE_BAR

#include <something_like_this>
//mvPosition = myPostDefaultTransformationLogic( mvPosition );

#endif

gl_Position = projectionMatrix * mvPosition;

#endif

بالطبع ifdefs والتضمينات لن تعمل على هذا النحو. لكن يمكنني أن أرى أنه يتم بشكل مستقيم نسبيًا مع النهج الآخر. يمكننا إضافة #include <some_phase> دائمًا ، بسلاسل فارغة. يمكن أن يساعد شيء ما في إدارة ما يتم تشغيله باستخدام #ifdef s. على سبيل المثال ، إذا قمت بتوفير منطق لمرحلة "vertex_transformation" ، فسيقوم التظليل بتحديد كل ما تقدمه. سيكون توثيق ما يفعله كل جزء باستخدام GLSL مفيدًا بشكل عام. بدون الخوض في المزيد من التجريد ، أعتقد أنه سيكون من الرائع الحصول على هذه الخريطة لكيفية تنظيم الأجزاء الآن.

نحن نفتح بابًا للسماح باختراق المواد المدمجة ، لكن لا أعتقد أنه يمكننا تقديم "الدعم" المناسب. يجب أن يدرك المستخدم أن الاحتمالات قد تنكسر الأشياء.

لدينا بالفعل عناصر التعريف المتوفرة في كل مادة. اقترح https://github.com/mrdoob/three.js/issues/10764 تعديل THREE.ShaderLib ثم تحديد خاصية .defines على مثيل Material . تم منح الملكية غير موثقة حتى كتبت الإدخال (لكنك وافقت عليه :)) ، وما زالت غير محددة .

لكن الطريقة التي يعمل بها هذا حاليًا ، والتي توارثها كل مادة ، يتم دعمها - إذا وضعت أشياء فيها ، فسيؤثر ذلك على تظليل تلك المادة . علاوة على ذلك ، إذا حدث أن قمت بتعريف شيء ما هو بالفعل جزء من مكتبة shader ، فقد يكسر الأشياء .

لا تحاول أن تكون ذكيًا ولكن تحاول أن تأتي بمثال. لقد استخدمت التعريفات في الغالب بـ ShaderMaterial لكنها تؤثر على جميع المواد ، فقط لأن كيفية عمل WebGLRenderer . لا يوجد منطق يقول:

إذا كنت أكثر ذكاءً ، سطح مثل تجريد مادة مثل Phong فلا تأخذ التعريفات في الحسبان. نظرًا لأن ثلاثة لم يتم تصميمها بحيث يتم تجاوز أجزاء التظليل الخاصة بها ، ونموذج Phong هو السلطة النهائية بشأن ما يحتاج GLSL إلى القيام به ، ويعمل على إخفاء هذا من الاستخدام ، فمن المنطقي عدم وجود تعريفات GLSL تتداخل مع هذا.

لست متأكدًا تمامًا مما إذا كان يمكن كسرها ، فسيتعين علي المحاولة.

مع ما يقال ، أود خيار كسر الأشياء ، إذا كان يوفر الكثير من المكاسب. باستخدام مقتطف GLSL صغير الحجم ومغلف جدًا ، يمكنني بسهولة تغيير الإصدار الثلاثة الخاص بي لعرض الخرائط العادية بشكل مختلف. إن أخذ الوضع الطبيعي وتحويله للحصول على وضع عادي آخر هو أمر سهل للغاية ، ما لم نبدأ في عمل رسومات الكمبيوتر بطريقة مختلفة تمامًا ، لا يمكنني رؤية هذا الانكسار على الإطلاق :)

كان المثيل مثالًا آخر:

أرغب في استخدام ANGLE_INSTANCED_ARRAYS ، يبدو أن ثلاثة منها لا تدعمها بظلالها أو مواد PBR ، اسمح لي فقط بإضافة هذين السطرين ، وجعلها تعمل من أجلي "

يسعدني أن أرى أن هذه الميزات ستأتي أخيرًا إلى three.js :). نعم ، لقد أنشأت أيضًا yet another material modifier PR (https://github.com/mrdoob/three.js/pull/7581) لقد كان قديمًا لدرجة أن الكود لم يعد ذا صلة بعد الآن ، ولكنه في الأساس يضخ السنانير مثل
تعجبني فكرة الخطافات المحددة مسبقًا لأنه من السهل فهم ما تقوم بتعديله حيث أعتقد أن معظم الأشخاص الذين يرغبون في استخدام هذه الميزة يريدون تعديل المادة الافتراضية "بشكل طفيف" بدلاً من إعادة كتابتها بالكامل.

تعجبني بساطة هذه العلاقات العامة ، لكن إذا أردنا إيجاد طريقة أكثر تنظيماً ونظافة للقيام بالأشياء ، فأنا أفضل أن يكون لديك بالفعل قاموس للخطافات لاستبداله بكودك وطريقة أبسط لإضافة زي موحد أو رمز مخصص من مجرد استبدال السلاسل.

fernandojsg ، أي فرصة يمكنك التحقق من #

fernandojsg لقد نسيت عن العلاقات العامة الخاصة بك 😚. أعتقد أن العلاقات العامة الخاصة بك تبدو كثيرًا عن الكيفية التي بدأت بها أرى هذا يعمل. الا وعي؟

لا تحاول أن تكون ذكيًا ولكن تحاول أن تأتي بمثال. لقد استخدمت التعريفات في الغالب بـ ShaderMaterial لكنها تؤثر على جميع المواد ، فقط لأن كيفية عمل WebGLRenderer .

يسعدني أن المكتبة قابلة للاختراق بهذه الطريقة ، لكن لا ينبغي لنا استخدام ميزات إساءة الاستخدام داخليًا للأشياء التي لم يكن الغرض منها. من السهل أن ينتهي بك الأمر برمز هش بهذه الطريقة.

قراءة # 7581 مرة أخرى ... فوق https://github.com/mrdoob/three.js/commit/e55898c27a843f69a47e602761c60d9bbe91ee35 يمكننا إضافة % HOOKS % ثم إنشاء فئة مثل هذا:

THREE.ExtendedMaterial = function ( material, hooks ) {

    material.onBeforeCompile = function ( shader ) {
        var vertexShader = shader.vertexShader;
        var fragmentShader = parameters.fragmentShader;
        for ( var name in hooks ) {
           vertexShader = vertexShader.replace( '%' + name + '%', hooks[ name ] );
           fragmentShader = fragmentShader.replace( '%' + name + '%', hooks[ name ] );
        }
        shader.vertexShader = vertexShader;
        shader.fragmentShader = fragmentShader;
    };

    return material;

};

ثم يمكننا القيام بذلك:

شبيبة
var material = new THREE.ExtendedMaterial (
جديد THREE.MeshBasicMaterial () ،
{قمة الرأس: 'transformed.x + = sin (position.y) / 2.0 ؛' }
) ؛

لذا فإن السؤال هو ، ما الخطافات التي يجب أن نحصل عليها؟

VERTEX
TRANSFORMED_VERTEX
PROJECTED_VERTEX

NORMAL
TRANSFORMED_NORMAL

FRAGMENT_UNIFORMS
INPUT_FRAGMENT
OUTPUT_FRAGMENT

mrdoob كمثال ، يمكنك أن ترى في هذا الجوهر حيث يجب إدخال الكود في تظليل قمة الرأس MeshBasicMaterial لدعم التثبيت.

وهنا لبقية المواد :)

https://github.com/mrdoob/three.js/pull/10750

VERTEX_UNIFORMS آرائًا للغاية ، أين يجب أن تضيف وظيفة أو سمة أو متغيرًا؟ PRE_VERTEX أو شيء من هذا القبيل؟

مطلوب بالتأكيد NORMAL_MAP

vert:

PRE_VERTEX
VERTEX
TRANSFORMED_VERTEX
PROJECTED_VERTEX

NORMAL
TRANSFORMED_NORMAL

UV
fragment:

PRE_FRAGMENT
INPUT_FRAGMENT
LIGHT
NORMAL

OUTPUT_FRAGMENT

VERTEX_UNIFORMS آرائًا للغاية ، أين يجب أن تضيف وظيفة أو سمة أو متغيرًا؟ PRE_VERTEX أو شيء من هذا القبيل؟

هممم ، عاقدة العزم؟ كيف ذلك؟

attribute vec4 aMyAttribute; ليس زي موحد :)

float myRand( vec4 foo ) { /*logic*/ return vec4(bar,baz)} ليس زيًا موحدًا

varying vec3 vMyVarying; ليس زيًا موحدًا أيضًا

إما ليس بصيغة الجمع أو ليس زيًا موحدًا على الإطلاق

ما هي حالة استخدام سمات "الحقن"؟
ألا يجب أن تستخدم geometry.addAttribute( 'aMyAttribute', ... ) بدلاً من ذلك؟

لم أكن أعلم أنه ليس عليك التصريح بذلك. لا يزال يترك الاختلافات والوظائف؟

لا يزال يترك الاختلافات والوظائف؟

نقطة جيدة.

لست مضطرًا حقًا إلى التصريح عن السمات على الإطلاق في GLSL؟ اعتقدت أنها تعمل مثل الزي الرسمي ، فأنت تعلن في GLSL ولكن لا يتعين عليك كتابتها في JS.

أعتقد أن هذه القائمة يمكن أن تنمو بسرعة كبيرة جدًا ، عندما يتعلق الأمر بأشياء معينة ، تصبح الشفرة مبعثرة جدًا. تتضمن إحدى طرق عمل الخرائط العادية سمتين إضافيتين وتنوعات ومنطق تحويل في كل من vert و frag.

تعجبني التغييرات الأخيرة التي لا تزال بسيطة وأنيقة. أتفق مع pailhead على أننا بحاجة إلى مكان لوضع الشفرة في النطاق العالمي. في https://github.com/mrdoob/three.js/pull/7581 كان لدي preMainVertex preMainFragment ليتم حقنها عالميًا حتى تتمكن من استخدامها للوظائف المتنوعة. ربما يكون اسم مثل globalVertex/Fragment أو اسم مشابه أفضل.

صوت GLOBAL_VERTEX و GLOBAL_FRAGMENT جيد 👌

بالضبط كيف سميتها في العلاقات العامة الأخرى 😆 👍

pailhead لكنك الآن تعرف سر دمج الكود الخاص بك: فقط افتح PR ، اتركه هناك بعض الوقت ، ثم انتظر mrdoob حتى يفكر في النهاية في فعل شيء مشابه ، انتظر علاقاته العامة ثم قم بالتعليق هناك بالإشارة إلى الأمر بالضبط بنفس الطريقة التي فعلت بها في العلاقات العامة الخاصة بك حتى يعتقد أنها كانت فكرته ، سيضيفها ، يدمج ... ربح!

image

الآن على محمل الجد ، أنا أيضًا أحب تلك الأسماء ومع ذلك أعتقد أننا مستعدون للذهاب ، أم أنني أفتقد شيئًا ما؟ سأحاول تحويل المثال من العلاقات العامة الخاصة بي إلى هذا الرمز الجديد ؛)

الجزء المتعلق بإدخال الكود جيد ، الخط الزمني متوقف نوعًا ما. # 7581 تم اقتراحه منذ عامين تقريبًا. لم تتم الإشارة إليه في https://github.com/mrdoob/three.js/issues/10789 ، لذلك ربما خرجت عن الرادار. كنت سأصطدم به أو أتشعبه.

حتى عند استيراد الوحدات واختيار العناصر الثلاثة الخاصة بك ، فإن الأشخاص ليسوا سعداء جدًا باستخدام الوحدات الأساسية غير الرسمية. من الأسهل بكثير القول ، "مرحبًا ، هناك حزمة npm تتعامل مع foo". لهذا السبب أشعر بأن العلاقات العامة مثل هذه مهمة ، ثلاثة ليست مرنة بما فيه الكفاية.

ربح!

أي ربح؟ 😆

الجزء المتعلق بإدخال الكود جيد ، الخط الزمني متوقف نوعًا ما. # 7581 تم اقتراحه منذ عامين تقريبًا. لم تتم الإشارة إليه في https://github.com/mrdoob/three.js/issues/10789 ، لذلك ربما خرجت عن الرادار. كنت سأصطدم به أو أتشعبه.

لما؟ لم تتحقق من جميع العلاقات العامة المفتوحة قبل إنشاء واحدة جديدة؟ # ترولول

حقيقية :)

حسنًا ، اطلب القائمة ودعنا نحصل على هذا في أسرع وقت ممكن: د

هل هذا التظليل (على سبيل المثال):

#include <shadowmap_pars_vertex>

void main() {

    #include <begin_vertex>
    #include <project_vertex>
    #include <worldpos_vertex>
    #include <shadowmap_vertex>

}

يبدو مثل هذا:

#include <shadowmap_pars_vertex>

void main() {

    % begin_vertex %
    % project_vertex %
    % worldpos_vertex %
    % shadowmap_vertex %

}

أم لست متأكدًا من استبدالها جميعًا أو مجرد إدخال الكود حول ترك بعض السلوك الحالي:

#include <shadowmap_pars_vertex>

%GLOBAL_VERTEX% 
void main() {
       %PRE_VERTEX% 
    #include <begin_vertex>
...
}

كان أسلوبي الأولي هو حقن الكود الإضافي مع ترك بقية التضمين دون تغيير.

لذا فإن % hook % مخصص فقط للخطافات الفعلية ، إذا أراد المرء استبدال <begin_vertex> فلا يزال يتعين عليه البحث عنه في سلسلة ، على سبيل المثال. لن يكون هناك خطاف begin_vertex ؟

في العلاقات العامة الخاصة بي ، أردت فقط تعديل سلوك المادة بشكل طفيف ، وعادةً ما أقوم ببعض تصحيحات الألوان بعد تنفيذ fs بالكامل أو التحويلات المماثلة لتلك التي أظهرهاmrdoob في مثاله.
ولكن إذا أردنا استبدال كل عنصر من العناصر المضمنة بالكامل ، فيجب علينا استخدام الخطافات بدلاً من التضمينات وإضافة المنطق لحقن التضمين نفسه في حالة عدم ربط الخطاف.

أود أن أفعل ذلك للأمور العادية (لا تستخدم المشتقات ، واستخدم معلومات TBN الفعلية من 3ds max أو maya أو في أي مكان يتم فيه إنشاء الخريطة العادية). يتطلب تكييف MeshPhongMaterial للعمل مع المثيلات أيضًا استبدال بعض الأجزاء تمامًا ، لكن هذا يبدو وكأنه حالة حافة.

هذان هما الشيءان اللذان يمكنني التفكير فيهما ، وأتساءل عما إذا كان هناك المزيد.

لذا فإن % hook % مخصص فقط للخطافات الفعلية ، إذا أراد المرء استبدال <begin_vertex> فلا يزال يتعين عليه البحث عنه في سلسلة ، على سبيل المثال. لن يكون هناك خطاف begin_vertex ؟

يمكنك استبدال كليهما. يسمح لك الكود الحالي بالفعل باستبدال أي شيء. %HOOK% منها للراحة.

كما ذكرت في # 11562 ، ماذا عن مفهوم قطع التظليل القابلة للاستبدال؟

مثال:

const material = new THREE.MeshPhongMaterial({
  color: 0xffffff,
  map: texture,

  parts: {
    frag: {
      map_pars_fragment: `
        uniform sampler2D map;
        uniform sampler2D map2;
     `,

      map_fragment: `
        vec4 texelColor = texture2D( map, vUv );
        vec4 texelColor2 = texture2D( map2, vUv );

    texelColor = mapTexelToLinear( 
          mix( texelColor, texelColor2, progress)
        );

    diffuseColor *= texelColor;
      `
    }
  }
});

material.uniforms.progress = {value: 1};
material.uniforms.map2 = {value: texture2};

هذا هو مدى بساطة رمز الانتقال بين مواد متعددة على مادة واحدة.

يمكن تنفيذها بسهولة وتجنب إنشاء تعليمات برمجية غير ضرورية.

@ sasha240100

https://github.com/mrdoob/three.js/pull/10791 يبدو تمامًا مثل الذي تقترحه ، باستثناء parts يُطلق عليه shaderChunks ولا يعتبره جدال.
: roll_eyes: 😆

لا تحتاج أيضًا إلى قاموس frag{} ، حيث تم تمييز الأجزاء بالفعل. كل منهم لديه _fragment و _vertex .

هذا يفعل الشيء نفسه باستثناء أنه يتعين عليك البحث في السلسلة للعثور على ما تحتاج إلى استبداله.

pailhead نعم ، فلنقم بإسقاط frag: {} . لقد استخدمتها كحجة لأنه يجب تمريرها قبل تسلسل تظليل المواد. في هذه الحالة يمكننا ببساطة تجنب استبدال الأجزاء الموجودة بعد التسلسل.

يمكننا بالفعل إضافة كلاً من: كوسيطة وكخاصية. مثل color يفعل

أين هذا الآن؟ أرى المثال يقوم بعمل .replace() ولا أرى أي خطافات / قطع قابلة للاستبدال؟ تضمين التغريدة

لم أتمكن من العودة إلى هذا بعد.

هل ترغب في إجراء العلاقات العامة للشيء % hook % ؟

هل تريد المادة الموسعة من التعليق أعلاه؟

THREE.ExtendedMaterial = function ( material, hooks ) {

    material.onBeforeCompile = function ( shader ) {
        var vertexShader = shader.vertexShader;
        var fragmentShader = parameters.fragmentShader;
        for ( var name in hooks ) {
           vertexShader = vertexShader.replace( '%' + name + '%', hooks[ name ] );
           fragmentShader = fragmentShader.replace( '%' + name + '%', hooks[ name ] );
        }
        shader.vertexShader = vertexShader;
        shader.fragmentShader = fragmentShader;
    };

    return material;

};

قد لا يكون اختيار مكان الخطافات وتوثيقها في الواقع بهذه السهولة؟ ربما استبدل hooks تم تمريره بـ chunks وأبحث عن العناصر المضمنة ، مع إضافة global_vert و global_frag في الوقت الحالي؟ الذي كتبته الآن ، يبدو أنه لا ينبغي أن يكون حتى مسؤولية ثلاثة ، ولكن من ناحية أخرى ، فإنه قد يؤدي إلى إيقاف THREE.ExtendedMaterial مقابل % hook % s في المستقبل؟

لا أعرف ما إذا كنت على علم بتمديد THREE.BAS. يستخدم العناصر النائبة في المواد الأصلية التي يمكن الوصول إليها من المواد المخصصة كمصفوفات ، مثل:

  var material = new BAS.PhongAnimationMaterial({
    flatShading: true,
    vertexColors: THREE.VertexColors,
    side: THREE.DoubleSide,
    uniforms: {
      uTime: {type: 'f', value: 0}
    },
    vertexFunctions: [
      // cubic_bezier defines the cubicBezier function used in the vertexPosition chunk
      BAS.ShaderChunk['cubic_bezier'],
      BAS.ShaderChunk['quaternion_rotation']
    ],
    vertexParameters: [
      'uniform float uTime;',
      'attribute vec2 aDelayDuration;',
      'attribute vec3 aStartPosition;',
      'attribute vec3 aEndPosition;',
      'attribute vec3 aControl0;',
      'attribute vec3 aControl1;',
      'attribute vec4 aAxisAngle;'
    ],
    vertexInit: [
      'float tProgress = mod((uTime + aDelayDuration.x), aDelayDuration.y) / aDelayDuration.y;',
      'vec4 tQuat = quatFromAxisAngle(aAxisAngle.xyz, aAxisAngle.w * tProgress);'
    ],
    vertexPosition: [
      'transformed = rotateVector(tQuat, transformed);',
      'transformed += cubicBezier(aStartPosition, aControl0, aControl1, aEndPosition, tProgress);'
    ]
  });

يعجبني حقيقة أنه يعتمد على اصطلاحات بسيطة: vertexInit و fragmentInit سيكونان في الجزء العلوي من الدالة main () على سبيل المثال. vertexParameters و fragmentParameters في الجزء العلوي من التظليل ، لتحديد الزي الرسمي أو السمات. vertexFunctions و fragmentFunctions قبل الوظيفة () الرئيسية. وهكذا بالنسبة للأعراف والموقف وما إلى ذلك ...

كما ترى في المركز ، يمكنك تغيير المتغير transformed لتغيير المركز النهائي. شيء مشابه للألوان ( objectNormal ) أو الألوان ( diffuseColor ) في تظليل الأجزاء ، على سبيل المثال.

هكذا تبدو مادة Phong ، تضيف العناصر النائبة فقط: https://github.com/zadvorsky/three.bas/blob/master/src/materials/PhongAnimationMaterial.js

مرحبًا يا رفاق ، كنت أحاول متابعة القافلة ولكن بصراحة لقد فقدت منذ أن جئت من الواجهة الأمامية وليس من مطوري اللعبة.

أحاول تحميل MTL والحصول على:

material.onBeforeCompile.toString () غير معرف.

كان ملف MTL الخاص بي يشير في الأصل إلى ملف .psd وقمت بتغييره إلى واحد من ملفات png القليلة التي تحتوي على نفس المجلد (عادي) أعتقد أنه من غير الممكن تحميل ملف psd ، ولكن على أي حال ، حتى مع فشل psd.

# Blender MTL File: 'goblin.blend'
# Material Count: 1

newmtl Material
Ns 96.078431
Ka 1.000000 1.000000 1.000000
Kd 0.640000 0.640000 0.640000
Ks 0.001617 0.005682 0.002517
Ke 0.000000 0.000000 0.000000
Ni 1.000000
d 1.000000
illum 2
map_Kd Normal.png

خرج وحدة التحكم هو:

THREE.WebGLRenderer 87
bundle.js:54570 OBJLoader: 29.447998046875ms
bundle.js:28429 Uncaught TypeError: Cannot read property 'toString' of undefined
    at WebGLPrograms.getProgramCode (bundle.js:28429)
    at initMaterial (bundle.js:32350)
    at setProgram (bundle.js:32542)
    at WebGLRenderer.renderBufferDirect (bundle.js:31605)
    at renderObject (bundle.js:32335)
    at renderObjects (bundle.js:32308)
    at WebGLRenderer.render (bundle.js:32072)
    at bundle.js:9658
    at bundle.js:53976
    at XMLHttpRequest.<anonymous> (bundle.js:40153)

والرمز الذي تستخدمه im هو بشكل أساسي:

OBJLoader(THREE);

const modelLoader = new THREE.OBJLoader();
const textureLoader = new MTLLoader();
textureLoader.setTexturePath( 'models/' );
    textureLoader.load('models/goblin.mtl', function( materials ) {

            materials.preload();

            modelLoader.setMaterials( materials );
            modelLoader.load('models/goblin.obj', function ( obj ) {
                 scene.add( obj );
                renderer.render( scene, camera );


            });

        }); 


    renderer.render( scene, camera );

}

هل هذه مشكلة في النموذج؟ في ثلاثة؟ في محمل mtl؟ لديها حل؟

سيكون موضع تقدير أي مساعدة.
شكرا.

هل يتعين علينا القيام بشيء مثل material.shader = shader في material.onBeforeCompile(shader=>...) ؟

أعتقد أنه يبدو ثقيلًا إلى حد ما ، قد يكون من المفيد إعادة النظر في الاقتراح الآخر في مرحلة ما :)

إنه ناتج عن هذا ، ولكن ما سبب عدم احتواء Material على هذه الوظيفة؟
https://github.com/mrdoob/three.js/blob/35a26f178c523514673d992da1aece23c1cfca6e/src/renderers/webgl/WebGLPrograms.js#L244

تضمين التغريدة

هل من الممكن ألا يتم تخزين هذه المظلات الممتدة مؤقتًا بشكل صحيح؟ أحاول استخدام مادتين مختلفتين ، إحداهما تغيرت dithering_fragment ، والأخرى لم تتغير. عندما أقوم بإضافة كلاهما إلى المشهد ، فإنه يظهر على أنه الشخص الوحيد الذي لا يستخدم القطعة dithering_fragment .

لم أتمكن من إعادة إنشائه بهذا الكمان
https://codepen.io/anon/pen/KQPBjd

ولكن مع هذا الرمز في المثال الخاص بي

const dithering_fragment = 
`
gl_FragColor.xyz *= foobar
`
// in onBeforeCompile
console.log(shader.fragmentShader)



md5-0f1a3ac67268b230968df20abdbd03d1



/**
#if defined( DITHERING )
  gl_FragColor.rgb = dithering( gl_FragColor.rgb );
#endif

gl_FragColor.xyz *= foobar

}
*/

لكن لا يوجد خطأ إذا أضفت مادة أخرى إلى المشهد تشاركها في تضمين وتعريفات أخرى.

إنه بسبب هذا:

https://github.com/mrdoob/three.js/blob/35a26f178c523514673d992da1aece23c1cfca6e/src/renderers/webgl/WebGLPrograms.js#L244

لدي نفس الوظيفة مع بعض المنطق المقدم لكلا المادتين ، متغيرات المنطق خارج نطاق رد النداء ، وبالتالي تحصل كلتا المادتين على نفس التجزئة؟

array.push( material.onBeforeCompile( obtainShaderSomehow ) )

https://github.com/mrdoob/three.js/pull/10791 حلها كما يلي:

https://github.com/pailhead/three.js/blob/879d52349bd5ef72c64fc962d8ca26bacaf489bf/src/renderers/webgl/WebGLPrograms.js#L242

هل ستعيد النظر في طلب السحب الآخر إذا قمت بإزالة العناصر النائبة / الخطافات global_vertex و global_fragment ؟ مع أولئك الذين تطرقوا إلى الكثير من الملفات ، بدونهم ، يكون رمزًا أقل. ليست ثلاثة أسطر ، لكنها تجزأ بشكل صحيح :)

التعليق #41 في هذا الكمان https://codepen.io/anon/pen/KQPBjd
وستتغير مادة الشبكة الأخرى في المشهد.

هل تم تضمين هذا في إصدار حديث أم أنه لا يزال قيد التطوير؟

mrdoob أعتقد أنه من الصعب (أو من المستحيل) إجراء تسلسل للمواد المخترقة باستخدام .onBeforeCompile() . هل تعتقد أنه يجب على المستخدمين استخدام ShaderMaterial إذا كانوا يريدون مواد مضمنة معدلة كاملة الوظائف (تصيير ، نسخ ، استنساخ ، تسلسل ، وما إلى ذلك)؟

_يرجى قراءة ما يلي بأجمل طريقة ممكنة وبناءة وغير تصادمية _ :)

takahirox لماذا يتم

أعتقد أنه من الصعب (أو المستحيل) إجراء تسلسل للمواد التي تم اختراقها

عندما تقوم "باختراق" المواد باستخدام onBeforeCompile فأنت تضيف فقط زيًا موحدًا مطابقًا لأي مادة أخرى. ليس هناك فرق. إذا كان بإمكانك إجراء تسلسل لـ material.color فلماذا لا يمكنك إجراء تسلسل material.userData.myColor ؟

أنا لا أحاول بدء قتال ، أو جدران نصية أو أي شيء. بأبسط العبارات الممكنة ، هل يمكنك أن تشرح لي ، أو على الأقل توجهني في الاتجاه الصحيح لسبب استحالة أو صعوبة ذلك؟ أنا منفتح على احتمال أن أفقد شيئًا واضحًا ، ولكن إذا كنت أرغب في فهم ما هو :)

من عينة صغيرة جدًا ، تم إنشاؤها بواسطة المقالات ، لا يبدو أن هذه التجربة يريد الناس استخدام منهج ShaderMaterial .


هذا فقط جاء في الذهن؟ هل يوجد نوع من الاختبار يثبت أن هذا صعب أو مستحيل؟ يحب:

runSerializationTest( someMaterialWithOnBeforeCompile ).expect( something )

نظرًا لأن طريقة onBeforeCompile قد تحتوي على رمز تعسفي للغاية ، فمن المستحيل بالتأكيد إجراء تسلسل قوي لرد الاتصال هذا. على سبيل المثال ، يمكن للطريقة إنشاء XMLHttpRequest متزامن وتفعل شيئًا مع النتيجة. 😅

ومع ذلك ... بالنسبة للطريقة التي يتم استخدامها عمليًا (لتصحيح المظلات) ، أوافق على أنه ليس مستحيلًا. لكن واجهات برمجة التطبيقات السهلة (على سبيل المثال fn.toString() ) معقدة ، وواجهات برمجة التطبيقات القوية أكثر تعقيدًا.

ما زلت لا أفهم المشكلة. ماذا عن وجهة النظر هذه:

خذ rN الذي كان يحتوي على MeshPhongMaterial ولم يكن يحتوي على MeshStandardMaterial .

يمكنك إجراء تسلسل لـ MeshPhongMaterial ie. اكتب JSON مثل هذا:

{
  color: 'red',
  specular: 'very',
  glossy: 'not much'
}

خذ rN + 1 الذي يحتوي على كلتا المادتين:

لا يزال بإمكانك إجراء تسلسل للطريقتين بنفس الطريقة:

//phong
{
  color: 'red',
  specular: 'very',
  glossy: 'not much'
}

//standard
{
  color:'red',
  shininess: 'shiny',
  metalness: 'not much'
}

لم تقم في أي مكان بإجراء تسلسل لـ GLSL من MeshStandardMaterial .

بنفس الطريقة ، تسلسل أي مادة ممتدة .

//extended PhongMaterial
{
   color: 'red',
   specular: 'very',
   glossy: 'not much',
   hamburger: 'medium rare'
}

نزع التسلسل:

if ( data.userData.hamburger && HamburgerPhongMaterial )
   mat = new HamburgerPhongMaterial( data ) 
else{ 
   console.warn(`I'm terribly sorry, but you don't have the HamburgerPhongMaterial extension, using default fallback`)
   mat = new PhongMaterial( data ) 
}

ما الذي افتقده هنا؟


كما onBeforeCompile ... إجراء تسلسل لهذا الاستدعاء.

لماذا ، لماذا تفكر فيه حتى :) أعتقد أن هذا هو جوهر حيرتي ، لماذا يتم التفكير في هذا الخطاف ، إنه ليس جزءًا من تعريف المواد أو الوصف أو أي شيء. يتعلق الأمر بالمحرك والمكونات الإضافية والتطبيقات وما إلى ذلك ، وليس البيانات.

المثال الذي قدمته أعلاه يبدو جيدًا بالنسبة لي ، فهو يتطلب فقط أن يعرف كود المستخدم الذي يقوم بإلغاء تسلسل المادة بوجود HamburgerPhongMaterial؟ ليس لدي مشكلة في ذلك ، فهو لا يتطلب بالضرورة تغييرات في واجهة برمجة التطبيقات إذا اتبعت نهجًا مشابهًا لـ # 14099 وتجاوزت toJSON و fromJSON.

ربما فسرنا سؤال

... من الصعب (أو المستحيل) إجراء تسلسل للمواد المخترقة باستخدام .onBeforeCompile (). هل تعتقد أنه يجب على المستخدمين استخدام ShaderMaterial إذا كانوا يريدون مواد مضمنة كاملة الوظائف (تصيير ، نسخ ، استنساخ ، تسلسل ، وما إلى ذلك)؟

سأحاول تقسيم ذلك إلى أجزاء:

  • إذا اتصل المستخدم بـ JSON () على MeshStandardMaterial العادي ، حيث تم تعديل GLSL بواسطة onBeforeCompile ، فلن يتم إجراء تسلسل للتغييرات على GLSL تلقائيًا.
  • إذا قام المستخدم بتسلسل MeshStandardMaterial مع بعض الخصائص الإضافية التي تشير إلى حدوث تغيير في GLSL ، وتحميلها برمز مخصص يعرف ما يجب فعله بهذه الخصائص الإضافية ، فلا بأس بذلك بالتأكيد.
  • العديد من الخيارات الأخرى (ShaderMaterial ، NodeMaterial ، glTF KHR_techniques_webgl ، ...) متاحة لتسلسل المواد المخصصة التعسفية.

إذا لم تكن الحالة التي نتحدث عنها واحدة من هؤلاء ، فأعتقد أنني أسيء فهمها هنا. إذا كان هذا حول # 14099 ، فأنا (ما زلت) أؤيد دمج ذلك.

حسنًا ، لم أكن أفرق بين الأولين. أحاول التفكير في شيء لا يتطلب زيًا موحدًا ، فقد يكون gl_FragColor.xyz /= gl_FragColor.a; على سبيل المثال. لكن لا يمكنني تخيل سيناريو تريد فيه إجراء تسلسل لشيء كهذا ( مع المادة؟ ). يبدو أنه يقع في نطاق عارض بعض التأثيرات أو شيء ما ، وليس البيانات المادية.

materials = loadSerializedMaterials()

effect = new Effect()

effect.load( 'alphaDivide').then(()=>materials.forEach(mat.onBeforeCompile = effect.getOnBeforeCompile('alphaDivide')))

المثال الثاني هو ما كان يدور في خلدي طوال الوقت. جنبًا إلى جنب مع المدخلات المختلفة ، قم بتسلسل تلميح حول ما يجب فعله معهم userData.extension === 'hamburger' .

أعتقد أنني كتبت بشكل سيء. ما أردت أن أذكره هو

  • المواد المضمنة التي تم اختراقها باستخدام .onBeforeCompile() لا يتم نسخها أو نسخها أو تسلسلها بشكل صحيح في نفس واجهة برمجة التطبيقات مثل المواد المضمنة. يتم التعامل معها على أنها مواد غير مخترقة.
  • إذا أراد المستخدمون النتيجة الصحيحة ، فإنهم يحتاجون إلى بعض العمل الإضافي في جانب المستخدم.
  • إذا أراد المستخدمون استخدام المواد المضمنة المخترقة باستخدام واجهة برمجة تطبيقات Three.js الأساسية دون أي عمل إضافي من جانب المستخدم ، فيجب عليهم التفكير في خيارات أخرى ، مثل ShaderMaterial .

سؤالي هو فقط لسياسة .onBeforeCompile() وليس للحالة المحددة. كنت أرغب في توضيح القيد وإضافة ملاحظة في المستند.

إذا نسيت حوالي three.js ونظام العرض بأكمله ، أعتقد أنني أرى النقطة. ككائن عام ، إذا كان يحتوي على .clone() فأنت تريد أن تكون قادرًا على الاستنساخ ولديك توقعات متسقة. المشكلة هي أن كلا الحلين (استنساخ هذا وليس استنساخه) يبدو أن لهما حجة صحيحة. أنت لا تستنسخ المستمعين ، لكنك تتوقع أيضًا إلى حد ما أن يكون الشيء الذي يؤثر على الرسم متسقًا.

ما زلت أعتقد أن اقتراحي أعلاه هو طريقة صالحة للقيام بذلك ، لأنني واجهت نفس المشكلة في مناطق أخرى (مثل مشاركة المخازن المؤقتة للعمق بين الأهداف يمكن حلها أيضًا باستخدام ownThing || outsideThing .

بدلاً من تخزين الوظيفة مؤقتًا ، والتي لا تعمل ، ستقوم بشكل أساسي بتخزين userData ولكن مجموعة فرعية منها. ليس من المنطقي تخزين userData.hamburger: 'rare' ولكنه يفعل userData.effectOn: true". The ownInput | ownChunks | ownWhat` من شأنه أن يحل هذه المشكلة.

كما أنه يحل مشكلة:

نظرًا لأن طريقة onBeforeCompile قد تحتوي على تعليمات برمجية عشوائية جدًا ، فمن المستحيل بالتأكيد إجراء تسلسل قوي لرد الاتصال هذا.

لقد مر وقت طويل ، وقد استخدم الأشخاص onBeforeCompile يجب أن نعرف الآن نوع الشفرة التعسفية التي يمكن العثور عليها هناك. أعتقد أنه لا يعمل إلا على الكائن shader الذي يتم تمريره. يمكنك تغيير هذا الكائن ، ولكن الطفرات التي لها معنى مع ShaderMaterial سيكون لها تأثير على أي حال. من المحتمل أن يتم تجاوز إعداد بعض الأشياء gl بنفسك ، وهذا يتعلق بالشيء الوحيد الذي يخطر ببالي.

إنها في الأساس خطوة pre three parse ، حيث تحصل على فرصة لتحليل التظليل بنفسك مع الواجهة الإلزامية uniforms:{} ، نظرًا لعدم توفرها على Material ( defines:{} من ناحية أخرى ، وكلاهما شقيقان في ShaderMaterial ).

كيف تفعل ذلك ، أي مهما كان الرمز التعسفي ، لا يهم. لا يقوم بإرجاع أي شيء ، ولكنه يقوم بتحويل shader:{} ويقوم العارض بعد ذلك باستخدامه.

المناهج التي أقترحها:

  1. أضف ownThing إلى فصول مختلفة. THREE.WebGLRenderTarget على .ownStencilDepthBuffer . هنا ، كما اقترحت أعلاه ، سيكون بعض الإصدارات من ownGLSL:{} ownInput | ownUniforms . أنت تزيل الحاجة إلى تعليمات برمجية عشوائية لتغيير الكائن shader:{} :

بالنظر إلى الإدخال مثل هذا الذي ينشأ من داخل WebGLRenderer (خاص جدًا):

const shader = {
  uniforms: buildFromMaterial(mat),
  vs: getVSTemplate(key),
  fs: getFSTemplate(key)
}

نووي هذا:

shader = onBeforeCompile( shader )

shader.vs //invalid GLSL
shader.uniforms //you got some extra ones that onBeforeCompile may have mutated, maybe removed some others

shader = ___parse(shader) //private step

shader.vs //valid glsl, (not a template)

compile(shader)

استخدم هذا:

function parseShader(shader){
   return {
     uniforms: shader.uniforms,
     vs: parseChunks(shader.vs)
     fs: parseChunks(shader.fs)
   }
}
//FIX FOR HASHING BUG
function parseChunk( material, chunkName ){
  return material.ownChunks[chunkName] || THREE.ShaderChunks[chunkName]
}

//do whatever you want with the templates, maybe remove an `#include <>`
shader = onBeforeParse(shader)

shader.vs //template || valid glsl

shader = parseShader(shader) //sample OWN || PRIVATE 

shader.vs //valid GLSL 

//if you want to apply a regex on the entire valid glsl, or compile node material or something else
shader = onBeforeCompile( shader )

compile(shader)
  1. اجعل WebGLRenderer لا تعرف شيئًا بخلاف ShaderMaterial .

أينما كنت

const mat = new THREE.MeshBasicMaterial()
const sm = new THREE.ShaderMaterial()

لديك

const mat = nodeMaterial.compile() //returns ShaderMaterial, with a friendly interface (same as StandardMaterial for example)

const mat = chunkMaterial.compile()

tl: dr من الأشياء المذكورة أعلاه هو أن المستخدم لا يهتم بنقطة زمنية معينة عند حدوث "compile" (parse) . أعتقد أنهم يهتمون أكثر بما يحدث ، ويمكن عزل ما يحدث إلى عدد قليل إن لم يكن حالة استخدام واحدة in: shaderString, out: shaderString . أعتقد أن سبب وجوب القيام بذلك في تلك المرحلة المحددة من خط الأنابيب يستحق التحقيق والفهم. يبدو أنه يعيق طريق الأشياء أكثر من مساعدته.

mrdoob أعتقد أنه من الصعب (أو من المستحيل) إجراء تسلسل للمواد المخترقة باستخدام .onBeforeCompile() . هل تعتقد أنه يجب على المستخدمين استخدام ShaderMaterial إذا كانوا يريدون مواد مضمنة معدلة كاملة الوظائف (تصيير ، نسخ ، استنساخ ، تسلسل ، وما إلى ذلك)؟

لم أتوقع (اعتبر) استخدام onBeforeCompile() متسلسلًا ...

لقد تعرضت للعض بشدة باستخدام onBeforeCompile. لدي فئة مساعد تظليل تسمح لي بإجراء تعديلات على التظليل المدمج بطريقة محددة. يمكنني استخدام طريقة onBeforeCompile للقيام بذلك. على ما يبدو ، كما هو مذكور في التعليق الأول ، يستخدم WebGLProgram onBeforeCompile.toString () كتجزئة. ولكن نظرًا لأن وظيفتي عامة (تستبدل أجزاء من الرأس وتظليل الشظايا بمتغيرات) ، فإن onBeforeCompile.toString () لا يبدو مختلفًا بالنسبة لمظلات مختلفة. هذا يعني أنه تم تخزين جميع أدوات التظليل المختلفة الخاصة بي مؤقتًا على أنها نفس البرنامج. تبدو كل من استدعاء Eval و uuid والآن وظائفي مختلفة. استغرق الأمر إلى الأبد لمعرفة ذلك.

donaldr راجع https://github.com/mrdoob/three.js/issues/13192. أعتقد أنه سيكون من الجيد توثيق هذه القيود.

هل يمكنك مشاركة طريقة استخدامك للتقييم؟ لقد كنت أفكر في ذلك ولكن بدا الأمر قذرًا جدًا. يمكنك بشكل أساسي إضافة const fdscxnmdrek435rkjl إلى الجزء العلوي من النص ثم تقييم؟

هذا يعني أنه تم تخزين جميع أدوات التظليل المختلفة الخاصة بي مؤقتًا على أنها نفس البرنامج. تبدو كل من استدعاء Eval و uuid والآن وظائفي مختلفة. استغرق الأمر إلى الأبد لمعرفة ذلك.

هذا يبدو محبطًا للغاية ، آسف. 😞 إذا بدت التعديلات التي احتجتها لجعلها منطقية في المكتبة نفسها ، فيرجى الترحيب بفتح المشكلات أيضًا.

من فضلك لا تتردد في فتح القضايا أيضا.

هل تفكر في إعادة فتح القائمة الموجودة؟ يبدو أن # 13192 هو نفسه ولكنه كان مغلقًا: crying_cat_face: سيكون من الرائع حقًا إذا تم نشر عمل هناك إذا تم اعتباره ميزة.

أمم...

const _obc = shader => {...}
const obc = `
function (shader){
  const _${ hash() }
  ${ _obc.toString() }
  _obc(shader)
}
`
material.onBeforeCompile = eval(obc)

^ هل سيعمل هذا؟ لم أستخدم أبدًا eval .

يضمن إدخال Material.customProgramCacheKey () عبر # 17567 أن المطورين لديهم الآن إمكانية عدم مشاركة برامج shader للمواد المعدلة عبر onBeforeCompile() مع العبارات الشرطية.

يرجى مناقشة المشكلات أو التحسينات الأخرى الموجودة في سياق onBeforeCompile() في سلاسل الرسائل الجديدة (مثل # 13446).

هل كانت هذه الصفحة مفيدة؟
0 / 5 - 0 التقييمات