בגרסאות קודמות של Direct3d הופיע Demo בשם DisplacementMapping10 שבא להדגים את היכולת של Displacement Mapping בהשוואה ל לטכניקות פשוטות יותר כמו Normal mapping .
Displacment Mapping demo
התוצאה של הDemo הינה רידנור של לטאה כאשר משתמשים ב Displacement Mapping ניתן לשנות את המעטפת של הMesh (רינדור הסנפיר על הגב של הלטאה ) דבר שהינו בילתי אפשרי בטכנולוגית Normal mapping המצויה .
בהשוואה ל רינדור עם Displacment mapping
הבעיה עם ה Demo הזה לפי דעתי היתה איטיות גם בכרטיסים לא חזקים לכן אולי הוא ירד .
הטכניקה של Displacment mapping (קימות כל מיני וריציות ) קיבלה boost בDirect3d11 בשל השימוש ב Hardware tessellation stage שמאפשר פיצול פוליגונים שהינם חלק מה mesh לפוליגונים קטנים .
מכיוון שפעולה זו מתבצעת על ידי החומרה של כרטיסי מסך תומכי Direct3d11 יש שיפור ניכר בביצועים של אפליקציות וdemos שמשתמשים בטכנולוגיה של Displacement mapping .
Tangent space שלפעמים נקרא גם Texture Space הינו מרחב בעולם התלת מימד שנוסף ל World, View ,Projection שייעודו הינו לחסוך משאבי GPU של חישובי טרנספורמציות של בPixel Shader .
כאשר מיישמים Per Pixel lighting יש הרבה טכנולוגיות שדורשות שלכל Texel בTexture יוצמד גם ערך של Normal דוגמא לטכנולוגיה כזו הינה : Normal mapping.
בד"כ כלל לאובייקטים התלת מימדיים עליהם אנו צריכים לישם טכנולוגית הקשורות ל per pixel light אנו מקבלים מהגרפיקאי שני קבצי Resource :קובץ של Color map וקובץ של Normal map כך שלכל Texel ב Color Map יש את וקטור הנורמל המשלים שלו ב Normal Map.
ערכי ה Texture מבוטאים על ידי color ערכי ה Normal מבוטאים על ידי vector מנורמל .
אם מגדירים את הערכים ב Normal Map כוקטורים ב object Space מכיוון שכאשר מיישמים חישוב של light ב Per pixel light גם ה Light Direction וגם ה Camera vector משתתפים בחישוב היינו צריכים על כל אחד מערכי ה Normal שדגמנו מה Normal Map לבצע טרנספורמציה למרחב בו מוגדרים הוקטורים של ה Light ו ה Camera . דבר זה יגרום לעומס עבודה ב Pixel shader .
על מנת לחסוך את הטרנספורמציה הזו מגדירים מרחב חדש בשם Tangent space
מרחב הצירים בTangent space מוגדר כ:
ה Vector X מוגדר לאורך ה U של ה Texture מוגדר כ Tangent
ה Vector Y מוגדר לאורך הV של ה Texture מוגדר Bitangent
ה Vector Z מוגדר כנורמל של ה Surface . מוגדר כ Normal
כאשר עובדים עם Tangent Space הNormals ב Normal maps מוגדרים ב Tangent space .
ערכי ה Normal נדגמים מהResource view על ידי ה PixelShader בדומה לדרך שבה דוגמים Texture רגיל כאשר ערכי ה xyz נמצאים ב ערכי הrgb
float3 n = normalize(tex2D(normalMap, IN.texCoord).rgb * 2.0f - 1.0f);
עבור כל polygon את ה light direction וה Camera vector אנו צריכים להמיר ל.Tangent space פעולה זו מתבצעת עבור כל וקטור ב Vertex Shader וכך אנו מקבלים ב Pixel shader את כל הוקטורים באותו מרחב (Tangent space ) דבר שחוסך לנו טרנספורמציות עבור כל texel .
על מנת להשתמש עם Tangent space אנו צריכים לבצע את הפעולות האילו
נצרף אלמנט של Tangent ל
D3D10_INPUT_ELEMENT_DESC
{ "TANGENT", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 32, D3D10_INPUT_PER_VERTEX_DATA, 0 },
אשר יוכנס לפקודת CreateInputLayout
מכיוון שיש לנו גם את הערך של ה Tangent וגם את הערך של הNormal אנו חוסכים את המרכיב של ה Bitangent בכל Vertex אותו נחשב בVertex Shader באמצעות Cross product .
במקרה והobject שאנו הולכם לרנדר לא מכיל ערכי Tangent מחושבים עבור כל ווקטור אנו צריכים לחשב את הערכים האילו לפני ששולחים את הVertexים לInput-Assembler Stage .
יש הרבה דוגמאות קוד ברשת לקוד שעובר על כל הפוליגונים של ישות ומחולל ומחולל לכל Vertex את ערכי ה Tangent שלו .
ב Vertex Shader אנו כאמור צריכים להמיר את המרחב של ה Viewer vector והlight direction ל Tangent space
השלבים ביצירת מטריצת ההמרה לTangent space הינם :
אנו כופלים את הערכים של ה Vertex במטריצה ההופכית המשוחלפת של ה World transformation
float3 n = mul(IN.normal, (float3x3)worldInverseTransposeMatrix);
float3 t = mul(IN.tangent.xyz, (float3x3)worldInverseTransposeMatrix);
אנו מחשבים את רכיב ה Bitangent על ידי Corss product כאשר ה ערך של IN.tangent.w מכי לערכים או של 1- או 1 שמצבעים על הקוטביות של ה Tangenet space coordinates
float3 b = cross(n, t) * IN.tangent.w;
מרכיבים את מטריצת ההמרה למרחב ה Tangent sapce
float3x3 tbnMatrix = float3x3(t.x, b.x, n.x,
t.y, b.y, n.y,
t.z, b.z, n.z);
המטריצה קודם מחזירה את הvetcor ל מרחב העצם ממרחב העולם ואח"כ מעבירה את העצם למרחב ה Tangent
כעת שיש לנו את מטריצת ההמרה אנו מכפילים את ערכי ה Light direction וה camera vector ב מטריצת ההמרה .
את הערכים המומרים שקיבלו אנו מציבים בstruct התוצאה של ה Vertex shader והם ישמשו ב חישוב ה light ב pixel shader .
כאשר בשלב של ה Pixel shader כל הוקטורים או הערכים שמשמשים לחישובי אור וכד נמצאים במרחב ה Texture דבר שחוסך לנו המרות של וקטורים ב pixel shader .
איזה דוד שאל שאלה בפורום תמיכה של Codeproject .
יש לו אפליקציה שמרנדרת Scene של Direcrt3D והוא מעוניין לשלב את התוצאה שלה עם streaming של וידיאו באמצעות DirectShow filter .
הוא שואל איך עושים את זה ?
ובכן לפי דעתי הכיוון הוא לא נכון .שילוב נכון של directshow video ו Direct3d עדיף שיתבצע באמצעות התשתית של Direct3d ולא של Directshow .
לכך יש מספר סיבות .
1.התשתית של Direct3D מתעדכנת טכנולוגית ומקבלת תשומת לב ממיקרוסופט בניגוד ל Directshow שתקוע כבר למעלה מ10 שנים באותו מקום .
2.על מנת לעבוד את התוצאה של הdx pipeline בתוך directshow filter צריכים גישה של הcpu לתוצר של הoutput merger stage.
אומנם הרינדור של Direct3d יכול להתבצע על Resource מסוג Texture אבל הResource חייב להיות מוגדר עםdefault usage שהכוונה שרק ל GPU יש הרשאת כתיבה וקריאה מה Resource הCPU לא יכול לגשת לTexture שהוגדר כ ID3D10RenderTargetView .
3.גם אם היינו משיגים את התוצאה של הdx pipeline המיזוג שלה עם הsurface של הdirectshow הינה פעולה יקרת משאבים מבחינת CPU סביר להניח שהפורמטים שונים ויש מצב שעל כל byte נצטרך לבצע פקודת if בCPU + הצבות וחישובים ,וכל frame מורכב מ 640 * 480 קריאות כאילו .
מניסיון מחשב חזק יכול לתמוך בפעולה כזו אבל חלק ניכר מהמשאבים כל הזמן ילך על הפעולה הזו .
4.בdirectshow filter אין גישה לכל נתוני התוצר של הoutput merger stage הכוונה לZ- Buffer ו stencil Buffer דבר שלא יאפשר לבצע חישובי הסתרות וכד כלומר הוידיאו לא חלק מהעולם של ה3D.
5.הוידיאו לא יהיה חלק אינטגרלי מהעולם כלומר כל חישובי ההצללה והתאורה לא יכללו בvideo מכיוון שהם נעשים בPixel shader .
בפוסט הבא אני אשתדל לכתוב איך לפתור את הבעיה באמצעות הפיכת ה Video Surface לDirect3D texture resource ושילובה בrendering של ה Sence .
לפעמים יש צורך לשלב בין שני scene ים ששתי אפליקציות Direct3D שונות יוצרות לתוך Scene אחד .
לדוגמא: אני רוצה להשתמש באפליקציה שלי בBing maps לצורך יצירת ועדכון הterrain ומעל הTerrain אני צריך לרנדר את האובייקטים שלי .
בניגוד למקרה עם אפליקציות 2D שאולי אפשר לשלב תמונות על ידי משחק עם ערכי alpha המצב בעולם של התלת מימד מורכב בהרבה .
הטכנולוגיות יכולות להיות מדור שונהBing עובד מול Direct3d9 ואני עובד עם Direct3d11 .כל ה api והאובייקטים שונים מאוד .
פעולת הrender חייבת להיות משותפת על מנת שהZ-buffer filter יפעל גם על האובייקטים שלי וגם על האובייקטים של Bing .כלומר אם מכונית שאני מרנדר נמצאת מאחורי הר שbing מרדנר ההר צריך להסתיר את המכונית שאני מרנדר .
פעולות בshaders של הצללה ואור צריכות להיות משותפות .(הקונספט של שמש בגבעון דום וירח בעמק איילון לא תופס כאן ) אותו מקור תאורה משפיע הן על האובייקטים שלי והן על האובייקטים המיובאים .
כמו כן יש אוביקטים בscene של Bing שאני לא רוצה שירונדרו אצלי באפליקציה אני רוצה רק את הTerrain נטו מבלי כפתורים שBing מרנדרת על הscene שלה .
מכיוון שאי אפשר לשתף את הsurface ים בין האפליקציות וbing לא פותח לנו api של קבלת הResource ים מbing (הVertexים והTexture ים ) אנו צריכים להוציא את הResources מBing לא בדרך המלך.
הפתרון שמימשנו
הפתרון מתבסס על יירוט של הקריאות ל dx api על ידי Bing .
יצרנו אפליקצית .net win form שמריצה WebBrowser Control ולתוך ה WebBrowser control אנו טוענים עמוד html מקומי שמציג את Bing אפשר לשלוט על Bing באמצעות פקודות של automation פשוטת של בחירת המיקום בעולם שהמפה מציגה וכד .
אנו יוצרים proxy dll שתפקידו ליירט קריאות מBing ל d3d9.dll ישנם מספר דוגמאות לשלד של dll כזה במרחבי ה Web . הDLL בשם d3d9.dll ממוקם בספריה שמריצה את האפליקציה עם Bing ולכן Bing טוען את הProxy dll שלנו כאשר הוא קורא לCreateDevice
אנו כתבנו proxy ל interface ים החשובים של Dx9 אשר הם נקראים במקום האורגינלים .
ברגע שאנו מיירטים פקודה שBing פקד וזו פקודה שמעדכנת Resource אנו מעתיקם את המידע שלה ל shared memory שמשותף ל dll המירט ו האפליקציה שלנו וכך יש לנו ביד את הpre resource ואנו מכניסים אותו ל pipline שלנו בתהליך הRender שלנו .
אנו צריכים לקלף או להתאים את הResource לDX11 יש שוני מהותי בין העבודה עם Resources בDX9 שהשתנה עם המעבר ל DX10 יש שונה בהדרת הSurfaceים וכד
אין צורך שתהליך הירוט יעביר את קריאות הRender ל d3d9.dll האורגינל חבל על תעבורה על הBus המיותרת ועבודת הכרטיס מסך.יש פקודות בעיקר אתחול שכן צריכות לקרא ל d3d9.dll המקורי על מנת ש bing יוכל לאתחל את העבודה שלו. הכל בתלות במשחק של trial and error .