You are on page 1of 28

‫‪@@@ÝîÜÄnÛa@òÌÛ@¶g@Ý‚‡ß‬‬

‫‪@ @ôìn¾a@òîÛbÇ‬‬

‫ﺳﻨﺼﻒ ﻓﻲ هﺬا اﻟﻔﺼﻞ ﻟﻐﺔ اﻟﺘﻈﻠﻴﻞ ﻋﺎﻟﻴﺔ اﻟﻤﺴﺘﻮى )‪ (High-Level Shading Language‬اﻟﺘﻲ‬
‫ﺳﻨﺴﺘﺨﺪﻣﻬﺎ ﻓﻲ ﺑﺮﻣﺠﺔ ﻣﻈﻠﻼت اﻟﺮؤوس واﻟﻌﻨﺼﻮرات ﺿﻤﻦ اﻟﻔﺼﻮل اﻟﺜﻼﺛﺔ اﻟﺘﺎﻟﻴﺔ‪.‬‬
‫ﺑﺎﺧﺘﺼﺎر ﻧﻘﻮل أن ﻣﻈﻠﻼت اﻟﺮؤوس واﻟﻌﻨﺼﻮرات ﻋﺒﺎرة ﻋﻦ ﺑﺮاﻣﺞ ﺻﻐﻴﺮة ﺧﺎﺻﺔ ﻧﻜﺘﺒﻬﺎ‬
‫ﻧﺤﻦ‪ ،‬وﺗُﻨﻔﱠﺬ ﺿﻤﻦ وﺣﺪة ﻣﻌﺎﻟﺠﺔ اﻟﺮﺳﻮﻣﻴﺎت )‪ GPU‬أو ‪ (graphic processing unit‬اﻟﻤﻮﺟﻮد ﻓﻲ‬
‫ﺑﻄﺎﻗﺔ اﻟﺮﺳﻮﻣﻴﺎت‪ ،‬ﺣﻴﺚ ﺗﺴﺘﻌﻴﺾ هﺬﻩ اﻟﺒﺮاﻣﺞ ﺟﺰءًا ﻣﻦ ﺧﻂ اﻟﻤﻌﺎﻟﺠﺔ ذو اﻟﻮﻇﻴﻔﺔ اﻟﺜﺎﺑﺘﺔ‪.‬‬
‫ﻧﺤﺼﻞ ﻣﻦ ﺧﻼل اﺳﺘﺒﺪال ﻗﺴﻢ ﻣﻦ ﺧﻂ اﻟﻤﻌﺎﻟﺠﺔ ذو اﻟﻮﻇﻴﻔﺔ اﻟﺜﺎﺑﺘﺔ ﺑﺒﺮﻧﺎﻣﺠﻨﺎ اﻟﻤﺨﺼﺺ‬
‫)اﻟﻤﻈﻠﻞ( ﻋﻠﻰ آ ّﻢ هﺎﺋﻞ ﻣﻦ اﻟﻤﺮوﻧﺔ ﻓﻲ إﻧﺠﺎز اﻟﺘﺄﺛﻴﺮات اﻟﺮﺳﻮﻣﻴﺔ‪ ،‬وﺑﺎﻟﺘﺎﻟﻲ ﻟﻢ ﻧﻌﺪ ﻣﻘﻴﺪﻳﻦ‬
‫ﺑﺎﻟﻌﻤﻠﻴﺎت اﻟﺜﺎﺑﺘﺔ ﻣﺴﺒﻘﺔ اﻟﺘﻌﺮﻳﻒ‪.‬‬
‫‪DirectX‬‬ ‫ﻧﺤﺘﺎج ﻣﻦ أﺟﻞ آﺘﺎﺑﺔ ﺑﺮاﻣﺞ اﻟﺘﻈﻠﻴﻞ إﻟﻰ ﻟﻐﺔ ﻟﻜﺘﺎﺑﺘﻬﺎ‪ .‬ﺗﻤﺖ آﺘﺎﺑﺔ اﻟﻤﻈﻠﻼت ﻓﻲ‬
‫‪ 8.x‬ﺑﻠﻐﺔ ﺗﻈﻠﻴﻞ ﺗﺠﻤﻴﻌﻴﺔ )‪ (assembly‬ﻣﻨﺨﻔﻀﺔ اﻟﻤﺴﺘﻮى‪ ،‬وﻟﻜﻦ ﻟﺤﺴﻦ اﻟﺤﻆ ﻟﺴﻨﺎ ﻣﺠﺒﺮﻳﻦ‬
‫ﻟﻜﺘﺎﺑﺔ اﻟﻤﻈﻠﻼت ﺑﻠﻐﺔ اﻟﺘﺠﻤﻴﻊ ﺑﻌﺪ اﻵن‪ ،‬ﻷن ‪ DirectX 9‬ﻗﺪ وﻓّﺮ ﻟﻐﺔ اﻟﺘﻈﻠﻴﻞ ﻋﺎﻟﻴﺔ‬
‫ﻻ ﻣﻦ ﻟﻐﺔ‬‫اﻟﻤﺴﺘﻮى اﻟﺘﻲ ﻳﻤﻜﻦ أن ﻧﺴﺘﺨﺪﻣﻬﺎ ﻟﻜﺘﺎﺑﺔ اﻟﻤﻈﻠﻼت‪ .‬إن ﻻﺳﺘﺨﺪام ‪ HLSL‬ﺑﺪ ً‬
‫اﻟﺘﺠﻤﻴﻊ ﻟﻜﺘﺎﺑﺔ ﺑﺮاﻣﺞ اﻟﺘﻈﻠﻴﻞ ﻧﻔﺲ ﻓﻮاﺋﺪ اﺳﺘﺨﺪام ﻟﻐﺔ ﻋﺎﻟﻴﺔ اﻟﻤﺴﺘﻮى )ﻣﺜﻞ ‪ C++‬أو‬
‫ﻻ ﻣﻦ ﻟﻐﺔ اﻟﺘﺠﻤﻴﻊ ﻟﻜﺘﺎﺑﺔ اﻟﺘﻄﺒﻴﻘﺎت‪ .‬هﺬﻩ اﻟﻔﻮاﺋﺪ هﻲ‪:‬‬
‫‪ (Pascal‬ﺑﺪ ً‬
‫إﻧﺘﺎﺟﻴﺔ أآﺒﺮ‪ :‬آﺘﺎﺑﺔ اﻟﺒﺮاﻣﺞ ﺑﻠﻐﺔ ﻋﺎﻟﻴﺔ اﻟﻤﺴﺘﻮى أﺳﺮع وأﺳﻬﻞ ﻣﻦ آﺘﺎﺑﺘﻬﺎ ﺑﻠﻐﺔ‬ ‫‪R‬‬
‫اﻟﻤﻈﻠﻼت واﻟﺘﺄﺛﻴﺮات‬ ‫‪٣٣٠‬‬

‫ﻣﻨﺨﻔﻀﺔ اﻟﻤﺴﺘﻮى‪ .‬ﻓﻬﻨﺎ ﻧﻘﻀﻲ وﻗﺘًﺎ أآﺒﺮ ﻓﻲ اﻟﺘﺮآﻴﺰ ﻋﻠﻰ اﻟﺨﻮارزﻣﻴﺎت ﻻ ﻓﻲ‬
‫آﺘﺎﺑﺔ اﻟﺸﻴﻔﺮة‪.‬‬
‫ﻗﺎﺑﻠﻴﺔ أﺣﺴﻦ ﻟﻠﻘﺮاءة‪ :‬اﻟﺒﺮاﻣﺞ اﻟﻤﻜﺘﻮﺑﺔ ﺑﻠﻐﺔ ﻋﺎﻟﻴﺔ اﻟﻤﺴﺘﻮى أﺳﻬﻞ ﻟﻠﻘﺮاءة‪ ،‬اﻷﻣﺮ‬ ‫‪R‬‬
‫اﻟﺬي ﻳﺆدي إﻟﻰ أن ﺗﻨﻘﻴﺢ وﺻﻴﺎﻧﺔ اﻟﺒﺮاﻣﺞ اﻟﻤﻜﺘﻮﺑﺔ ﺑﻠﻐﺔ ﻋﺎﻟﻴﺔ اﻟﻤﺴﺘﻮى أﺳﻬﻞ‪.‬‬
‫ﺗﻮﻟﺪ اﻟﻤﺘﺮﺟﻤﺎت )ﻓﻲ أﻏﻠﺐ اﻷﺣﻴﺎن( ﺷﻴﻔﺮة ﺗﺠﻤﻴﻊ أآﺜﺮ ﻓﻌﺎﻟﻴﺔ ﻣﻦ ﺷﻴﻔﺮة اﻟﺘﺠﻤﻴﻊ‬ ‫‪R‬‬
‫اﻟﻤﻜﺘﻮﺑﺔ ﻳﺪوﻳًﺎ‪.‬‬
‫ﻧﺴﺘﻄﻴﻊ ﻣﻦ ﺧﻼل اﺳﺘﻌﻤﺎل ﻣﺘﺮﺟﻢ ‪ HLSL‬أن ﻧﺘﺮﺟﻢ ﺷﻴﻔﺮﺗﻨﺎ إﻟﻰ أي إﺻﺪار ﻣﺘﺎح ﻣﻦ‬ ‫‪R‬‬
‫اﻟﻤﻈﻠﻼت‪ ،‬أﻣﺎ ﻋﻨﺪ اﺳﺘﺨﺪام ﻟﻐﺔ اﻟﺘﺠﻤﻴﻊ ﻓﻴﺠﺐ اﻻﻟﺘﺰام ﺑﻜﺘﺎﺑﺔ ﺷﻴﻔﺮة ﻟﻜﻞ إﺻﺪار ﻧﺮﻳﺪﻩ‪.‬‬
‫أو ‪ ،C++‬ﻟﺬا ﻟﻴﺲ ﻣﻦ اﻟﺼﻌﺐ اﻻﻧﺘﻘﺎل إﻟﻰ‬ ‫‪C‬‬ ‫إن ﻟﻐﺔ ‪ HLSL‬ﺗﺸﺒﻪ آﺜﻴﺮًا ﺻﻴﻐﺔ ﻟﻐﺔ‬
‫اﻟﺼﻴﺎﻏﺔ ﺑﻬﺬﻩ اﻟﻠﻐﺔ‪.‬‬
‫أﺧﻴﺮًا ﻧﺬآﺮ ﺑﺄﻧﻪ ﻳﺠﺐ اﻟﺘﺒﺪﻳﻞ إﻟﻰ اﻟﺠﻬﺎز ‪ REF‬ﻣﻦ أﺟﻞ أﻣﺜﻠﺔ اﻟﻤﻈﻠﻼت إذا ﻟﻢ ﺗﻜﻦ ﺑﻄﺎﻗﺔ‬
‫اﻟﺮﺳﻮﻣﻴﺎت ﺗﺪﻋﻢ ﻣﻈﻠﻼت اﻟﺮؤوس واﻟﻌﻨﺼﻮرات‪ .‬إن اﺳﺘﺨﺪام اﻟﺠﻬﺎز ‪ REF‬ﻳﻌﻨﻲ أن‬
‫أﻣﺜﻠﺔ اﻟﻤﻈﻠﻼت ﺳﺘُﻨﻔﱠﺬ ﺑﺒﻂء وﻟﻜﻦ ﻣﻊ إﻇﻬﺎر اﻟﻨﺘﺎﺋﺞ اﻟﺼﺤﻴﺤﺔ ﺑﺤﻴﺚ ﻳﻤﻜﻨﻨﺎ اﻟﺘﺄآﺪ ﻣﻦ‬
‫ﺻﺤﺔ اﻟﺸﻴﻔﺮة اﻟﺘﻲ ﻧﻜﺘﺒﻬﺎ‪.‬‬

‫ﻳﺘﻢ ﺗﻨﻔﻴﺬ ﻣﻈﻠﻼت اﻟﺮؤوس ﺑﺮﻣﺠﻴًﺎ ﻣﻦ ﺧﻼل ﻣﻌﺎﻟﺠﺔ اﻟﺮؤوس ﺑﺮﻣﺠﻴًﺎ‬


‫)‪.(D3DCREATE_SOFTWARE_VERTEX_PROCESSING‬‬

‫@@ @‬ ‫‪@@ @Òa‡çþa‬‬


‫ﺗﻌﻠﻢ آﻴﻔﻴﺔ آﺘﺎﺑﺔ وﺗﺮﺟﻤﺔ ﺑﺮﻧﺎﻣﺞ ﺗﻈﻠﻴﻞ ﻣﻜﺘﻮب ﺑﻠﻐﺔ ‪.HLSL‬‬ ‫‪R‬‬

‫ﺗﻌﻠﻢ آﻴﻔﻴﺔ اﺗﺼﺎل اﻟﻤﻌﻄﻴﺎت ﻓﻲ اﻟﺘﻄﺒﻴﻖ ﻣﻊ ﺑﺮﻧﺎﻣﺞ اﻟﻤﻈﻠﻞ‪.‬‬ ‫‪R‬‬

‫اﻟﺘﺂﻟﻒ ﻣﻊ اﻟﺼﻴﻐﺔ واﻷﻧﻮاع واﻟﺘﻮاﺑﻊ اﻟﻀﻤﻨﻴﺔ ﻟﻠﻐﺔ ‪.HLSL‬‬ ‫‪R‬‬

‫@@ @‬ ‫@@‬ ‫‪@HLSL@òÌÜi@ÝÜÄß@òibn×@Z16.1‬‬


‫ﻳﻤﻜﻨﻨﺎ أن ﻧﻜﺘﺐ ﺷﻴﻔﺮة ﻣﻈﻠﻼت ‪ HLSL‬ﻣﺒﺎﺷﺮة ﺿﻤﻦ اﻟﻤﻠﻔﺎت اﻟﻤﺼﺪرﻳﺔ ﻟﺘﻄﺒﻴﻘﻨﺎ ﻋﻠﻰ‬
‫ﺷﻜﻞ ﺳﻠﺴﻠﺔ رﻣﺰﻳﺔ ﻃﻮﻳﻠﺔ‪ .‬وﻟﻜﻦ ﻣﻦ اﻟﻤﻼﺋﻢ ﻓﺼﻞ ﺷﻴﻔﺮة اﻟﻤﻈﻠﻞ ﻋﻦ ﺷﻴﻔﺮة اﻟﺘﻄﺒﻴﻖ‪،‬‬
٣٣١ ‫ ﻣﺪﺧﻞ إﻟﻰ ﻟﻐﺔ اﻟﺘﻈﻠﻴﻞ ﻋﺎﻟﻴﺔ اﻟﻤﺴﺘﻮى‬:16

‫( وﻧﺤﻔﻈﻬﺎ آﻤﻠﻔﺎت ﻧﺼﻴﺔ‬Notepad) ‫ﻟﺬﻟﻚ ﺳﻨﻜﺘﺐ اﻟﻤﻈﻠﻼت ﺿﻤﻦ ﺑﺮﻧﺎﻣﺞ ﻣﺜﻞ اﻟﻤﻔﻜﺮة‬
‫ )اﻟﻤﺸﺮوح ﻓﻲ‬D3DXCompileShaderFromFile ‫ ﺛﻢ ﻧﺴﺘﺨﺪم اﻟﺘﺎﺑﻊ‬،(ASCII ‫ﻋﺎدﻳﺔ )ﺑﺮﻣﻮز‬
.‫( ﻣﻦ أﺟﻞ ﺗﺮﺟﻤﺔ اﻟﻤﻈﻠﻼت‬16.2.2 ‫اﻟﻔﻘﺮة‬
‫ واﻟﺬي ﺗﻢ ﺣﻔﻈﻪ ﻓﻲ‬HLSL ‫آﻤﻘﺪﻣﺔ ﻧﻮرد ﻣﻈﻠﻞ اﻟﺮؤوس اﻟﺒﺴﻴﻂ اﻟﺘﺎﻟﻲ واﻟﻤﻜﺘﻮب ﺑﻠﻐﺔ‬
‫ )ﻣﻠﻔﺎت اﻟﻤﺸﺮوع اﻟﻜﺎﻣﻞ ﻣﻮﺟﻮدة ﻓﻲ اﻟﻘﺮص اﻟﻤﺮﻓﻖ‬Transform.txt ‫ﻣﻠﻒ ﻧﺼﻲ اﺳﻤﻪ‬
‫ ﻳﻘﻮم هﺬا اﻟﻤﻈﻠﻞ ﺑﺘﺤﻮﻳﻞ اﻟﺮؤوس ﻧﻘﻄﻴًﺎ ﺑﺎﺳﺘﺨﺪام ﻣﺼﻔﻮﻓﺔ‬.(Transform ‫ﺗﺤﺖ ﻋﻨﻮان‬
.‫ﻣﺮآﱠﺒﺔ ﻣﻦ اﻟﻌﺮض واﻹﺳﻘﺎط آﻤﺎ ﻳﻀﻊ ﻣﺮآﺒﺔ اﻟﻠﻮن اﻟﻤﻨﺘﺜﺮ ﻟﻠﺮأس ﺑﺎﻟﻠﻮن اﻷزرق‬

‫ع‬
ٍ ‫ وﻟﻴﺲ هﻨﺎك دا‬،‫ﻳﺴﺘﺨﺪم هﺬا اﻟﻤﺜﺎل ﻣﻈﻠﻞ رؤوس ﻣﻦ أﺟﻞ اﻟﺘﻮﺿﻴﺢ‬
‫ﻟﻠﻘﻠﻖ ﺣﻮل ﻣﺎ ﻳُﻔﺘﺮض أن ﻳﻘﻮم ﺑﻪ هﺬا اﻟﻤﻈﻠﻞ اﻵن ﻷن ذﻟﻚ ﺳﻴُﺸﺮح ﻓﻲ‬
‫ أﻣﺎ اﻟﻐﺎﻳﺔ اﻟﺤﺎﻟﻴﺔ ﻓﻬﻲ اﻟﺘﺂﻟﻒ ﻣﻊ ﺻﻴﻐﺔ وﺗﻨﺴﻴﻖ ﺑﺮﻧﺎﻣﺞ‬.‫اﻟﻔﺼﻞ اﻟﻘﺎدم‬
.HLSL

// File: transform.txt
// Desc: Vertex shader that transforms a vertex by the view and
// projection transformation, and sets the vertex color to blue.

//
// Globals
//

// Global variable to store a combined view and projection


// transformation matrix. We initialize this variable
// from the application.
matrix ViewProjMatrix;

// Initialize a global blue color vector.


vector Blue = {0.0f, 0.0f, 1.0f, 1.0f};

//
// Structures
//

// Input structure describes the vertex that is input


// into the shader. Here the input vertex contains
// a position component only.
struct VS_INPUT
{
vector position : POSITION;
‫اﻟﻤﻈﻠﻼت واﻟﺘﺄﺛﻴﺮات‬ ٣٣٢

};

// Output structure describes the vertex that is


// output from the shader. Here the output
// vertex contains a position and color component.
struct VS_OUTPUT
{
vector position : POSITION;
vector diffuse : COLOR;
};

//
// Main Entry Point, observe the main function
// receives a copy of the input vertex through
// its parameter and returns a copy of the output
// vertex it computes.
//

VS_OUTPUT Main(VS_INPUT input)


{
// zero out members of output
VS_OUTPUT output = (VS_OUTPUT)0;

// transform to view space and project


output.position = mul(input.position, ViewProjMatrix);

// set vertex diffuse color to blue


output.diffuse = Blue;

return output;
}

@ @@ @@ @@ @òßbÈÛa@püìzn¾a@Z16.1.1

:‫ﻻ ﻧﻘﻮم ﺑﺘﻌﺮﻳﻒ ﻣﺘﺤﻮﻟﻴﻦ ﻋﺎﻣﻴﻦ‬


ً ‫أو‬
matrix ViewProjMatrix;
vector Blue = {0.0f, 0.0f, 1.0f, 1.0f};

‫ ﻣﻌﺮف‬4×4 ‫ )واﻟﺬي هﻮ ﻧﻮع ﻟﻤﺼﻔﻮﻓﺔ‬matrix ‫ ﻣﻦ اﻟﻨﻮع‬ViewProjMatrix ‫اﻟﻤﺘﺤﻮل اﻷول‬


‫ ﺳﻴﺨﺰن هﺬا اﻟﻤﺘﺤﻮل ﻣﺼﻔﻮﻓﺔ اﻟﻌﺮض واﻹﺳﻘﺎط اﻟﻤﺮآﺒﺔ ﺑﺤﻴﺚ‬،(HLSL ‫ﺿﻤﻨﻴًﺎ ﻓﻲ‬
‫ ﺑﻬﺬﻩ اﻟﻄﺮﻳﻘﺔ ﺳﻴﻜﻮن ﻋﻠﻴﻨﺎ إﺟﺮاء ﻋﻤﻠﻴﺔ ﺿﺮب‬.‫ﻳﺼﻒ هﺬﻳﻦ اﻟﺘﺤﻮﻳﻠﻴﻦ اﻟﻨﻘﻄﻴﻴﻦ ﻣﻌًﺎ‬
‫ ﻻﺣﻆ ﺑﺄﻧﻨﺎ ﻻ ﻧﻬﻲء هﺬا اﻟﻤﺘﺤﻮل ﻓﻲ أي ﻣﻜﺎن‬.‫ﻻ ﻣﻦ ﻋﻤﻠﻴﺘﻴﻦ‬
ً ‫ﺷﻌﺎع ﺑﻤﺼﻔﻮﻓﺔ واﺣﺪة ﺑﺪ‬
‫‪٣٣٣‬‬ ‫‪ :16‬ﻣﺪﺧﻞ إﻟﻰ ﻟﻐﺔ اﻟﺘﻈﻠﻴﻞ ﻋﺎﻟﻴﺔ اﻟﻤﺴﺘﻮى‬

‫ﺿﻤﻦ اﻟﺸﻴﻔﺮة اﻟﻤﺼﺪرﻳﺔ ﻟﻠﻤﻈﻠﻞ‪ ،‬ﻷﻧﻨﺎ ﻧﺤﺪد ﻗﻴﻤﺘﻪ ﻣﻦ ﺧﻼل اﻟﺸﻴﻔﺮة اﻟﻤﺼﺪرﻳﺔ ﻟﻠﺘﻄﺒﻴﻖ‬
‫وﻟﻴﺲ ﻓﻲ اﻟﻤﻈﻠﻞ‪ .‬إن ﻋﻤﻠﻴﺔ اﺗﺼﺎل اﻟﺘﻄﺒﻴﻖ ﻣﻊ ﺑﺮﻧﺎﻣﺞ اﻟﻤﻈﻠﻞ ﻣﻄﻠﻮﺑﺔ آﺜﻴﺮًا وﺳﻴﺘﻢ‬
‫ﺷﺮﺣﻬﺎ ﻓﻲ اﻟﻔﻘﺮة ‪.16.2.1‬‬
‫اﻟﻤﺘﺤﻮل اﻟﺜﺎﻧﻲ ‪ Blue‬ﻣﻦ اﻟﻨﻮع اﻟﻀﻤﻨﻲ ‪) vector‬واﻟﺬي هﻮ ﺷﻌﺎع رﺑﺎﻋﻲ اﻷﺑﻌﺎد(‪ .‬ﻧﻘﻮم‬
‫ﺑﺘﻬﻴﺌﺔ ﻣﺮآﺒﺎت هﺬا اﻟﺸﻌﺎع ﻟﺘﻤﺜﻞ اﻟﻠﻮن اﻷزرق وذﻟﻚ ﺑﻤﻌﺎﻣﻠﺘﻪ آﺸﻌﺎع ﻟﻮﻧﻲ ‪.RGBA‬‬
‫@@ @‬ ‫@@‬ ‫‪@x‹©aë@Ý‚‡Ûa@bnîäi@Z16.1.2‬‬

‫ﺑﻌﺪ اﻟﺘﺼﺮﻳﺢ ﻋﻦ اﻟﻤﺘﺤﻮﻻت اﻟﻌﺎﻣﺔ ﻧﻌﺮّف ﺑﻨﻴﺘﺎن ﺧﺎﺻﺘﺎن ﺳﻨﺪﻋﻮهﻤﺎ ﺑﻨﻴﺘﺎ اﻟﺪﺧﻞ‬
‫واﻟﺨﺮج‪ .‬ﺑﺎﻟﻨﺴﺒﺔ إﻟﻰ ﻣﻈﻠﻼت اﻟﺮؤوس ﺗﻌﺮّف هﺎﺗﺎن اﻟﺒﻨﻴﺘﺎن ﻣﻌﻄﻴﺎت اﻟﺮأس اﻟﺘﻲ‬
‫ﻳﺴﺘﺨﺪﻣﻬﺎ اﻟﻤﻈﻠﻞ آﺪﺧﻞ وﺧﺮج‪.‬‬
‫‪struct VS_INPUT‬‬
‫{‬
‫‪vector position‬‬ ‫;‪: POSITION‬‬
‫;}‬

‫‪struct VS_OUTPUT‬‬
‫{‬
‫;‪vector position : POSITION‬‬
‫;‪vector diffuse : COLOR‬‬
‫;}‬

‫ﺗﻌﺮف ﺑﻨﻴﺘﺎ اﻟﺪﺧﻞ واﻟﺨﺮج ﻟﻤﻈﻠﻞ اﻟﻌﻨﺼﻮرات ﻣﻌﻄﻴﺎت ﻋﻨﺼﻮرة‪.‬‬

‫ﻓﻲ هﺬا اﻟﻤﺜﺎل ﻳﺤﺘﻮي اﻟﺮأس اﻟﺬي ﻳﺪﺧﻞ إﻟﻰ ﻣﻈﻠﻞ اﻟﺮؤوس ﻋﻠﻰ ﻣﺮآﺒﺔ ﻟﻠﻤﻮﺿﻊ ﻓﻘﻂ‪،‬‬
‫أﻣﺎ اﻟﺮأس اﻟﺬي ﻳﻌﻄﻴﻪ ﻣﻈﻠﻞ اﻟﺮؤوس آﺨﺮج ﻓﻴﺤﺘﻮي ﻋﻠﻰ ﻣﺮآﺒﺔ ﻟﻠﻤﻮﺿﻊ وﻣﺮآﺒﺔ‬
‫ﻟﻠﻮن‪.‬‬
‫ﺗﺸﻴﺮ ﻋﻼﻣﺔ اﻟﺘﻔﺼﻴﻞ )‪ (:‬إﻟﻰ اﻟﻤﻌﻨﻰ )‪ (semantic‬اﻟﺬي ﻳﺴﺘﺨﺪم ﻣﻦ أﺟﻞ ﺗﺤﺪﻳﺪ اﺳﺘﻌﻤﺎل‬
‫ﻼ ﻟﺪﻳﻨﺎ ﻓﻲ‬
‫اﻟﻤﺘﺤﻮل‪ .‬إن اﻟﻤﻌﻨﻰ ﻳﺸﺒﻪ ﺗﻨﺴﻴﻖ اﻟﺮؤوس اﻟﻤﺮن )‪ (FVF‬ﻟﺒﻨﻴﺔ رأس‪ ،‬ﻣﺜ ً‬
‫‪ VS_INPUT‬اﻟﺤﻘﻞ اﻟﺘﺎﻟﻲ‪:‬‬
‫‪vector position‬‬ ‫;‪: POSITION‬‬

‫اﻟﺼﻴﻐﺔ "‪ ":POSITION‬ﺗﻨﺺ ﻋﻠﻰ أن اﻟﺸﻌﺎع ‪ position‬ﻳُﺴﺘﻌﻤﻞ ﻟﻮﺻﻒ ﻣﻜﺎن رأس‬


‫اﻟﺪﺧﻞ‪ .‬ﻟﺪﻳﻨﺎ ﻣﺜﺎل ﺁﺧﺮ ﺣﻮل ذﻟﻚ‪ ،‬ﻓﻲ اﻟﺒﻨﻴﺔ ‪ VS_OUTPUT‬ﻳﻮﺟﺪ‪:‬‬
‫‪vector diffuse‬‬ ‫;‪: COLOR‬‬
‫اﻟﻤﻈﻠﻼت واﻟﺘﺄﺛﻴﺮات‬ ‫‪٣٣٤‬‬

‫ﺣﻴﺚ هﻨﺎ "‪ ":COLOR‬ﻳﻨﺺ ﻋﻠﻰ أن اﻟﺸﻌﺎع ﻳُﺴﺘﻌﻤﻞ ﻣﻦ أﺟﻞ وﺻﻒ ﻟﻮن رأس اﻟﺨﺮج‪.‬‬
‫ﺳﻨﺘﺤﺪث أآﺜﺮ ﺣﻮل ﻣﻌﺮّﻓﺎت اﻻﺳﺘﻌﻤﺎل اﻟﻤﺘﺎﺣﺔ ﻻﺣﻘًﺎ ﻓﻲ اﻟﻔﺼﻠﻴﻦ اﻟﺘﺎﻟﻴﻴﻦ ﻋﻨﺪ دراﺳﺔ‬
‫ﻣﻈﻠﻼت اﻟﺮؤوس واﻟﻌﻨﺼﻮرات‪.‬‬

‫ﻣﻦ ﻣﻨﻈﻮر ﻣﻨﺨﻔﺾ اﻟﻤﺴﺘﻮى‪ ،‬ﺗﻘﻮم ﺻﻴﻐﺔ اﻟﻤﻌﻨﻰ ﺑﺮﺑﻂ أي ﻣﺘﺤﻮل ﻓﻲ‬
‫اﻟﻤﻈﻠﻞ ﺑﻤﺴﺠﻞ )‪ (register‬ﻓﻲ اﻟﻌﺘﺎد‪ .‬أي أن ﻣﺘﺤﻮﻻت اﻟﺪﺧﻞ ﺗُﺮﺑﻂ ﻣﻊ‬
‫ﻣﺴﺠﻼت اﻟﺪﺧﻞ وﺗﺮﺑﻂ ﻣﺘﺤﻮﻻت اﻟﺨﺮج ﻣﻊ ﻣﺴﺠﻼت اﻟﺨﺮج‪ .‬ﻋﻠﻰ ﺳﺒﻴﻞ‬
‫اﻟﻤﺜﺎل‪ ،‬ﻳﺘﺼﻞ اﻟﺤﻘﻞ ﻓﻲ اﻟﺒﻨﻴﺔ ‪ VS_INPUT‬ﺑﻤﺴﺠﻞ ﻣﻜﺎن رأس اﻟﺪﺧﻞ‪،‬‬
‫وﺑﺸﻜﻞ ﻣﺸﺎﺑﻪ ﻳﺘﺼﻞ ‪ diffuse‬ﻣﻊ ﻣﺴﺠﻞ ﻟﻮن ﻣﻌﻴﻦ ﻟﺮأس اﻟﺨﺮج‪.‬‬
‫@@ @‬ ‫‪@Þ삇Ûa@òİÔã@Éibm@Z16.1.3‬‬
‫ﻟﻜﻞ ﺑﺮﻧﺎﻣﺞ ‪) HLSL‬آﻤﺎ ﻓﻲ ﺑﺮﻧﺎﻣﺞ ﺑﻠﻐﺔ ‪ (C++‬ﻧﻘﻄﺔ دﺧﻮل‪ .‬ﻓﻲ ﻣﺜﺎﻟﻨﺎ ﺣﻮل ﻣﻈﻠﻞ‬
‫اﻟﺮؤوس ﺳﻤﻴﻨﺎ ﺗﺎﺑﻊ ﻧﻘﻄﺔ اﻟﺪﺧﻮل ‪ Main‬وﻟﻜﻨﻨﺎ ﻟﺴﻨﺎ ﻣﻠﺰﻣﻴﻦ ﺑﻬﺬﻩ اﻟﺘﺴﻤﻴﺔ‪ ،‬إذ ﻳﻤﻜﻦ أن‬
‫ﻳﺄﺧﺬ ﺗﺎﺑﻊ ﻧﻘﻄﺔ اﻟﺪﺧﻮل ﻓﻲ ﻣﻈﻠﻞ أي اﺳﻢ ﻣﻘﺒﻮل آﺎﺳﻢ ﺗﺎﺑﻊ‪ .‬ﻳﺠﺐ أن ﻳﻜﻮن ﻟﺘﺎﺑﻊ ﻧﻘﻄﺔ‬
‫اﻟﺪﺧﻮل وﺳﻴﻄًﺎ هﻮ ﺑﻨﻴﺔ اﻟﺪﺧﻞ واﻟﺬي ﻳُﺴﺘﺨﺪم ﻟﺘﻤﺮﻳﺮ رأس اﻟﺪﺧﻞ إﻟﻰ اﻟﻤﻈﻠﻞ‪ ،‬آﻤﺎ ﻳﺠﺐ‬
‫ﻋﻠﻰ ﺗﺎﺑﻊ ﻧﻘﻄﺔ اﻟﺪﺧﻮل أن ﻳﻌﻴﺪ ﺑﻨﻴﺔ ﺧﺮج واﻟﺘﻲ ﻓﻴﻬﺎ ﻳﻮﺟﺪ اﻟﺮأس اﻟﻤﻌﺎﻟَﺞ ﻣﻦ ﻗﺒﻞ‬
‫اﻟﻤﻈﻠﻞ‪.‬‬
‫)‪VS_OUTPUT Main(VS_INPUT input‬‬
‫{‬

‫ﻓﻲ اﻟﻮاﻗﻊ‪ ،‬ﻟﻴﺲ ﻣﻦ اﻟﻮاﺟﺐ اﺳﺘﺨﺪام ﺑﻨﻴﺘﺎ دﺧﻞ وﺧﺮج‪ .‬ﻋﻠﻰ ﺳﺒﻴﻞ اﻟﻤﺜﺎل‪،‬‬
‫ﻗﺪ ﺗﺮى أﺣﻴﺎﻧًﺎ ﺻﻴﻐﺔ ﻣﺸﺎﺑﻬﺔ ﻟﻤﺎ ﻳﻠﻲ ﺧﺼﻮﺻًﺎ ﻓﻲ ﻣﻈﻠﻼت اﻟﻌﻨﺼﻮرات‪:‬‬
‫‪float4 Main(in float2 base : TEXCOORD0,‬‬
‫‪in float2 spot : TEXCOORD1,‬‬
‫;‪in float2 text : TEXCOORD2) : COLOR‬‬
‫{‬
‫‪...‬‬
‫}‬

‫ﻼ ﻟﻠﻤﻈﻠﻞ )ﻓﻲ ﻣﺜﺎﻟﻨﺎ اﻟﻤﺬآﻮر ﻧﻘﻮم ﺑﺈدﺧﺎل ﺛﻼث‬


‫ﺣﻴﺚ ﺗﻜﻮن اﻟﻮﺳﻄﺎء دﺧ ً‬
‫إﺣﺪاﺛﻴﺎت ﻧﺴﻴﺠﻴﺔ(‪ .‬ﻳﻌﻴﺪ اﻟﻤﻈﻠﻞ ﻟﻮﻧًﺎ وﺣﻴﺪًا آﺨﺮج ﺣﻴﺚ ﺗﻤﺖ اﻹﺷﺎرة إﻟﻰ‬
‫ذﻟﻚ ﻣﻦ ﺧﻼل اﻟﺼﻴﻐﺔ "‪ ":COLOR‬اﻟﺘﻲ ﺗﻠﻲ رأس اﻟﺘﺎﺑﻊ‪ .‬إن هﺬا اﻟﺘﻌﺮﻳﻒ‬
‫ﻳﻜﺎﻓﺊ ﻣﺎ ﻳﻠﻲ‪:‬‬
‫‪struct INPUT‬‬
‫{‬
‫‪float2 base : TEXCOORD0,‬‬
‫‪٣٣٥‬‬ ‫‪ :16‬ﻣﺪﺧﻞ إﻟﻰ ﻟﻐﺔ اﻟﺘﻈﻠﻴﻞ ﻋﺎﻟﻴﺔ اﻟﻤﺴﺘﻮى‬

‫‪float2 spot : TEXCOORD1,‬‬


‫)‪float2 text : TEXCOORD2‬‬
‫;}‬

‫‪struct OUTPUT‬‬
‫{‬
‫;‪float4 c : COLOR‬‬
‫;}‬

‫)‪OUTPUT Main(INPUT input‬‬


‫{‬
‫‪...‬‬
‫}‬

‫إن ﺟﺴﻢ ﺗﺎﺑﻊ ﻧﻘﻄﺔ اﻟﺪﺧﻮل ﻣﺴﺆول ﻋﻦ ﺣﺴﺎب رأس اﻟﺨﺮج اﻋﺘﺒﺎرًا ﻣﻦ رأس اﻟﺪﺧﻞ‪.‬‬
‫ﻳﻘﻮم اﻟﻤﻈﻠﻞ ﻓﻲ هﺬا اﻟﻤﺜﺎل ﺑﺘﺤﻮﻳﻞ رأس اﻟﺪﺧﻞ إﻟﻰ ﻓﻀﺎء اﻟﻌﺮض وﻓﻀﺎء اﻹﺳﻘﺎط‪،‬‬
‫ﻻ ﻧﻘﻮم ﺑﺈﻧﺸﺎء ﻧﺴﺨﺔ ﻣﻦ‬ ‫وﻳﺠﻌﻞ ﻟﻮن اﻟﺮأس أزرق‪ ،‬وﻳﻌﻴﺪ اﻟﺮأس اﻟﻨﺎﺗﺞ‪ .‬أو ً‬
‫‪ VS_OUTPUT‬وﻧﻀﻊ ﻓﻲ آﻞ ﺣﻘﻮﻟﻬﺎ اﻟﻘﻴﻤﺔ ‪:0‬‬
‫;‪VS_OUTPUT output = (VS_OUTPUT)0‬‬

‫ﻼ ﻧﻘﻄﻴًﺎ ﻟﻤﻜﺎن رأس اﻟﺪﺧﻞ ﻣﻦ ﺧﻼل ﺿﺮﺑﻪ ﺑﺎﻟﻤﺘﺤﻮل‬ ‫ﺛﻢ ﻳﺠﺮي اﻟﻤﻈﻠﻞ ﺗﺤﻮﻳ ً‬
‫‪ ViewProjMatrix‬ﺑﺎﺳﺘﺨﺪام اﻟﺘﺎﺑﻊ ‪ ،mul‬اﻟﺬي هﻮ ﺗﺎﺑﻊ ﺿﻤﻨﻲ ﻳﻤﻜﻨﻪ ﺿﺮب ﺷﻌﺎع‬
‫ﺑﻤﺼﻔﻮﻓﺔ وﺿﺮب ﻣﺼﻔﻮﻓﺔ ﺑﻤﺼﻔﻮﻓﺔ‪ .‬ﻧﺤﻔﻆ اﻟﺸﻌﺎع اﻟﻨﺎﺗﺞ ﻋﻦ اﻟﺘﺤﻮﻳﻞ اﻟﻨﻘﻄﻲ ﻓﻲ ﺣﻘﻞ‬
‫اﻟﻤﻮﺿﻊ ﺿﻤﻦ ﺑﻨﻴﺔ اﻟﺨﺮج‪:‬‬
‫;)‪output.position = mul(input.position, ViewProjMatrix‬‬

‫ﺑﻌﺪ ذﻟﻚ ﻧﻀﻊ ﻓﻲ ﺣﻘﻞ اﻟﻠﻮن اﻟﻤﻨﺘﺜﺮ ﺿﻤﻦ ‪ output‬اﻟﻘﻴﻤﺔ ‪:BLUE‬‬


‫;‪output.diffuse = BLUE‬‬
‫وأﺧﻴﺮًا ﻧﻌﻴﺪ اﻟﺮأس اﻟﻨﺎﺗﺞ‪:‬‬
‫;‪return output‬‬
‫}‬

‫@@ @‬ ‫‪@@ @HLSL@òÌÜi@lìnØß@ÝÜÄß@ò»‹m@Z16.2‬‬


‫@@ @‬ ‫‪@@ @oiaìrÛa@Þë‡u@Z16.2.1‬‬
‫ﻳﻮﺟﺪ ﻟﻜﻞ ﻣﻈﻠﻞ ﺟﺪول ﺛﻮاﺑﺖ ﻳﺴﺘﺨﺪم ﻟﺘﺨﺰﻳﻦ ﻣﺘﺤﻮﻻﺗﻪ‪ .‬ﺗﻮﻓﺮ اﻟﻤﻜﺘﺒﺔ ‪ D3DX‬ﻟﺘﻄﺒﻴﻘﻨﺎ‬
‫إﻣﻜﺎﻧﻴﺔ اﻟﻮﻟﻮج إﻟﻰ ﺟﺪول ﺛﻮاﺑﺖ اﻟﻤﻈﻠﻞ ﻣﻦ ﺧﻼل اﻟﻮاﺟﻬﺔ ‪.ID3DXConstantTable‬‬
‫ﻳﻤﻜﻨﻨﺎ ﺑﻮاﺳﻄﺔ هﺬﻩ اﻟﻮاﺟﻬﺔ ﺗﺤﺪﻳﺪ ﻗﻴﻢ اﻟﻤﺘﺤﻮﻻت اﻟﻤﻮﺟﻮدة ﻓﻲ اﻟﺸﻴﻔﺮة اﻟﻤﺼﺪرﻳﺔ‬
‫اﻟﻤﻈﻠﻼت واﻟﺘﺄﺛﻴﺮات‬ ‫‪٣٣٦‬‬

‫ﻟﻠﻤﻈﻠﻞ ﻣﻦ ﺧﻼل ﺷﻴﻔﺮة ﺗﻄﺒﻴﻘﻨﺎ‪.‬‬


‫ﺳﻨﻮرد اﻵن ﻻﺋﺤﺔ ﻣﺨﺘﺼﺮة ﺑﺎﻟﻤﻨﺎهﺞ اﻟﺘﻲ ﺗﺤﻘﻘﻬﺎ اﻟﻮاﺟﻬﺔ ‪ .ID3DXConstantTable‬ﻣﻦ‬
‫أﺟﻞ اﻟﺤﺼﻮل ﻋﻠﻰ اﻟﻼﺋﺤﺔ اﻟﻜﺎﻣﻠﺔ ﺑﻬﺬﻩ اﻟﻤﻨﺎهﺞ راﺟﻊ وﺛﺎﺋﻖ ‪.Direct3D‬‬

‫‪@ @@ @oibrÛ@jÔß@óÜÇ@Þì—¨a@Z16.2.1.1‬‬

‫ﻣﻦ أﺟﻞ ﺗﺤﺪﻳﺪ ﻗﻴﻤﺔ ﻣﺘﺤﻮل ﻣﻌﻴﻦ ﻓﻲ اﻟﻤﻈﻠﻞ ﻣﻦ ﺧﻼل ﺷﻴﻔﺮة ﺗﻄﺒﻴﻘﻨﺎ ﻧﺤﺘﺎج إﻟﻰ ﻃﺮﻳﻘﺔ‬
‫ﻟﻠﺮﺟﻮع إﻟﻴﻬﺎ‪ .‬ﻳﺘﻢ اﻟﺮﺟﻮع إﻟﻰ ﻣﺘﺤﻮل ﻓﻲ اﻟﻤﻈﻠﻞ ﻣﻦ ﻗﺒﻞ ﺗﻄﺒﻴﻘﻨﺎ ﺑﺎﺳﺘﺨﺪام ﻣﻘﺒﺾ ﻣﻦ‬
‫اﻟﻨﻮع ‪ .D3DXHANDLE‬ﻳﻌﻴﺪ اﻟﻤﻨﻬﺞ اﻟﺘﺎﻟﻲ ﻣﻘﺒﻀًﺎ ﻟﻤﺘﺤﻮل ﻓﻲ اﻟﻤﻈﻠﻞ اﻋﺘﻤﺎدًا ﻋﻠﻰ‬
‫اﺳﻤﻪ‪:‬‬
‫(‪D3DXHANDLE ID3DXConstantTable::GetConstantByName‬‬
‫‪D3DXHANDLE hConstant,‬‬ ‫‪// scope of constant‬‬
‫‪LPCSTR pName‬‬ ‫‪// name of constant‬‬
‫;)‬
‫ﺣﻴﺚ‪:‬‬
‫‪ :hConstant‬اﻟﻤﻘﺒﺾ اﻟﺬي ﻳﻌﺮف اﻟﺒﻨﻴﺔ اﻷب اﻟﺘﻲ ﺗﺤﻮي اﻟﻤﺘﺤﻮل اﻟﺬي ﻧﻮد‬ ‫‪R‬‬
‫اﻟﺤﺼﻮل ﻋﻠﻰ ﻣﻘﺒﺾ ﻟﻪ‪ .‬ﻣﺜﻼً‪ ،‬إذا أردﻧﺎ اﻟﺤﺼﻮل ﻋﻠﻰ ﻣﻘﺒﺾ ﻟﺤﻘﻞ ﻣﻌﻄﻴﺎت وﺣﻴﺪ‬
‫ﻓﻲ ﺑﻨﻴﺔ ﻣﻌﻴﻨﺔ ﻓﻌﻠﻴﻨﺎ أن ﻧﻤﺮر ﻣﻘﺒﺾ اﻟﺒﻨﻴﺔ ﻓﻲ هﺬا اﻟﻮﺳﻴﻂ‪ .‬إذا آﻨﺎ ﻧﺮﻳﺪ اﻟﺤﺼﻮل‬
‫ﻋﻠﻰ ﻣﻘﺒﺾ ﻟﻤﺘﺤﻮل ﻣﻮﺟﻮد ﻓﻲ أﻋﻠﻰ ﻣﺴﺘﻮى ﻋﻨﺪهﺎ ﻧﻤﺮر ﻗﻴﻤﺔ ‪.0‬‬
‫‪ :pName‬اﺳﻢ اﻟﻤﺘﺤﻮل اﻟﻤﺴﺘﺨﺪم ﻓﻲ اﻟﺸﻴﻔﺮة اﻟﻤﺼﺪرﻳﺔ ﻟﻠﻤﻈﻠﻞ واﻟﺬي ﻧﻮد اﻟﺤﺼﻮل‬ ‫‪R‬‬
‫ﻋﻠﻰ ﻣﻘﺒﺾ ﻟﻪ‪.‬‬
‫وآﺎن ﻣﻮﺟﻮدًا‬ ‫‪ViewProjMatrix‬‬ ‫ﻋﻠﻰ ﺳﺒﻴﻞ اﻟﻤﺜﺎل‪ ،‬ﻟﻮ آﺎن اﺳﻢ اﻟﻤﺘﺤﻮل ﻓﻲ اﻟﻤﻈﻠﻞ هﻮ‬
‫ﻓﻲ أﻋﻠﻰ ﻣﺴﺘﻮى ﻋﻨﺪهﺎ ﻧﻜﺘﺐ‪:‬‬
‫;‪D3DXHANDLE h0‬‬
‫;)"‪h0 = ConstTable->GetConstantByName(0, "ViewProjMatrix‬‬

‫‪@ @@ @oiaìrÛa@áîÓ@‡í‡¥@Z16.2.1.2‬‬

‫ﺣﺎﻟﻤﺎ ﻳﺤﺼﻞ ﺗﻄﺒﻴﻘﻨﺎ ﻋﻠﻰ ﻣﻘﺒﺾ ﻳﺸﻴﺮ إﻟﻰ ﻣﺘﺤﻮل ﻣﻌﻴﻦ ﻓﻲ ﺷﻴﻔﺮة اﻟﻤﻈﻠﻞ ﻋﻨﺪهﺎ‬
‫ﻧﺴﺘﻄﻴﻊ ﺗﺤﺪﻳﺪ ﻗﻴﻤﺔ اﻟﻤﺘﺤﻮل داﺧﻞ ﺗﻄﺒﻴﻘﻨﺎ ﻣﻦ ﺧﻼل اﺳﺘﺨﺪام اﻟﻤﻨﺎهﺞ‬
‫‪ .ID3DXConstantTable::SetXXX‬ﺣﻴﺚ ‪ ،XXX‬ﺗﺴﺘﺒﺪل ﺑﺎﺳﻢ ﻧﻮع ﻳﺪل ﻋﻠﻰ ﻧﻮع اﻟﻤﺘﺤﻮل‬
‫اﻟﻤﺮاد ﺗﺤﺪﻳﺪ ﻗﻴﻤﺘﻪ‪ .‬ﻋﻠﻰ ﺳﺒﻴﻞ اﻟﻤﺜﺎل‪ ،‬إذا آﺎن اﻟﻤﺘﺤﻮل اﻟﺬي ﻧﻮد ﺗﺤﺪﻳﺪ ﻗﻴﻤﺘﻪ هﻮ ﻧﺴﻖ‬
‫‪٣٣٧‬‬ ‫‪ :16‬ﻣﺪﺧﻞ إﻟﻰ ﻟﻐﺔ اﻟﺘﻈﻠﻴﻞ ﻋﺎﻟﻴﺔ اﻟﻤﺴﺘﻮى‬

‫ﻣﻦ اﻷﺷﻌﺔ ﻓﻌﻨﺪﺋﺬ ﻳﻜﻮن اﺳﻢ اﻟﻤﻨﻬﺞ ‪.SetVectorArray‬‬


‫اﻟﺼﻴﻐﺔ اﻟﻌﺎﻣﺔ ﻟﻤﻨﻬﺞ ‪ ID3DXConstantTable::SetXXX‬هﻲ ﻋﻠﻰ اﻟﺸﻜﻞ اﻟﺘﺎﻟﻲ‪:‬‬
‫(‪HRESULT ID3DXConstantTable::SetXXX‬‬
‫‪LPDIRECT3DDEVICE9 pDevice,‬‬
‫‪D3DXHANDLE hConstant,‬‬
‫‪XXX value‬‬
‫;)‬

‫‪ :pDevice‬ﻣﺆﺷﺮ إﻟﻰ اﻟﺠﻬﺎز اﻟﻤﺨﺼﺺ ﻟﺠﺪول اﻟﺜﻮاﺑﺖ‪.‬‬ ‫‪R‬‬

‫‪ :hConstant‬ﻣﻘﺒﺾ ﻳﺸﻴﺮ إﻟﻰ اﻟﻤﺘﺤﻮل اﻟﺬي ﻧﺮﻳﺪ ﺗﺤﺪﻳﺪ ﻗﻴﻤﺘﻪ‪.‬‬ ‫‪R‬‬

‫‪ :value‬اﻟﻘﻴﻤﺔ اﻟﺘﻲ ﻧﺮﻳﺪ وﺿﻌﻬﺎ ﻓﻲ اﻟﻤﺘﺤﻮل ﺣﻴﺚ أن ‪ XXX‬ﻳﺴﺘﺒﺪل ﺑﺎﺳﻢ ﻧﻮع‬ ‫‪R‬‬
‫اﻟﻤﺘﺤﻮل اﻟﺬي ﻧﺮﻳﺪ ﺗﺤﺪﻳﺪ ﻗﻴﻤﺘﻪ‪ .‬ﺑﺎﻟﻨﺴﺒﺔ إﻟﻰ ﺑﻌﺾ اﻷﻧﻮاع )ﻣﺜﻞ‪ bool :‬أو ‪ int‬أو‬
‫‪ (float‬ﻧﻤﺮر ﻧﺴﺨﺔ ﻣﻦ اﻟﻘﻴﻤﺔ‪ ،‬وﺑﺎﻟﻨﺴﺒﺔ ﻟﺒﻌﺾ اﻷﻧﻮاع اﻷﺧﺮى )ﻣﺜﻞ‪ vector :‬أو‬
‫‪ matrix‬أو اﻟﺒﻨﻰ( ﻧﻤﺮر ﻣﺆﺷﺮًا إﻟﻰ اﻟﻘﻴﻤﺔ‪.‬‬
‫ﻋﻨﺪ ﺗﺤﺪﻳﺪ ﻗﻴﻢ ﻣﺼﻔﻮﻓﺎت ﻳﺄﺧﺬ اﻟﻤﻨﻬﺞ ‪ SetXXX‬وﺳﻴﻄًﺎ راﺑﻌًﺎ إﺿﺎﻓﻴًﺎ ﻳﺤﺪد ﻋﺪد ﻋﻨﺎﺻﺮ‬
‫اﻟﻤﺼﻔﻮﻓﺔ‪ .‬ﻣﺜﻼً‪ ،‬ﻳﻜﻮن رأس اﻟﻤﻨﻬﺞ اﻟﺬي ﻳﻘﻮم ﺑﺘﺤﺪﻳﺪ ﻗﻴﻤﺔ ﻧﺴﻖ ﻣﻦ أﺷﻌﺔ رﺑﺎﻋﻴﺔ اﻷﺑﻌﺎد‬
‫ﺑﺎﻟﺸﻜﻞ اﻟﺘﺎﻟﻲ‪:‬‬
‫(‪HRESULT ID3DXConstantTable::SetVectorArray‬‬
‫‪LPDIRECT3DDEVICE9 pDevice,‬‬
‫‪D3DXHANDLE hConstant,‬‬
‫‪CONST D3DXVECTOR4* pVector,‬‬
‫‪UINT Count‬‬
‫;)‬

‫ﺗﺼﻒ اﻟﻼﺋﺤﺔ اﻟﺘﺎﻟﻴﺔ اﻷﻧﻮاع اﻟﺘﻲ ﻳﻤﻜﻨﻨﺎ اﺳﺘﺨﺪاﻣﻬﺎ ﻣﻦ ﺧﻼل اﻟﻮاﺟﻬﺔ‬


‫‪ .ID3DXConstantTable‬ﺑﻔﺮض أﻧﻪ ﻟﺪﻳﻨﺎ ﺟﻬﺎزًا اﺳﻤﻪ ‪ Device‬وﻣﻘﺒﺾ اﻟﻤﺘﺤﻮل اﻟﺬي ﻧﺮﻳﺪ‬
‫ﺗﺤﺪﻳﺪ ﻗﻴﻤﺘﻪ هﻮ ‪:handle‬‬
‫‪ :SetBool‬ﻳﺴﺘﺨﺪم ﻟﻮﺿﻊ ﻗﻴﻤﺔ ﺑﻮﻟﻴﺎﻧﻴﺔ‪:‬‬ ‫‪R‬‬
‫;‪bool b = true‬‬
‫;)‪ConstTable->SetBool(Device, handle, b‬‬

‫‪ :SetBoolArray‬ﻳﺴﺘﺨﺪم ﻟﻮﺿﻊ ﻧﺴﻖ ﻣﻦ اﻟﻘﻴﻢ ﺑﻮﻟﻴﺎﻧﻴﺔ‪:‬‬ ‫‪R‬‬


‫;}‪bool b[3] = {true, false, true‬‬
‫;)‪ConstTable->SetBoolArray(Device, handle, b, 3‬‬
‫اﻟﻤﻈﻠﻼت واﻟﺘﺄﺛﻴﺮات‬ ٣٣٨

:‫ ﻳﺴﺘﺨﺪم ﻟﻮﺿﻊ ﻗﻴﻤﺔ ﺣﻘﻴﻘﻴﺔ‬:SetFloat R


float f = 3.14f;
ConstTable->SetFloat(Device, handle, f);

:‫ ﻳﺴﺘﺨﺪم ﻟﻮﺿﻊ ﻧﺴﻖ ﻣﻦ اﻟﻘﻴﻢ اﻟﺤﻘﻴﻘﻴﺔ‬:SetFloatArray R


float f[2] = {1.0f, 2.0f};
ConstTable->SetFloatArray(Device, handle, f, 2);

:‫ ﻳﺴﺘﺨﺪم ﻟﻮﺿﻊ ﻗﻴﻤﺔ ﺻﺤﻴﺤﺔ‬:SetInt R


int x = 4;
ConstTable->SetInt(Device, handle, x);

:‫ ﻳﺴﺘﺨﺪم ﻟﻮﺿﻊ ﻧﺴﻖ ﻣﻦ اﻟﻘﻴﻢ اﻟﺼﺤﻴﺤﺔ‬:SetIntArray R


int x[4] = {1, 2, 3, 4};
ConstTable->SetIntArray(Device, handle, x, 4);

:4×4 ‫ ﻳﺴﺘﺨﺪم ﻟﻮﺿﻊ ﻗﻴﻢ ﻣﺼﻔﻮﻓﺔ‬:SetMatrix R


D3DXMATRIX M(...);
ConstTable->SetMatrix(Device, handle, &M);

:4×4 ‫ ﻳﺴﺘﺨﺪم ﻟﻮﺿﻊ ﻗﻴﻢ ﻧﺴﻖ ﻣﻦ اﻟﻤﺼﻔﻮﻓﺎت‬:SetMatrixArray R


D3DXMATRIX M[4];

// ...initialize matrices.

ConstTable->SetMatrixArray(Device, handle, M, 4);

‫ ﻳﺴﺘﺨﺪم ﻟﻮﺿﻊ ﻗﻴﻢ ﻧﺴﻖ ﻣﻦ ﻣﺆﺷﺮات ﺗﺸﻴﺮ آﻞ ﻣﻨﻬﺎ إﻟﻰ‬:SetMatrixPointerArray R


:4×4 ‫ﻣﺼﻔﻮﻓﺔ‬
D3DXMATRIX* M[4];

// ...allocate and initialize matrix pointers.

ConstTable->SetMatrixPointerArray(Device, handle, M, 4);

.4×4 ‫ ﻳﺴﺘﺨﺪم ﻟﻮﺿﻊ ﻗﻴﻤﺔ ﻣﻨﻘﻮل ﻣﺼﻔﻮﻓﺔ‬:SetMatrixTranspose R


D3DXMATRIX M(...);
D3DXMatrixTranspose(&M, &M);
ConstTable->SetMatrixTranspose(Device, handle, &M);

:4×4 ‫ ﻳﺴﺘﺨﺪم ﻟﻮﺿﻊ ﻗﻴﻢ ﻧﺴﻖ ﻣﻦ ﻣﻨﻘﻮﻻت ﻟﻤﺼﻔﻮﻓﺎت‬:SetMatrixTransposeArray R


D3DXMATRIX M[4];
٣٣٩ ‫ ﻣﺪﺧﻞ إﻟﻰ ﻟﻐﺔ اﻟﺘﻈﻠﻴﻞ ﻋﺎﻟﻴﺔ اﻟﻤﺴﺘﻮى‬:16

// ...initialize matrices and transpose them.

ConstTable->SetMatrixTransposeArray(Device, handle, M, 4);

‫ ﻳﺴﺘﺨﺪم ﻟﻮﺿﻊ ﻗﻴﻢ ﻧﺴﻖ ﻣﻦ اﻟﻤﺆﺷﺮات ﻳﺸﻴﺮ‬:SetMatrixTransposePointerArray R


:4×4 ‫آﻞ ﻣﻨﻬﺎ إﻟﻰ ﻣﻨﻘﻮل ﻣﺼﻔﻮﻓﺔ‬
D3DXMATRIX M[4];

// ...allocate and initialize matrices and transpose them.

ConstTable->SetMatrixTransposePointerArray(Device, handle, M, 4);

:D3DXVECTOR4 ‫ ﻳﺴﺘﺨﺪم ﻟﻮﺿﻊ ﻗﻴﻢ ﻣﺘﺤﻮل ﻣﻦ اﻟﻨﻮع‬:SetVector R


D3DXVECTOR4 v(1.0f, 2.0f, 3.0f, 4.0f);
ConstTable->SetVector(Device, handle, &v);

:‫ ﻳﺴﺘﺨﺪم ﻟﻮﺿﻊ ﻗﻴﻤﺔ ﻣﺘﺤﻮل ﻋﺒﺎرة ﻋﻦ ﻧﺴﻖ ﻣﻦ اﻷﺷﻌﺔ‬:SetVectorArray R


D3DXVECTOR4 v[3];

// ...initialize vectors

ConstTable->SetVectorArray(Device, handle, v, 3);


‫ﻼ ﻻﺳﺘﺨﺪام‬
ً ‫ ﻣﺜ‬.‫ ﻳﺴﺘﺨﺪم ﻟﻮﺿﻊ ﻗﻴﻤﺔ ﻣﻦ ﻧﻮع ذو ﺣﺠﻢ ﻏﻴﺮ ﻣﺒﻴﻦ ﻣﺜﻞ ﺑﻨﻴﺔ‬:SetValue R
:‫ ﻧﻜﺘﺐ‬D3DXMATRIX ‫ ﻟﻮﺿﻊ ﻗﻴﻤﺔ ﻣﻦ اﻟﻨﻮع‬SetValue
D3DXMATRIX M(...);
ConstTable->SetValue(Device, handle, (void*)&M, sizeof(M));

@ @@ @òîšaÏüa@oiaìrÛa@áîÓ@‡í‡¥@:16.2.1.3

‫ واﻟﺘﻲ هﻲ اﻟﻘﻴﻢ اﻟﺘﻲ ﺗﻢ اﺳﺘﺨﺪاﻣﻬﺎ ﻓﻲ‬،‫ﻳﻘﻮم اﻟﻤﻨﻬﺞ اﻟﺘﺎﻟﻲ ﺑﻮﺿﻊ اﻟﺜﻮاﺑﺖ ﺑﻘﻴﻤﻬﺎ اﻻﻓﺘﺮاﺿﻴﺔ‬
‫ ﻳﺠﺐ اﺳﺘﺪﻋﺎء هﺬا اﻟﻤﻨﻬﺞ ﻣﺮة واﺣﺪة أﺛﻨﺎء إﻋﺪاد‬.‫ﺗﻬﻴﺌﺔ اﻟﺜﻮاﺑﺖ ﻋﻨﺪﻣﺎ ﺗﻢ اﻟﺘﺼﺮﻳﺢ ﻋﻨﻬﺎ‬
:‫اﻟﺘﻄﺒﻴﻖ‬
HRESULT ID3DXConstantTable::SetDefaults(
LPDIRECT3DDEVICE9 pDevice
);
.‫ ﻣﺆﺷﺮ إﻟﻰ اﻟﺠﻬﺎز اﻟﻤﺨﺼﺺ ﻟﺠﺪول اﻟﺜﻮاﺑﺖ‬:pDevice R
‫اﻟﻤﻈﻠﻼت واﻟﺘﺄﺛﻴﺮات‬ ‫‪٣٤٠‬‬

‫‪@ @@ @HLSL@òÌÜi@ÝÜÄß@ò»‹m@Z16.2.2‬‬

‫ﻳﺘﻢ ﺗﺮﺟﻤﺔ ﻣﻈﻠﻞ ﺑﻌﺪ آﺘﺎﺑﺘﻪ ﻓﻲ ﻣﻠﻒ ﻧﺼﻲ ﺑﺎﺳﺘﺨﺪام اﻟﺘﺎﺑﻊ اﻟﺘﺎﻟﻲ‪:‬‬
‫(‪HRESULT D3DXCompileShaderFromFile‬‬
‫‪LPCTSTR pSrcFile,‬‬
‫‪CONST D3DXMACRO* pDefines,‬‬
‫‪LPD3DXINCLUDE pInclude,‬‬
‫‪LPCTSTR pFunctionName,‬‬
‫‪LPCTSTR pTarget,‬‬
‫‪DWORD Flags,‬‬
‫‪LPD3DXBUFFER* ppShader,‬‬
‫‪LPD3DXBUFFER *ppErrorMsgs,‬‬
‫‪LPD3DXSHADER_CONSTANTTABLE *ppConstantTable‬‬
‫;)‬

‫‪ :pSrcFile‬اﺳﻢ اﻟﻤﻠﻒ اﻟﻨﺼﻲ اﻟﺤﺎوي ﻋﻠﻰ اﻟﺸﻴﻔﺮة اﻟﻤﺼﺪرﻳﺔ ﻟﻠﻤﻈﻠﻞ اﻟﺬي ﺗﺮﻳﺪ‬ ‫‪R‬‬
‫ﺗﺮﺟﻤﺘﻪ‪.‬‬
‫‪ :pDefines‬هﺬا اﻟﻮﺳﻴﻂ ﺧﻴﺎري ﻟﺬا ﺳﻨﻤﺮر ﻓﻴﻪ اﻟﻘﻴﻤﺔ ‪ null‬ﺣﻴﺜﻤﺎ ورد ﻓﻲ اﻟﻜﺘﺎب‪.‬‬ ‫‪R‬‬

‫‪ :pInclude‬ﻣﺆﺷﺮ إﻟﻰ واﺟﻬﺔ ‪ .ID3DXInclude‬هﺬﻩ اﻟﻮاﺟﻬﺔ ﻣﺼﻤﻤﺔ ﺑﺤﻴﺚ ﻳﺘﻢ‬ ‫‪R‬‬


‫ﺗﺤﻘﻴﻘﻬﺎ ﻓﻲ اﻟﺘﻄﺒﻴﻖ ﺣﺘﻰ ﻧﻘﻮم ﺑﺘﺠﺎوز ﺳﻠﻮك اﻟﺘﻀﻤﻴﻦ اﻻﻓﺘﺮاﺿﻲ‪ .‬ﻋﻠﻰ اﻟﻌﻤﻮم إن‬
‫اﻟﺴﻠﻮك اﻻﻓﺘﺮاﺿﻲ ﻣﻨﺎﺳﺐ ﻟﻨﺎ ﻟﺬا ﻳﻤﻜﻨﻨﺎ ﺗﺠﺎهﻞ هﺬا اﻟﻮﺳﻴﻂ ﺑﻮﺿﻊ ﻗﻴﻤﺔ ‪ null‬ﻓﻴﻪ‪.‬‬
‫ﻼ إذا آﺎن اﺳﻢ ﺗﺎﺑﻊ‬
‫‪ :pFunctionName‬ﺳﻠﺴﻠﺔ رﻣﺰﻳﺔ ﺗﺤﺪد اﺳﻢ ﺗﺎﺑﻊ ﻧﻘﻄﺔ اﻟﺪﺧﻮل‪ .‬ﻣﺜ ً‬ ‫‪R‬‬
‫ﻧﻘﻄﺔ اﻟﺪﺧﻮل ﻓﻲ اﻟﻤﻈﻠﻞ ‪ Main‬ﻋﻨﺪهﺎ ﻧﻤﺮر اﻟﺴﻠﺴﻠﺔ "‪ "Main‬ﻓﻲ هﺬا اﻟﻮﺳﻴﻂ‪.‬‬
‫‪HLSL‬‬ ‫‪ :pTarget‬ﺳﻠﺴﻠﺔ رﻣﺰﻳﺔ ﺗﺤﺪد إﺻﺪار اﻟﻤﻈﻠﻞ اﻟﺬي ﻧﺮﻳﺪ ﺗﺮﺟﻤﺔ ﺷﻴﻔﺮة‬ ‫‪R‬‬
‫اﻟﻤﺼﺪرﻳﺔ ﺑﻪ‪ .‬إن إﺻﺪارات ﻣﻈﻠﻼت اﻟﺮؤوس اﻟﻤﺘﺎﺣﺔ‪ vs_1_1 :‬و‪vs_2_0‬‬
‫و‪ .vs_2_sw‬إﺻﺪارات ﻣﻈﻠﻼت اﻟﻌﻨﺼﻮرات اﻟﻤﺘﺎﺣﺔ‪ ps_1_1 :‬و‪ ps_1_2‬و‪ps_1_3‬‬
‫و‪ ps_1_4‬و‪ ps_2_0‬و‪ .ps_2_sw‬ﻣﺜﻼً‪ ،‬إذا أردﻧﺎ ﺗﺮﺟﻤﺔ ﻣﺜﺎل ﻣﻈﻠﻞ اﻟﺮؤوس‬
‫اﻟﻤﻌﺮوض ﻓﻲ أول اﻟﻔﺼﻞ إﻟﻰ اﻹﺻﺪار ‪ 2.0‬ﻋﻨﺪهﺎ ﻧﻤﺮر ‪ vs_2_0‬ﻓﻲ هﺬا اﻟﻮﺳﻴﻂ‪.‬‬

‫إن اﻟﻘﺪرة ﻋﻠﻰ اﻟﺘﺮﺟﻤﺔ إﻟﻰ إﺻﺪارات ﻣﺨﺘﻠﻔﺔ ﻟﻠﻤﻈﻠﻼت هﻲ إﺣﺪى اﻟﻔﻮاﺋﺪ‬
‫ﻻ ﻣﻦ ﻟﻐﺔ اﻟﺘﺠﻤﻴﻊ‪ .‬ﻳﻤﻜﻨﻨﺎ ﻣﻦ ﺧﻼل‬ ‫اﻟﺮﺋﻴﺴﻴﺔ ﻣﻦ اﺳﺘﺨﺪام ﻟﻐﺔ ‪ HLSL‬ﺑﺪ ً‬
‫اﺳﺘﺨﺪام ﻟﻐﺔ ‪ HLSL‬ﺗﺼﺪﻳﺮ أي ﻣﻈﻠﻞ ﺗﻘﺮﻳﺒًﺎ إﻟﻰ أي إﺻﺪار ﺑﺒﺴﺎﻃﺔ ﻋﻦ‬
‫ﻃﺮﻳﻖ إﻋﺎدة ﺗﺮﺟﻤﺘﻪ إﻟﻰ اﻹﺻﺪار اﻟﻤﻄﻠﻮب‪ ،‬أﻣﺎ ﻋﻨﺪ اﺳﺘﺨﺪام ﻟﻐﺔ اﻟﺘﺠﻤﻴﻊ‬
‫ﻓﻌﻠﻴﻨﺎ ﺗﺼﺪﻳﺮ اﻟﺸﻴﻔﺮة ﻳﺪوﻳًﺎ‪.‬‬

‫ﻟﺘﺤﺪﻳﺪ ﻋﺪم‬ ‫‪0‬‬ ‫‪ :Flags‬ﻋﺒﺎرة ﻋﻦ ﻣﺠﻤﻮﻋﺔ ﻣﻦ أﻋﻼم ﺧﻴﺎرﻳﺔ ﻟﻠﺘﺮﺟﻤﺔ )ﺿﻊ ﻗﻴﻤﺔ‬ ‫‪R‬‬
‫‪٣٤١‬‬ ‫‪ :16‬ﻣﺪﺧﻞ إﻟﻰ ﻟﻐﺔ اﻟﺘﻈﻠﻴﻞ ﻋﺎﻟﻴﺔ اﻟﻤﺴﺘﻮى‬

‫وﺟﻮد أﻋﻼم( اﻟﺨﻴﺎرات اﻟﻤﺘﺎﺣﺔ هﻲ‪:‬‬


‫‪ :D3DXSHADER_DEBUG‬ﻳﺄﻣﺮ اﻟﻤﺘﺮﺟﻢ ﺑﻜﺘﺎﺑﺔ ﻣﻌﻠﻮﻣﺎت اﻟﺘﻨﻘﻴﺢ‪.‬‬ ‫‪Q‬‬

‫‪ :D3DXSHADER_SKIPVALIDATION‬ﻳﺄﻣﺮ اﻟﻤﺘﺮﺟﻢ ﺑﻌﺪم إﺟﺮاء أي ﻓﺤﺺ‬ ‫‪Q‬‬


‫ﻟﻠﺸﻴﻔﺮة )ﻳﺠﺐ أن ﻻ ﻳﺴﺘﺨﺪم هﺬا اﻟﻌﻠﻢ ﻣﻊ أي ﻣﻈﻠﻞ إﻻ إذا آﻨﺖ واﺛﻘًﺎ ﻣﻦ أﻧﻪ‬
‫ﻳﻌﻤﻞ(‪.‬‬
‫‪ :D3DXSHADER_SKIPOPTIMIZATION‬ﻳﺄﻣﺮ اﻟﻤﺘﺮﺟﻢ ﺑﻌﺪم إﺟﺮاء أي اﺧﺘﺰال‬ ‫‪Q‬‬
‫ﻟﻠﺸﻴﻔﺮة‪ .‬ﻋﻤﻠﻴًﺎ ﻳﺴﺘﺨﺪم هﺬا ﻓﻘﻂ ﻣﻦ أﺟﻞ اﻟﺘﻨﻘﻴﺢ ﺣﻴﺚ ﻻ ﺗﺮﻏﺐ أن ﻳﻘﻮم‬
‫اﻟﻤﺘﺮﺟﻢ ﺑﺘﻐﻴﻴﺮ اﻟﺸﻴﻔﺮة ﺑﺄي ﺷﻜﻞ آﺎن‪.‬‬
‫‪ :ppShader‬ﻳﻌﻴﺪ ﻣﺆﺷﺮًا إﻟﻰ واﺟﻬﺔ ‪ ID3DXBuffer‬ﺗﺤﺘﻮي ﻋﻠﻰ ﺷﻴﻔﺮة اﻟﻤﻈﻠﻞ‬ ‫‪R‬‬
‫اﻟﻤﺘﺮﺟﻤﺔ‪ .‬ﺗﺴﺘﺨﺪم ﺷﻴﻔﺮة اﻟﻤﻈﻠﻞ اﻟﻤﺘﺮﺟﻤﺔ هﺬﻩ ﺑﻌﺪ ذﻟﻚ آﻮﺳﻴﻂ ﻟﺘﺎﺑﻊ ﺁﺧﺮ ﻳﻨﺸﺊ‬
‫ﻣﻈﻠﻞ اﻟﺮؤوس أو اﻟﻌﻨﺼﻮرات اﻟﻔﻌﻠﻲ‪.‬‬
‫ﺗﺤﺘﻮي ﻋﻠﻰ ﺳﻠﺴﻠﺔ رﻣﺰﻳﺔ‬ ‫‪ID3DXBuffer‬‬ ‫‪ :ppErrorMsgs‬ﻳﻌﻴﺪ ﻣﺆﺷﺮًا إﻟﻰ واﺟﻬﺔ‬ ‫‪R‬‬
‫ﻓﻴﻬﺎ ﺷﻴﻔﺮات ورﺳﺎﺋﻞ اﻟﺨﻄﺄ‪.‬‬
‫ﺗﺤﺘﻮي ﻋﻠﻰ‬ ‫‪ID3DXConstantTable‬‬ ‫‪ :ppConstantTable‬ﻳﻌﻴﺪ ﻣﺆﺷﺮًا إﻟﻰ واﺟﻬﺔ‬ ‫‪R‬‬
‫ﻣﻌﻄﻴﺎت ﺟﺪول ﺛﻮاﺑﺖ هﺬا اﻟﻤﻈﻠﻞ‪.‬‬
‫ﻓﻴﻤﺎ ﻳﻠﻲ ﻣﺜﺎل ﺣﻮل اﺳﺘﺪﻋﺎء ‪:D3DXCompileShaderFromFile‬‬
‫‪//‬‬
‫‪// Compile shader.‬‬
‫‪//‬‬

‫;‪ID3DXConstantTable* TransformConstantTable = 0‬‬


‫‪ID3DXBuffer* shader‬‬ ‫;‪= 0‬‬
‫;‪ID3DXBuffer* errorBuffer = 0‬‬

‫(‪hr = D3DXCompileShaderFromFile‬‬
‫‪"transform.txt",‬‬
‫‪0,‬‬
‫‪0,‬‬
‫‪"Main", // entry point function name‬‬
‫‪"vs_2_0",// shader version to compile to‬‬
‫‪D3DXSHADER_DEBUG,‬‬
‫‪&shader,‬‬
‫‪&errorBuffer,‬‬
‫;)‪&TransformConstantTable‬‬

‫‪// output any error messages‬‬


‫) ‪if( errorBuffer‬‬
‫اﻟﻤﻈﻠﻼت واﻟﺘﺄﺛﻴﺮات‬ ‫‪٣٤٢‬‬

‫{‬
‫;)‪::MessageBox(0, (char*)errorBuffer->GetBufferPointer(), 0, 0‬‬
‫;)‪d3d::Release<ID3DXBuffer*>(errorBuffer‬‬
‫}‬

‫))‪if(FAILED(hr‬‬
‫{‬
‫;)‪::MessageBox(0, "D3DXCreateEffectFromFile() - FAILED", 0, 0‬‬
‫;‪return false‬‬
‫}‬

‫@@ @‬ ‫‪@@püìzn¾a@Êaìãc@Z16.3‬‬
‫هﻨﺎﻟﻚ ﺑﻌﺾ اﻷﻧﻮاع اﻟﻐﺮﺿﻴﺔ اﻟﻀﻤﻨﻴﺔ ﻓﻲ ‪ HLSL‬ﺑﺎﻹﺿﺎﻓﺔ إﻟﻰ اﻷﻧﻮاع‬
‫اﻟﻤﻮﺻﻮﻓﺔ ﻓﻲ اﻟﻔﻘﺮات اﻟﺘﺎﻟﻴﺔ )ﻣﺜﻞ ﻏﺮض ‪ (texture‬ﻟﻜﻦ ﺑﻤﺎ أن هﺬﻩ‬
‫اﻷﻧﻮاع اﻟﻐﺮﺿﻴﺔ ﺗﺴﺘﺨﺪم ﺑﺸﻜﻞ رﺋﻴﺴﻲ ﻓﻘﻂ ﻓﻲ إﻃﺎر ﻋﻤﻞ اﻟﺘﺄﺛﻴﺮات ﻟﺬا‬
‫ﻧﺆﺟﻞ دراﺳﺘﻬﻢ إﻟﻰ اﻟﻔﺼﻞ اﻟﺘﺎﺳﻊ ﻋﺸﺮ‪.‬‬

‫@@ @‬ ‫‪@@ @òîàÜÛa@Êaìãþa@Z16.3.1‬‬

‫ﺗﺰودﻧﺎ ﻟﻐﺔ ‪ HLSL‬ﺑﺎﻷﻧﻮاع اﻟﺴﻠﻤﻴﺔ اﻟﺘﺎﻟﻴﺔ‪:‬‬


‫هﻤﺎ آﻠﻤﺘﺎن ﻣﺤﺠﻮزﺗﺎن ﺿﻤﻦ‬ ‫‪ true‬و‪false‬‬ ‫)ﻻﺣﻆ أن‬ ‫‪false‬‬ ‫أو‬ ‫‪true‬‬ ‫‪ :bool‬ﻳﺄﺧﺬ ﻗﻴﻤﺔ‬ ‫‪R‬‬
‫ﻟﻐﺔ ‪.(HLSL‬‬
‫‪ :int‬ﻋﺪد ﺻﺤﻴﺢ ﻣﺆﺷﺮ ﺑﻌﺮض ‪ 32‬ﺑﺖ‪.‬‬ ‫‪R‬‬

‫‪ :half‬ﻋﺪد ذو ﻓﺎﺻﻠﺔ ﻋﺎﺋﻤﺔ ﺑﻌﺮض ‪ 16‬ﺑﺖ‪.‬‬ ‫‪R‬‬

‫‪ :float‬ﻋﺪد ذو ﻓﺎﺻﻠﺔ ﻋﺎﺋﻤﺔ ﺑﻌﺮض ‪ 32‬ﺑﺖ‪.‬‬ ‫‪R‬‬

‫‪ :double‬ﻋﺪد ذو ﻓﺎﺻﻠﺔ ﻋﺎﺋﻤﺔ ﺑﻌﺮض ‪ 64‬ﺑﺖ‪.‬‬ ‫‪R‬‬

‫و‪ .double‬ﻓﻲ هﺬﻩ اﻟﺤﺎﻟﺔ ﻳﺘﻢ‬ ‫‪ int‬و‪half‬‬ ‫ﻗﺪ ﻻ ﺗﺪﻋﻢ ﺑﻌﺾ اﻷﻧﻈﻤﺔ اﻷﻧﻮاع‪:‬‬
‫اﺳﺘﺨﺪام اﻟﻨﻮع ‪ float‬ﺑﺪ ً‬
‫ﻻ ﻋﻨﻬﺎ‪.‬‬

‫@@ @‬ ‫‪@òÈ’þa@Êaìãc@Z16.3.2‬‬

‫ﻳﻮﺟﺪ ﻓﻲ ﻟﻐﺔ ‪ HLSL‬أﻧﻮاع اﻷﺷﻌﺔ اﻟﻀﻤﻨﻴﺔ اﻟﺘﺎﻟﻴﺔ‪:‬‬


‫‪٣٤٣‬‬ ‫‪ :16‬ﻣﺪﺧﻞ إﻟﻰ ﻟﻐﺔ اﻟﺘﻈﻠﻴﻞ ﻋﺎﻟﻴﺔ اﻟﻤﺴﺘﻮى‬

‫‪ :vector‬ﺷﻌﺎع رﺑﺎﻋﻲ اﻷﺑﻌﺎد ﺗﻜﻮن آﻞ ﻣﺮآﺒﺔ ﻓﻴﻪ ﻣﻦ اﻟﻨﻮع ‪.float‬‬ ‫‪R‬‬

‫>‪ :vector<T, n‬ﺷﻌﺎع ذو ‪ n‬ﺑﻌﺪ ﺣﻴﺚ ﺗﻜﻮن آﻞ ﻣﺮآﺒﺔ ﻓﻴﻪ ﻣﻦ اﻟﻨﻮع اﻟﺴﻠﻤﻲ ‪.T‬‬ ‫‪R‬‬
‫اﻟﺒﻌﺪ ‪ n‬ﻳﺠﺐ أن ﻳﻜﻮن ﺑﻴﻦ ‪ 1‬و‪ .4‬هﻨﺎ ﻣﺜﺎل ﻋﻦ ﺷﻌﺎع ﺛﻨﺎﺋﻲ اﻷﺑﻌﺎد ﻣﺮآﺒﺎﺗﻪ أﻋﺪاد‬
‫ﺣﻘﻴﻘﻴﺔ ذات دﻗﺔ ﻣﻀﺎﻋﻔﺔ‪:‬‬
‫;‪vector<double, 2> vec2‬‬

‫ﻼ ﻟﻮﺿﻊ‬
‫ﻳﻤﻜﻨﻨﺎ اﻟﻮﻟﻮج إﻟﻰ أي ﻣﺮآﺒﺔ ﻓﻲ ﺷﻌﺎع ﺑﺎﺳﺘﺨﺪام اﻟﺼﻴﻐﺔ اﻟﺪﻟﻴﻠﻴﺔ ﻟﻸﻧﺴﺎق‪ .‬ﻣﺜ ً‬
‫ﻗﻴﻤﺔ ﻓﻲ اﻟﻤﺮآﺒﺔ )‪ (i‬ﻣﻦ اﻟﺸﻌﺎع ‪ vec‬ﻧﻜﺘﺐ‪:‬‬
‫;‪vec[i] = 2.0f‬‬

‫آﻤﺎ ﻳﻤﻜﻨﻨﺎ أﻳﻀًﺎ اﻟﻮﻟﻮج إﻟﻰ ﻣﺮآﺒﺎت ﺷﻌﺎع ‪ vec‬ﻣﺜﻠﻤﺎ ﻳﺘﻢ اﻟﻮﻟﻮج إﻟﻰ ﺣﻘﻮل أي ﺑﻨﻴﺔ ﻋﻦ‬
‫ﻃﺮﻳﻖ أﺳﻤﺎء اﻟﻤﺮآﺒﺎت اﻟﻤﻌﺮﻓﺔ اﻟﺘﺎﻟﻴﺔ‪.a, b, g, r, w, z, y, x :‬‬
‫‪vec.x‬‬ ‫=‬ ‫‪vec.r‬‬ ‫=‬ ‫;‪1.0f‬‬
‫‪vec.y‬‬ ‫=‬ ‫‪vec.g‬‬ ‫=‬ ‫;‪2.0f‬‬
‫‪vec.z‬‬ ‫=‬ ‫‪vec.b‬‬ ‫=‬ ‫;‪3.0f‬‬
‫‪vec.w‬‬ ‫=‬ ‫‪vec.a‬‬ ‫=‬ ‫;‪4.0f‬‬

‫ﺣﻴﺚ ﺗﺸﻴﺮ اﻷﺳﻤﺎء ‪ a, b, g, r‬إﻟﻰ ﻧﻔﺲ اﻟﻤﺮآﺒﺎت اﻟﺘﻲ ﺗﺸﻴﺮ إﻟﻴﻬﺎ اﻷﺳﻤﺎء ‪ w, z, y, x‬ﻋﻠﻰ‬
‫اﻟﺘﺮﺗﻴﺐ‪ .‬ﺣﻴﺚ أﻧﻪ ﻣﻦ اﻷﻓﻀﻞ اﺳﺘﺨﺪام ﺻﻴﻐﺔ ‪ RGBA‬ﻟﺘﻤﺜﻴﻞ اﻷﻟﻮان ﻷن ذﻟﻚ ﻳﺆآﺪ أن‬
‫اﻟﺸﻌﺎع ﻳﻤﺜﻞ ﻟﻮﻧًﺎ‪.‬‬
‫ﻻ ﻣﻦ ذﻟﻚ اﺳﺘﺨﺪام اﻷﻧﻮاع اﻟﻤﺴﺒﻘﺔ اﻟﺘﻌﺮﻳﻒ اﻷﺧﺮى اﻟﺘﻲ ﺗﻤﺜﻞ أﺷﻌﺔ ﺛﻨﺎﺋﻴﺔ‬ ‫ﻳﻤﻜﻨﻨﺎ ﺑﺪ ً‬
‫اﻷﺑﻌﺎد وﺛﻼﺛﻴﺔ اﻷﺑﻌﺎد ورﺑﺎﻋﻴﺔ اﻷﺑﻌﺎد‪:‬‬
‫;‪float2 vec2‬‬
‫;‪float3 vec3‬‬
‫;‪float4 vec4‬‬
‫ﻟﻴﻜﻦ ﻟﺪﻳﻨﺎ اﻟﺸﻌﺎع )‪ ،u = (ux, uy, uz, uw‬وﻧﻮد ﻧﺴﺦ ﻣﺮآﺒﺎت ‪ u‬إﻟﻰ ﺷﻌﺎع ‪ v‬ﻟﻴﺼﺒﺢ‬
‫)‪ .v = (vx, vy, vz, vw‬ﻳﻜﻮن اﻟﺤﻞ اﻟﺒﺪﻳﻬﻲ هﻮ ﻧﺴﺦ آﻞ ﻣﺮآﺒﺔ ﻣﻦ ‪ u‬إﻟﻰ ‪ v‬آﻞ ﻋﻠﻰ ﺣﺪة‬
‫ﺣﺴﺐ اﻟﺤﺎﺟﺔ‪ .‬وﻟﻜﻦ ﺗﺰودﻧﺎ ﻟﻐﺔ ‪ HLSL‬ﺑﺼﻴﻐﺔ ﺧﺎﺻﺔ ﻹﺟﺮاء هﺬا اﻟﻨﻮع اﻟﺨﺎص ﻣﻦ‬
‫اﻟﻨﺴﺦ ﺗﺪﻋﻰ )‪:(swizzle‬‬
‫;}‪vector u = {1.0f, 2.0f, 3.0f, 4.0f‬‬
‫;}‪vector v = {0.0f, 0.0f, 5.0f, 6.0f‬‬

‫} ‪v = u.xyyw; // v = {1.0f, 2.0f, 2.0f, 4.0f‬‬

‫‪y, x‬‬ ‫ﻼ ﻳﻤﻜﻨﻨﺎ ﻧﺴﺦ اﻟﻤﺮآﺒﺘﻴﻦ‬


‫ﻻ ﻳﺘﻮﺟﺐ ﻋﻠﻴﻨﺎ ﻧﺴﺦ آﻞ اﻟﻤﺮآﺒﺎت ﻋﻨﺪ ﻧﺴﺦ اﻷﺷﻌﺔ‪ .‬ﻣﺜ ً‬
‫ﻓﻘﻂ آﻤﺎ ﻳﺘﻀﺢ ﻣﻦ اﻟﺸﻴﻔﺮة اﻟﺘﺎﻟﻴﺔ‪:‬‬
‫اﻟﻤﻈﻠﻼت واﻟﺘﺄﺛﻴﺮات‬ ‫‪٣٤٤‬‬

‫;}‪vector u = {1.0f, 2.0f, 3.0f, 4.0f‬‬


‫;}‪vector v = {0.0f, 0.0f, 5.0f, 6.0f‬‬

‫} ‪v.xy = u; // v = {1.0f, 2.0f, 5.0f, 6.0f‬‬

‫@@ @‬ ‫‪@@ @pbÏìЗ¾a@Êaìãc@Z16.3.3‬‬

‫ﻳﻮﺟﺪ ﻓﻲ ﻟﻐﺔ ‪ HLSL‬أﻧﻮاع اﻟﻤﺼﻔﻮﻓﺎت اﻟﻀﻤﻨﻴﺔ اﻟﺘﺎﻟﻴﺔ‪:‬‬


‫‪ :matrix‬ﻣﺼﻔﻮﻓﺔ ‪ 4×4‬ﺣﻴﺚ آﻞ ﺣﺠﺮة ﻓﻴﻬﺎ ﻣﻦ اﻟﻨﻮع ‪.float‬‬ ‫‪R‬‬

‫>‪ :matrix<T, m, n‬ﻣﺼﻔﻮﻓﺔ ‪ m×n‬ﺣﻴﺚ آﻞ ﺣﺠﺮة ﻓﻴﻬﺎ ﻣﻦ اﻟﻨﻮع اﻟﺴﻠﻤﻲ ‪ T‬ﻳﺠﺐ‬ ‫‪R‬‬
‫أن ﺗﻜﻮن أﺑﻌﺎد اﻟﻤﺼﻔﻮﻓﺔ ‪ n, m‬ﺑﻴﻦ ‪ 1‬و ‪ .4‬هﻨﺎ ﻣﺜﺎل ﻋﻦ ﻣﺼﻔﻮﻓﺔ ‪ 2×2‬ﻣﻦ اﻷﻋﺪاد‬
‫اﻟﺼﺤﻴﺤﺔ‪:‬‬
‫;‪matrix<int, 2, 2> m2x2‬‬

‫و ‪ (4‬ﺑﺎﺳﺘﺨﺪام‬ ‫‪1‬‬ ‫ﻳﺘﺮواﺣﺎن ﺑﻴﻦ‬ ‫‪n, m‬‬ ‫)ﺣﻴﺚ‬ ‫‪m×n‬‬ ‫ﻻ ﻣﻦ ذﻟﻚ ﺗﻌﺮﻳﻒ ﻣﺼﻔﻮﻓﺔ‬ ‫ﻳﻤﻜﻨﻨﺎ ﺑﺪ ً‬
‫اﻟﺼﻴﻐﺔ اﻟﺘﺎﻟﻴﺔ‪:‬‬
‫;‪floatmxn matmxn‬‬
‫أﻣﺜﻠﺔ‪:‬‬
‫‪float2x2‬‬ ‫;‪mat2x2‬‬
‫‪float3x3‬‬ ‫;‪mat3x3‬‬
‫‪float4x4‬‬ ‫;‪mat4x4‬‬
‫‪float2x4‬‬ ‫;‪mat2x4‬‬

‫ﻟﻴﺲ ﻣﻦ اﻟﻼزم أن ﻳﻜﻮن اﻟﻨﻮع هﻮ ‪ float‬داﺋﻤًﺎ‪ .‬ﺣﻴﺚ ﻳﻤﻜﻨﻨﺎ اﺳﺘﺨﺪام أي‬


‫ﻧﻮع ﺁﺧﺮ‪ .‬ﻣﺜﻼً‪ ،‬ﻻﺳﺘﺨﺪام أﻋﺪاد ﺻﺤﻴﺤﺔ ﻧﻜﺘﺐ‪:‬‬
‫;‪int2x2 i2x2‬‬
‫;‪int3x3 i3x3‬‬
‫;‪int2x4 i2x4‬‬
‫ﻳﻤﻜﻨﻨﺎ اﻟﻮﻟﻮج إﻟﻰ أي ﺣﺠﺮة ﻓﻲ ﻣﺼﻔﻮﻓﺔ ﺑﺎﺳﺘﺨﺪام اﻟﺼﻴﻐﺔ اﻟﺪﻟﻴﻠﻴﺔ اﻟﻤﺰدوﺟﺔ ﻟﻸﻧﺴﺎق‪.‬‬
‫ﻣﺜﻼً‪ ،‬ﻟﻮﺿﻊ ﻗﻴﻤﺔ ﻓﻲ اﻟﺤﺠﺮة )‪ (ij‬ﻣﻦ اﻟﻤﺼﻔﻮﻓﺔ ‪ M‬ﻧﻜﺘﺐ‪:‬‬
‫;‪M[i][j] = value‬‬

‫ﻣﺜﻠﻤﺎ ﻳﺘﻢ اﻟﻮﻟﻮج إﻟﻰ ﺣﻘﻮل أي ﺑﻨﻴﺔ‪ .‬ﻓﻴﻤﺎ‬ ‫‪M‬‬ ‫آﻤﺎ ﻳﻤﻜﻨﻨﺎ اﻹﺷﺎرة إﻟﻰ ﺣﺠﺮات اﻟﻤﺼﻔﻮﻓﺔ‬
‫ﻳﻠﻲ ﻧﺬآﺮ أﺳﻤﺎء اﻟﺤﺠﺮات اﻟﻤﻌﺮﻓﺔ‪:‬‬
‫ﺑﺪءًا ﻣﻦ اﻟﻮاﺣﺪ‪:‬‬ ‫‪R‬‬
‫;‪M._11 = M._12 = M._13 = M._14 = 0.0f‬‬
‫‪٣٤٥‬‬ ‫‪ :16‬ﻣﺪﺧﻞ إﻟﻰ ﻟﻐﺔ اﻟﺘﻈﻠﻴﻞ ﻋﺎﻟﻴﺔ اﻟﻤﺴﺘﻮى‬

‫;‪M._21 = M._22 = M._23 = M._24 = 0.0f‬‬


‫;‪M._31 = M._32 = M._33 = M._34 = 0.0f‬‬
‫;‪M._41 = M._42 = M._43 = M._44 = 0.0f‬‬

‫ﺑﺪءًا ﻣﻦ اﻟﺼﻔﺮ‪:‬‬ ‫‪R‬‬


‫‪M._m00‬‬ ‫=‬ ‫‪M._m01‬‬ ‫=‬ ‫‪M._m02‬‬ ‫=‬ ‫‪M._m03‬‬ ‫=‬ ‫;‪0.0f‬‬
‫‪M._m10‬‬ ‫=‬ ‫‪M._m11‬‬ ‫=‬ ‫‪M._m12‬‬ ‫=‬ ‫‪M._m13‬‬ ‫=‬ ‫;‪0.0f‬‬
‫‪M._m20‬‬ ‫=‬ ‫‪M._m21‬‬ ‫=‬ ‫‪M._m22‬‬ ‫=‬ ‫‪M._m23‬‬ ‫=‬ ‫;‪0.0f‬‬
‫‪M._m30‬‬ ‫=‬ ‫‪M._m31‬‬ ‫=‬ ‫‪M._m32‬‬ ‫=‬ ‫‪M._m33‬‬ ‫=‬ ‫;‪0.0f‬‬

‫ﻗﺪ ﻧﻮد اﻹﺷﺎرة إﻟﻰ ﺷﻌﺎع ﺳﻄﺮ ﻣﻌﻴﻦ ﻓﻲ ﻣﺼﻔﻮﻓﺔ‪ .‬ﻳﻤﻜﻨﻨﺎ ذﻟﻚ ﻣﻦ ﺧﻼل اﺳﺘﺨﺪام‬
‫اﻟﺼﻴﻐﺔ اﻟﺪﻟﻴﻠﻴﺔ اﻟﻤﻔﺮدة ﻟﻸﻧﺴﺎق‪ .‬ﻣﺜﻼً‪ ،‬ﻟﻺﺷﺎرة إﻟﻰ ﺷﻌﺎع اﻟﺴﻄﺮ )‪ (i‬ﻣﻦ اﻟﻤﺼﻔﻮﻓﺔ ‪M‬‬
‫ﻧﻜﺘﺐ‪:‬‬
‫;]‪vector ithRow = M[i‬‬

‫ﻳﻤﻜﻨﻨﺎ ﺗﻬﻴﺌﺔ اﻟﻤﺘﺤﻮﻻت ﺑﻠﻐﺔ ‪ HLSL‬ﻋﻦ ﻃﺮﻳﻖ اﻟﺼﻴﻐﺘﻴﻦ اﻟﺘﺎﻟﻴﺘﻴﻦ‪:‬‬


‫;}‪vector u = {0.6f, 0.3f, 1.0f, 1.0f‬‬
‫;}‪vector v = {1.0f, 5.0f, 0.2f, 1.0f‬‬

‫أو ﺑﺸﻜﻞ ﻣﻜﺎﻓﺊ ﻳﻤﻜﻨﻨﺎ اﺳﺘﺨﺪام ﺻﻴﻐﺔ اﻟﺒﺎﻧﻲ‪:‬‬


‫;)‪vector u = vector(0.6f, 0.3f, 1.0f, 1.0f‬‬
‫;)‪vector v = vector(1.0f, 5.0f, 0.2f, 1.0f‬‬

‫وﻓﻴﻤﺎ ﻳﻠﻲ أﻣﺜﻠﺔ أﺧﺮى‪:‬‬


‫;)‪float2x2 f2x2 = float2x2(1.0f, 2.0f, 3.0f, 4.0f‬‬
‫;}‪int2x2 m = {1, 2, 3, 4‬‬
‫;)‪int n = int(5‬‬
‫;}‪int a = {5‬‬
‫;)‪float3 x = float3(0, 0, 0‬‬
‫@@ @‬ ‫@@‬ ‫‪@Öbãþa@Z16.3.4‬‬

‫ﻼ‪:‬‬
‫ﻳﺘﻢ اﻟﺘﺼﺮﻳﺢ ﻋﻦ ﻧﺴﻖ ﻣﻦ ﻧﻮع ﻣﻌﻴﻦ ﺑﺎﺳﺘﺨﺪام ﺻﻴﻐﺔ ﻟﻐﺔ ‪ C++‬اﻟﻤﺄﻟﻮﻓﺔ‪ ،‬ﻣﺜ ً‬
‫;]‪float M[4][4‬‬
‫;]‪half p[4‬‬
‫;]‪vector v[12‬‬
‫اﻟﻤﻈﻠﻼت واﻟﺘﺄﺛﻴﺮات‬ ‫‪٣٤٦‬‬

‫@@ @‬ ‫@@‬ ‫‪@óäjÛa@Z16.3.5‬‬

‫أن‬ ‫‪HLSL‬‬ ‫ﻳﺘﻢ ﺗﻌﺮﻳﻒ اﻟﺒﻨﻰ ﺗﻤﺎﻣًﺎ آﻤﺎ ﺗﻌﺮف ﻓﻲ ﻟﻐﺔ ‪ .C++‬ﻟﻜﻦ ﻻ ﻳﻤﻜﻦ ﻟﻠﺒﻨﻰ ﻓﻲ ﻟﻐﺔ‬
‫ﺗﻤﺘﻠﻚ ﻣﻨﺎهﺞ‪ .‬ﻓﻴﻤﺎ ﻳﻠﻲ ﻣﺜﺎل ﻋﻦ ﺑﻨﻴﺔ ﺑﻠﻐﺔ ‪:HLSL‬‬
‫‪struct MyStruct‬‬
‫{‬
‫;‪matrix T‬‬
‫;‪vector n‬‬
‫;‪float f‬‬
‫;‪int x‬‬
‫;‪bool b‬‬
‫;}‬
‫;‪MyStruct s‬‬
‫;‪s.f = 5.0f‬‬

‫@@ @‬ ‫@@‬ ‫‪@typedef@ñŒìva@òàÜØÛa@Z16.3.6‬‬

‫إن وﻇﻴﻔﺔ اﻟﻜﻠﻤﺔ اﻟﻤﺤﺠﻮزة ‪ typedef‬ﻓﻲ ﻟﻐﺔ ‪ HLSL‬هﻲ ﻧﻔﺴﻬﺎ ﺗﻤﺎﻣًﺎ آﻤﺎ ﻓﻲ ﻟﻐﺔ ‪.C++‬‬
‫ﻼ ﻳﻤﻜﻨﻨﺎ إﻃﻼق اﺳﻢ ‪ point‬ﻋﻠﻰ اﻟﻨﻮع >‪ vector<float, 3‬ﺑﺎﺳﺘﺨﺪام اﻟﺼﻴﻐﺔ اﻟﺘﺎﻟﻴﺔ‪:‬‬
‫ﻣﺜ ً‬
‫;‪typedef vector<float, 3> point‬‬
‫ﻻ ﻣﻦ أن ﻧﻜﺘﺐ‪:‬‬
‫ﻋﻨﺪﺋﺬ ﺑﺪ ً‬
‫;‪vector<float, 3> myPoint‬‬
‫ﻳﻤﻜﻨﻨﺎ ﻓﻘﻂ أن ﻧﻜﺘﺐ‪:‬‬
‫;‪point myPoint‬‬

‫هﻨﺎ ﻣﺜﺎﻟﻴﻦ ﺁﺧﺮﻳﻦ ﻳﺒﻴﻨﺎن اﺳﺘﺨﺪام اﻟﻜﻠﻤﺔ اﻟﻤﺤﺠﻮزة ‪ typedef‬ﻟﺘﻌﺮﻳﻒ ﻧﻮع ﺛﺎﺑﺖ وﻧﺴﻖ‪:‬‬
‫;‪typedef const float CFLOAT‬‬
‫;]‪typedef float point2[2‬‬

‫@@ @‬ ‫‪@@ püìzn¾a@Õiaì@Z16.3.7‬‬

‫ﻳﻤﻜﻦ اﺳﺘﺨﺪام اﻟﻜﻠﻤﺎت اﻟﻤﺤﺠﻮزة اﻟﺘﺎﻟﻴﺔ آﺴﺎﺑﻘﺔ ﻋﻨﺪ اﻟﺘﺼﺮﻳﺢ ﻋﻦ ﻣﺘﺤﻮل‪:‬‬


‫‪ :static‬إذا آﺎن ﻣﺘﺤﻮل ﻣﺎ ﻣﺴﺒﻮﻗًﺎ ﺑﺎﻟﻜﻠﻤﺔ اﻟﻤﺤﺠﻮزة ‪ static‬ﻓﻬﺬا ﻳﻌﻨﻲ ﺑﺄﻧﻪ ﻟﻦ ﻳﻜﻮن‬ ‫‪R‬‬
‫ﻣﺮﺋﻴًﺎ ﺧﺎرج اﻟﻤﻈﻠﻞ‪ .‬ﺑﺘﻌﺒﻴﺮ ﺁﺧﺮ ﺳﻴﻜﻮن هﺬا اﻟﻤﺘﺤﻮل ﻣﺤﻠﻴًﺎ ﻓﻲ اﻟﻤﻈﻠﻞ‪.‬‬
‫أﻣﺎ إذا ﺗﻢ إﺳﺒﺎق ﻣﺘﺤﻮل ﻣﺤﻠﻲ ﺑﺎﻟﻜﻠﻤﺔ اﻟﻤﺤﺠﻮزة ‪ static‬ﻋﻨﺪهﺎ ﺳﻴﺴﻠﻚ ﻧﻔﺲ ﺳﻠﻮك‬
‫ﻣﺘﺤﻮل ﻣﺤﻠﻲ ‪ static‬ﻓﻲ ﻟﻐﺔ ‪ .C++‬أي ﻳﺘﻢ ﺗﻬﻴﺌﺘﻪ ﻣﺮة واﺣﺪة ﻋﻨﺪﻣﺎ ﻳﺘﻢ ﺗﻨﻔﻴﺬ اﻟﺘﺎﺑﻊ‬
‫‪٣٤٧‬‬ ‫‪ :16‬ﻣﺪﺧﻞ إﻟﻰ ﻟﻐﺔ اﻟﺘﻈﻠﻴﻞ ﻋﺎﻟﻴﺔ اﻟﻤﺴﺘﻮى‬

‫وﻳﺒﻘﻰ ﻣﺤﺎﻓﻈًﺎ ﻋﻠﻰ ﻗﻴﻤﺘﻪ ﺧﻼل آﺎﻓﺔ اﺳﺘﺪﻋﺎءات هﺬا اﻟﺘﺎﺑﻊ‪ .‬إذا ﻟﻢ ﺗﺘﻢ ﺗﻬﻴﺌﺔ‬
‫اﻟﻤﺘﺤﻮل ﻋﻨﺪهﺎ ﺗﺘﻢ ﺗﻬﻴﺌﺘﻪ ﺁﻟﻴًﺎ ﺑﺎﻟﻘﻴﻤﺔ ‪.0‬‬
‫;‪static int x = 5‬‬

‫‪ :uniform‬إذا آﺎن ﻣﺘﺤﻮل ﻣﺎ ﻣﺴﺒﻮﻗًﺎ ﺑﺎﻟﻜﻠﻤﺔ اﻟﻤﺤﺠﻮزة ‪ uniform‬ﻓﻬﺬا ﻳﻌﻨﻲ أن‬ ‫‪R‬‬
‫ﻼ ﻣﻦ ﻗﺒﻞ ﺗﻄﺒﻴﻖ ﻣﻜﺘﻮب ﺑﻠﻐﺔ ‪ .(C++‬وﻳﺴﺘﺨﺪم‬ ‫اﻟﻤﺘﺤﻮل ﺳﻴﻬﻴﺄ ﺧﺎرج اﻟﻤﻈﻠﻞ )ﻣﺜ ً‬
‫داﺧﻞ اﻟﻤﻈﻠﻞ‪.‬‬
‫‪ :extern‬إذا آﺎن ﻣﺘﺤﻮل ﻣﺎ ﻣﺴﺒﻮﻗًﺎ ﺑﺎﻟﻜﻠﻤﺔ اﻟﻤﺤﺠﻮزة ‪ extern‬ﻓﻬﺬا ﻳﻌﻨﻲ أﻧﻪ ﻳﻤﻜﻦ‬ ‫‪R‬‬
‫اﻟﻮﻟﻮج إﻟﻰ اﻟﻤﺘﺤﻮل ﻣﻦ ﺧﺎرج اﻟﻤﻈﻠﻞ )ﻣﻦ ﻗﺒﻞ ﺗﻄﺒﻴﻖ ﻣﻜﺘﻮب ﺑﻠﻐﺔ ‪ C++‬ﻣﺜ ً‬
‫ﻼ(‪.‬‬
‫اﻟﻤﺘﺤﻮﻻت اﻟﻌﺎﻣﺔ ﻓﻘﻂ ﻳﻤﻜﻦ أن ﺗﻜﻮن ﻣﺴﺒﻮﻗﺔ ﺑﺎﻟﻜﻠﻤﺔ اﻟﻤﺤﺠﻮزة ‪ .extern‬آﻤﺎ أن‬
‫اﻟﻤﺘﺤﻮﻻت اﻟﻌﺎﻣﺔ اﻟﺘﻲ هﻲ ﻟﻴﺴﺖ ‪ static‬ﺗﻜﻮن ‪ extern‬اﻓﺘﺮاﺿﻴًﺎ‪.‬‬
‫‪ :shared‬إذا آﺎن ﻣﺘﺤﻮل ﻣﺎ ﻣﺴﺒﻮﻗًﺎ ﺑﺎﻟﻜﻠﻤﺔ اﻟﻤﺤﺠﻮزة ‪ shared‬ﻓﻬﺬا ﻳﺸﻴﺮ ﻹﻃﺎر ﻋﻤﻞ‬ ‫‪R‬‬
‫اﻟﺘﺄﺛﻴﺮات إﻟﻰ أن اﻟﻤﺘﺤﻮل ﺳﻴﻜﻮن ﻣﺸﺘﺮآًﺎ ﺑﻴﻦ ﻋﺪة ﺗﺄﺛﻴﺮات‪ .‬اﻟﻤﺘﺤﻮﻻت اﻟﻌﺎﻣﺔ ﻓﻘﻂ‬
‫ﻳﻤﻜﻦ أن ﺗﻜﻮن ﻣﺴﺒﻮﻗﺔ ﺑﺎﻟﻜﻠﻤﺔ اﻟﻤﺤﺠﻮزة ‪.shared‬‬
‫‪ :volatile‬إذا آﺎن ﻣﺘﺤﻮل ﻣﺎ ﻣﺴﺒﻮﻗًﺎ ﺑﺎﻟﻜﻠﻤﺔ اﻟﻤﺤﺠﻮزة ‪ volatile‬ﻓﻬﺬا ﻳﺸﻴﺮ ﻹﻃﺎر‬ ‫‪R‬‬
‫ﻋﻤﻞ اﻟﺘﺄﺛﻴﺮات إﻟﻰ أن هﺬا اﻟﻤﺘﺤﻮل ﺳﺘﺘﻐﻴﺮ ﻗﻴﻤﺘﻪ آﺜﻴﺮًا‪ .‬اﻟﻤﺘﺤﻮﻻت اﻟﻌﺎﻣﺔ ﻓﻘﻂ‬
‫ﻳﻤﻜﻦ أن ﺗﻜﻮن ﻣﺴﺒﻮﻗﺔ ﺑﺎﻟﻜﻠﻤﺔ اﻟﻤﺤﺠﻮزة ‪.volatile‬‬
‫‪ :const‬إن ﻟﻠﻜﻠﻤﺔ اﻟﻤﺤﺠﻮزة ‪ const‬ﻓﻲ ﻟﻐﺔ ‪ HLSL‬ﻧﻔﺲ اﻟﻤﻌﻨﻰ ﻓﻲ ﻟﻐﺔ ‪ .C++‬أي إذا‬ ‫‪R‬‬
‫آﺎن ﻣﺘﺤﻮل ﻣﺎ ﻣﺴﺒﻮﻗًﺎ ﺑﺎﻟﻜﻠﻤﺔ اﻟﻤﺤﺠﻮزة ‪ const‬ﻋﻨﺪﺋﺬ ﺳﻴﺒﻘﻰ اﻟﻤﺘﺤﻮل ﺛﺎﺑﺘًﺎ ﻻ ﻳﻤﻜﻦ‬
‫ﺗﻐﻴﻴﺮ ﻗﻴﻤﺘﻪ‪.‬‬
‫;‪const float pi = 3.14f‬‬
‫@@ @‬ ‫‪@@@Êaìãþa@kÜÓë@paŠbjÈÛaë@ñŒìva@pbàÜØÛa@Z16.4‬‬
‫‪@ @ñŒìva@pbàÜØÛa@Z16.4.1‬‬

‫ﻓﻴﻤﺎ ﻳﻠﻲ ﻧﻮرد اﻟﻜﻠﻤﺎت اﻟﻤﺤﺠﻮزة اﻟﻤﻌﺮﻓﺔ ﻓﻲ ﻟﻐﺔ ‪:HLSL‬‬


‫‪asm‬‬ ‫‪bool‬‬ ‫‪compile‬‬ ‫‪const‬‬ ‫‪decl‬‬ ‫‪do‬‬
‫‪double‬‬ ‫‪else‬‬ ‫‪extern‬‬ ‫‪false‬‬ ‫‪float‬‬ ‫‪for‬‬
‫‪half‬‬ ‫‪if‬‬ ‫‪in‬‬ ‫‪inline‬‬ ‫‪inout‬‬ ‫‪int‬‬
‫اﻟﻤﻈﻠﻼت واﻟﺘﺄﺛﻴﺮات‬ ٣٤٨

matrix out pass pixelshader return sampler


shared static string struct technique texture
true typedef uniform vector vertexshader void
volatile while
‫ﻓﻴﻤﺎ ﻳﻠﻲ ﻧﻮرد اﻟﻤﻌﺮﻓﺎت اﻟﻤﺤﺠﻮزة وﻟﻜﻦ ﻏﻴﺮ اﻟﻤﺴﺘﺨﺪﻣﺔ واﻟﺘﻲ ﻗﺪ ﺗﺼﺒﺢ آﻠﻤﺎت‬
:‫ﻼ‬
ً ‫ﻣﺤﺠﻮزة ﻣﺴﺘﻘﺒ‬
auto break case catch char class
const_cast continue default delete dynamic_cast enum
explicit friend goto long mutable namespace
new operator private protected public register
reinterpret_cast short signed sizeof static_cast switch
template this throw try typename union
unsigned using virtual

@ @@ @@ @wßbãÛa@lbîãa@Z16.4.2
‫ اﻟﻤﺄﻟﻮﻓﺔ ﻣﻦ أﺟﻞ اﻻﺧﺘﻴﺎر واﻟﺘﻜﺮار‬C++ ‫ اﻟﻌﺪﻳﺪ ﻣﻦ ﻋﺒﺎرات ﻟﻐﺔ‬HLSL ‫ﺗﻮﻓﺮ ﻟﻐﺔ‬
‫ إن ﺻﻴﻎ هﺬﻩ اﻟﻌﺒﺎرات ﻣﺸﺎﺑﻬﺔ ﺗﻤﺎﻣًﺎ ﻟﻤﺜﻴﻼﺗﻬﺎ ﻓﻲ ﻟﻐﺔ‬.‫واﻧﺴﻴﺎب اﻟﺒﺮﻧﺎﻣﺞ ﺑﺸﻜﻞ ﻋﺎم‬
:C++
:Return ‫ﻋﺒﺎرة‬ R
return (expression);
:If...Else‫ و‬If ‫ﻋﺒﺎرﺗﺎ‬ R
if( condition )
{
statement(s);
}

if( condition )
{
statement(s);
}
else
{
statement(s);
}
:for ‫ﻋﺒﺎرة‬ R
for(initial; condition; increment)
{
‫‪٣٤٩‬‬ ‫‪ :16‬ﻣﺪﺧﻞ إﻟﻰ ﻟﻐﺔ اﻟﺘﻈﻠﻴﻞ ﻋﺎﻟﻴﺔ اﻟﻤﺴﺘﻮى‬

‫;)‪statement(s‬‬
‫}‬
‫ﻋﺒﺎرة ‪:while‬‬ ‫‪R‬‬
‫) ‪while( condition‬‬
‫{‬
‫;)‪statement(s‬‬
‫}‬
‫ﻋﺒﺎرة ‪:do...while‬‬ ‫‪R‬‬
‫‪do‬‬
‫{‬
‫;)‪statement(s‬‬
‫;) ‪} while ( condition‬‬

‫‪@ @@Êaìãþa@kÜÓ@Z16.4.3‬‬
‫هﻲ ﻧﻔﺴﻬﺎ‬ ‫‪HLSL‬‬ ‫ﺗﻮﻓﺮ ﻟﻐﺔ ‪ HLSL‬ﻧﻤﻮذﺟًﺎ ﻣﺮﻧًﺎ ﻟﻘﻠﺐ اﻷﻧﻮاع‪ .‬ﺻﻴﻐﺔ ﻗﻠﺐ اﻷﻧﻮاع ﻓﻲ ﻟﻐﺔ‬
‫ﻓﻲ ﻟﻐﺔ ‪ .C‬ﻟﻘﻠﺐ ﻧﻮع ‪ float‬إﻟﻰ ‪ matrix‬ﻧﻜﺘﺐ‪:‬‬
‫;‪float f = 5.0f‬‬
‫;‪matrix m = (matrix)f‬‬

‫ﻳﻤﻜﻨﻚ اﺳﺘﺨﻼص ﻣﻌﻨﻰ ﻗﻠﺐ اﻟﻨﻮع ﻓﻲ أﻣﺜﻠﺔ هﺬا اﻟﻜﺘﺎب ﻣﻦ ﺧﻼل اﻟﺴﻴﺎق‪ .‬أﻣﺎ إذا أردت‬
‫اﻟﺤﺼﻮل ﻋﻠﻰ ﻣﻌﻠﻮﻣﺎت ﻣﻔﺼﻠﺔ ﻋﻦ ﻃﺮق ﻗﻠﺐ اﻷﻧﻮاع اﻟﻤﺘﻮﻓﺮة ﻓﻴﻤﻜﻨﻚ أن ﺗﺮاهﺎ ﻓﻲ‬
‫وﺛﺎﺋﻖ ﻣﺠﻤﻮﻋﺔ ﺗﻄﻮﻳﺮ ‪ DirectX‬ﺗﺤﺖ اﻟﺒﻨﺪ ‪ Contents‬ﻓﻲ‪:‬‬
‫‪DirectX Graphics\References\Shader Reference\High Level Shading‬‬
‫‪Language\Type.‬‬

‫@@ @‬ ‫‪@@ @pbîÜàÈÛa@Z16.5‬‬


‫ﺗﻮﻓﺮ ﻟﻐﺔ ‪ HLSL‬اﻟﻌﺪﻳﺪ ﻣﻦ اﻟﻌﻤﻠﻴﺎت اﻟﻤﺄﻟﻮﻓﺔ ﻓﻲ ﻟﻐﺔ ‪ .C++‬ﺗﺴﺘﺨﺪم هﺬﻩ اﻟﻌﻤﻠﻴﺎت ﺗﻤﺎﻣًﺎ آﻤﺎ‬
‫ﺗﺴﺘﺨﺪم ﻓﻲ ﻟﻐﺔ ‪ C++‬إﻻ ﻓﻲ ﺑﻌﺾ اﻻﺳﺘﺜﻨﺎءات اﻟﻤﺬآﻮرة أدﻧﺎﻩ‪ .‬ﻓﻴﻤﺎ ﻳﻠﻲ ﻻﺋﺤﺔ ﺑﺎﻟﻌﻤﻠﻴﺎت ﻓﻲ‬
‫‪:HLSL‬‬
‫][‬ ‫‪.‬‬ ‫>‬ ‫<‬ ‫=<‬ ‫=>‬
‫=!‬ ‫==‬ ‫!‬ ‫&&‬ ‫||‬ ‫‪?:‬‬
‫‪+‬‬ ‫=‪+‬‬ ‫‪-‬‬ ‫=‪-‬‬ ‫*‬ ‫=*‬
‫‪/‬‬ ‫=‪/‬‬ ‫‪%‬‬ ‫=‪%‬‬ ‫‪++‬‬ ‫‪--‬‬
‫=‬ ‫)(‬ ‫‪,‬‬

‫إﻻ أﻧﻪ ﺗﻮﺟﺪ ﺑﻌﺾ‬ ‫‪C++‬‬ ‫ﺑﺎﻟﺮﻏﻢ ﻣﻦ أن ﺳﻠﻮك اﻟﻌﻤﻠﻴﺎت ﻳﺸﺒﻪ آﺜﻴﺮًا ﺳﻠﻮآﻬﺎ ﻓﻲ ﻟﻐﺔ‬
‫اﻟﻤﻈﻠﻼت واﻟﺘﺄﺛﻴﺮات‬ ‫‪٣٥٠‬‬

‫ﻻ ﺗﺴﺘﺨﺪم اﻟﻌﻤﻠﻴﺔ ‪ %‬ﻣﻊ اﻷﻋﺪاد اﻟﺼﺤﻴﺤﺔ وذات اﻟﻔﺎﺻﻠﺔ اﻟﻌﺎﺋﻤﺔ‪ .‬آﻤﺎ ﻳﺠﺐ‬
‫اﻟﻔﺮوق‪ .‬أو ً‬
‫أن ﺗﻜﻮن اﻟﻘﻴﻤﺘﺎن ﻋﻠﻰ ﻳﺴﺎر وﻳﻤﻴﻦ اﻟﻌﻤﻠﻴﺔ ﻣﻦ ﻧﻔﺲ اﻹﺷﺎرة )أي ﻳﺠﺐ أن ﻳﻜﻮن آﻼ‬
‫اﻟﻄﺮﻓﻴﻦ ﻣﻮﺟﺒﻴﻦ أو ﺳﺎﻟﺒﻴﻦ(‪.‬‬
‫ﺛﺎﻧﻴﺎً‪ ،‬اﻧﺘﺒﻪ إﻟﻰ أن اﻟﻌﺪﻳﺪ ﻣﻦ اﻟﻌﻤﻠﻴﺎت ﻓﻲ ‪ HLSL‬ﺗﻌﻤﻞ ﻋﻠﻰ أﺳﺎس آﻞ ﻣﺮآﺒﺔ ﻋﻠﻰ ﺣﺪة‪.‬‬
‫هﺬا ﻧﺎﺗﺞ ﻋﻦ آﻮن اﻟﻌﻤﻠﻴﺎت ﺗﺘﻢ ﻋﻠﻰ ﻣﺴﺘﻮى اﻟﻤﺮآﺒﺎت ﻟﺬا ﻳﻤﻜﻦ إﺟﺮاء ﻋﻤﻠﻴﺎت ﺟﻤﻊ‬
‫اﻷﺷﻌﺔ واﻟﻤﺼﻔﻮﻓﺎت وﻃﺮح اﻷﺷﻌﺔ واﻟﻤﺼﻔﻮﻓﺎت واﺧﺘﺒﺎرات ﺗﺴﺎوي اﻷﺷﻌﺔ‬
‫واﻟﻤﺼﻔﻮﻓﺎت ﺑﺎﺳﺘﺨﺪام ﻧﻔﺲ اﻟﻌﻤﻠﻴﺎت اﻟﻤﺴﺘﻌﻤﻠﺔ ﻣﻊ اﻷﻧﻮاع اﻟﺴﻠﻤﻴﺔ‪ .‬اﻧﻈﺮ إﻟﻰ اﻷﻣﺜﻠﺔ‬
‫اﻟﺘﺎﻟﻴﺔ‪:‬‬
‫;}‪vector u = {1.0f, 0.0f, -3.0f, 1.0f‬‬
‫;}‪vector v = {-4.0f, 2.0f, 1.0f, 0.0f‬‬

‫)‪vector sum = u + v; // sum = (-3.0f, 2.0f, -2.0f, 1.0f‬‬

‫زﻳﺎدة ﺷﻌﺎع ﻣﻦ ﺧﻼل اﻟﻌﻤﻠﻴﺔ ‪ ++‬ﺗﺰﻳﺪ ﻗﻴﻤﺔ آﻞ ﻣﺮآﺒﺔ‪:‬‬


‫)‪// before increment: sum = (-3.0f, 2.0f, -2.0f, 1.0f‬‬
‫)‪sum++; // after increment: sum = (-2.0f, 3.0f, -1.0f, 2.0f‬‬

‫ﺿﺮب اﻟﻤﺮآﺒﺎت‪:‬‬
‫;}‪vector u = {1.0f, 0.0f, -3.0f, 1.0f‬‬
‫;}‪vector v = {-4.0f, 2.0f, 1.0f, 0.0f‬‬

‫)‪vector product = u * v; // product = (-4.0f, 0.0f, -3.0f, 0.0f‬‬

‫ﺗﺘﻢ اﻟﻤﻘﺎرﻧﺔ ﺑﺘﻄﺒﻴﻖ ﻋﻤﻠﻴﺎت اﻟﻤﻘﺎرﻧﺔ ﻋﻠﻰ آﻞ ﻣﺮآﺒﺔ ﻋﻠﻰ ﺣﺪة‪ ،‬وﺗﻌﻴﺪ ﺷﻌﺎﻋًﺎ )أو‬
‫ﻣﺼﻔﻮﻓﺔ( آﻞ ﻣﺮآﺒﺔ ﻓﻴﻪ ﻣﻦ اﻟﻨﻮع ‪ .bool‬ﺣﻴﺚ ﻳﺤﺘﻮي اﻟﺸﻌﺎع اﻟﺒﻮﻟﻴﺎﻧﻲ اﻟﻨﺎﺗﺞ ﻋﻠﻰ ﻧﺘﺎﺋﺞ‬
‫ﻼ‪:‬‬
‫ﻣﻘﺎرﻧﺔ آﻞ ﻣﺮآﺒﺔ ﻋﻠﻰ ﺣﺪة‪ .‬ﻣﺜ ً‬
‫;}‪vector u = {1.0f, 0.0f, -3.0f, 1.0f‬‬
‫;}‪vector v = {-4.0f, 0.0f, 1.0f, 1.0f‬‬

‫)‪vector b = (u == v); // b = (false, true, false, true‬‬

‫أﺧﻴﺮاً‪ ،‬ﺳﻨﺨﺘﺘﻢ ﺣﺪﻳﺜﻨﺎ ﺑﺪراﺳﺔ ﺗﺮﻗﻴﺔ اﻟﻤﺘﺤﻮل ﻓﻲ اﻟﻌﻤﻠﻴﺎت اﻟﺜﻨﺎﺋﻴﺔ )ذات اﻟﺤﺪﻳﻦ(‪:‬‬
‫ﺑﺎﻟﻨﺴﺒﺔ إﻟﻰ اﻟﻌﻤﻠﻴﺎت اﻟﺜﻨﺎﺋﻴﺔ إذا آﺎن اﻟﻄﺮف اﻷﻳﺴﺮ ﻳﺨﺘﻠﻒ ﻋﻦ اﻟﻄﺮف اﻷﻳﻤﻦ ﻓﻲ‬ ‫‪R‬‬
‫اﻷﺑﻌﺎد ﻋﻨﺪﺋﺬ ﺗﺘﻢ ﺗﺮﻗﻴﺔ اﻟﻄﺮف ذو اﻷﺑﻌﺎد اﻷﺻﻐﺮ )ﻳﺘﻢ ﻗﻠﺐ ﻧﻮﻋﻪ( ﻟﻴﺼﻴﺮ ﺑﻨﻔﺲ‬
‫‪٣٥١‬‬ ‫‪ :16‬ﻣﺪﺧﻞ إﻟﻰ ﻟﻐﺔ اﻟﺘﻈﻠﻴﻞ ﻋﺎﻟﻴﺔ اﻟﻤﺴﺘﻮى‬

‫‪float3‬‬ ‫ﻼ‪ :‬إذا آﺎن ‪ x‬ﻣﻦ اﻟﻨﻮع ‪ float‬و‪ y‬ﻣﻦ اﻟﻨﻮع‬‫أﺑﻌﺎد اﻟﻄﺮف ذو اﻷﺑﻌﺎد اﻷآﺒﺮ‪ .‬ﻣﺜ ً‬
‫ﻋﻨﺪهﺎ ﺗﺘﻢ ﺗﺮﻗﻴﺔ ‪ x‬ﻓﻲ اﻟﺘﻌﺒﻴﺮ )‪ (x+y‬إﻟﻰ اﻟﻨﻮع ‪ float3‬واﻟﺘﻌﺒﻴﺮ ﺳﻴﻌﻄﻲ ﻗﻴﻤﺔ ﻣﻦ‬
‫اﻟﻨﻮع ‪ .float3‬ﻳﺘﻢ إﻧﺠﺎز اﻟﺘﺮﻗﻴﺔ ﻋﻦ ﻃﺮﻳﻖ ﻗﻠﺐ اﻟﻨﻮع اﻟﻤﻌﺮف‪ .‬ﻓﻔﻲ هﺬﻩ اﻟﺤﺎﻟﺔ ﻧﻘﻮم‬
‫ﺑﻘﻠﺐ ﻧﻮع ﺳﻠﻤﻲ إﻟﻰ ﺷﻌﺎع‪ ،‬ﻟﺬﻟﻚ ﺑﻌﺪ أن ﺗﺘﻢ ﺗﺮﻗﻴﺔ ‪ x‬إﻟﻰ ‪ float3‬ﻳﻜﻮن )‪x = (x, x, x‬‬
‫ﺣﺴﺐ ﺗﻌﺮﻳﻒ ﻗﻠﺐ اﻟﻨﻮع اﻟﺴﻠﻤﻲ إﻟﻰ ﺷﻌﺎع‪ .‬ﻻﺣﻆ أن اﻟﺘﺮﻗﻴﺔ ﺗﻜﻮن ﻏﻴﺮ ﻣﻌﺮﻓﺔ إذا‬
‫ﻟﻢ ﻳﻜﻦ ﻗﻠﺐ اﻟﻨﻮع ﻣﻌﺮﻓًﺎ‪ .‬ﻣﺜﻼً‪ ،‬ﻻ ﻳﻤﻜﻦ ﺗﺮﻗﻴﺔ ‪ float2‬إﻟﻰ ‪ float3‬ﻷﻧﻪ ﻻ ﻳﻮﺟﺪ ﻗﻠﺐ‬
‫أﻧﻮاع ﻣﻌﺮف آﻬﺬا‪.‬‬
‫ﺑﺎﻟﻨﺴﺒﺔ إﻟﻰ اﻟﻌﻤﻠﻴﺎت اﻟﺜﻨﺎﺋﻴﺔ‪ ،‬إذا آﺎن اﻟﻄﺮف اﻷﻳﺴﺮ ﻳﺨﺘﻠﻒ ﻋﻦ اﻟﻄﺮف اﻷﻳﻤﻦ ﻓﻲ‬ ‫‪R‬‬
‫اﻟﻨﻮع‪ ،‬ﻋﻨﺪﺋﺬ ﺗﺘﻢ ﺗﺮﻗﻴﺔ )ﻗﻠﺐ ﻧﻮع( اﻟﻄﺮف ذو اﻟﻨﻮع اﻷﻗﻞ دﻗﺔ ﻟﻴﺼﻴﺮ ﻧﻔﺲ ﻧﻮع‬
‫اﻟﻄﺮف ذو اﻟﻨﻮع اﻷآﺒﺮ دﻗﺔ‪ .‬ﻣﺜﻼً‪ ،‬إذا آﺎن ‪ x‬ﻣﻦ اﻟﻨﻮع ‪ int‬و‪ y‬ﻣﻦ اﻟﻨﻮع ‪ ،half‬ﻓﺘﺘﻢ‬
‫ﺗﺮﻗﻴﺔ اﻟﻤﺘﺤﻮل ‪ x‬ﺿﻤﻦ اﻟﺘﻌﺒﻴﺮ )‪ (x+y‬إﻟﻰ اﻟﻨﻮع ‪ half‬وﺗﻜﻮن ﻗﻴﻤﺔ اﻟﺘﻌﺒﻴﺮ اﻟﻨﺎﺗﺠﺔ‬
‫ﻣﻦ اﻟﻨﻮع ‪.half‬‬

‫@@ @‬ ‫‪@⇃n¾a@ÝjÓ@åß@òϋȾa@ÉiaìnÛa@Z16.6‬‬
‫إن ﻟﻠﺘﻮاﺑﻊ ﻓﻲ ﻟﻐﺔ ‪ HLSL‬اﻟﺨﺼﺎﺋﺺ اﻟﺘﺎﻟﻴﺔ‪:‬‬
‫ﺗﺴﺘﺨﺪم اﻟﺘﻮاﺑﻊ ﺻﻴﻐﺔ ‪ C++‬اﻟﻤﺄﻟﻮﻓﺔ‪.‬‬ ‫‪R‬‬

‫ﻳﺘﻢ ﺗﻤﺮﻳﺮ اﻟﻮﺳﻄﺎء ﻋﻦ ﻃﺮﻳﻖ اﻟﻘﻴﻤﺔ )‪ (by value‬ﻓﻘﻂ‪.‬‬ ‫‪R‬‬

‫اﻟﺘﻌﺎودﻳﺔ ﻏﻴﺮ ﻣﺴﻤﻮﺣﺔ‪.‬‬ ‫‪R‬‬

‫ﺗﺴﺘﺨﺪم اﻟﺘﻮاﺑﻊ داﺋﻤًﺎ ﺑﺸﻜﻞ ‪.inline‬‬ ‫‪R‬‬

‫وﻓﻮق آﻞ ذﻟﻚ ﺗﻀﻴﻒ ﻟﻐﺔ ‪ HLSL‬ﺑﻌﺾ اﻟﻜﻠﻤﺎت اﻟﻤﺤﺠﻮزة اﻹﺿﺎﻓﻴﺔ اﻟﺘﻲ ﺗﺴﺘﺨﺪم ﻣﻊ‬
‫اﻟﺘﻮاﺑﻊ‪ .‬ﻋﻠﻰ ﺳﺒﻴﻞ اﻟﻤﺜﺎل‪ ،‬ﺗﺄﻣﻞ اﻟﺘﺎﺑﻊ اﻟﺘﺎﻟﻲ اﻟﻤﻜﺘﻮب ﺑﻠﻐﺔ ‪:HLSL‬‬
‫‪bool foo(in const bool b,‬‬ ‫‪// input bool‬‬
‫‪out int r1,‬‬ ‫‪// output int‬‬
‫)‪inout float r2‬‬ ‫‪// input/output float‬‬
‫{‬
‫) ‪if( b‬‬ ‫‪// test input value‬‬
‫{‬
‫;‪r1 = 5‬‬ ‫‪// output a value through r1‬‬
‫}‬
‫‪else‬‬
‫{‬
‫اﻟﻤﻈﻠﻼت واﻟﺘﺄﺛﻴﺮات‬ ‫‪٣٥٢‬‬

‫;‪r1 = 1‬‬ ‫‪// output another value through r1‬‬


‫}‬

‫‪// since r2 is inout we can use it as an input value‬‬


‫‪// and also output a value through it‬‬
‫;‪r2 = r2 * r2 * r2‬‬

‫;‪return true‬‬
‫}‬

‫‪in‬‬ ‫ﻓﻴﻤﺎ ﻋﺪا وﺟﻮد اﻟﻜﻠﻤﺎت اﻟﻤﺤﺠﻮزة‬ ‫‪C++‬‬ ‫إن هﺬا اﻟﺘﺎﺑﻊ ﻣﻤﺎﺛﻞ ﺗﻘﺮﻳﺒًﺎ ﻷي ﺗﺎﺑﻊ ﺑﻠﻐﺔ‬
‫و‪out‬‬
‫و‪.inout‬‬
‫‪ :in‬ﻳﻌﻨﻲ أﻧﻪ ﺳﺘﻨﺴﺦ ﻗﻴﻤﺔ اﻟﻮﺳﻴﻂ اﻟﻔﻌﻠﻲ إﻟﻰ اﻟﻮﺳﻴﻂ اﻟﺸﻜﻠﻲ ﻗﺒﻞ ﺑﺪء ﺗﻨﻔﻴﺬ اﻟﺘﺎﺑﻊ‪.‬‬ ‫‪R‬‬
‫ﻟﻴﺲ ﻣﻦ اﻟﻀﺮوري ذآﺮ ‪ in‬ﻗﺒﻞ اﺳﻢ اﻟﻮﺳﻴﻂ ﺻﺮاﺣﺔ ﻷن اﻟﻮﺳﻴﻂ هﻮ ‪ in‬اﻓﺘﺮاﺿﻴًﺎ‪.‬‬
‫ﻣﺜﻼً‪ ،‬إن آﻼ اﻟﺘﺎﺑﻌﻴﻦ اﻟﺘﺎﻟﻴﻴﻦ ﻣﺘﻜﺎﻓﺌﻴﻦ‪:‬‬
‫)‪float square(in float x‬‬
‫{‬
‫;‪return x * x‬‬
‫}‬

‫)ﺑﺪون ذآﺮ ‪ in‬ﺑﺸﻜﻞ ﺻﺮﻳﺢ(‪:‬‬


‫)‪float square(float x‬‬
‫{‬
‫;‪return x * x‬‬
‫}‬

‫‪ :out‬ﻳﻌﻨﻲ أﻧﻪ ﺳﻴُﻨﺴﺦ اﻟﻮﺳﻴﻂ اﻟﺸﻜﻠﻲ إﻟﻰ اﻟﻮﺳﻴﻂ اﻟﻔﻌﻠﻲ ﻋﻨﺪﻣﺎ ﻳﻌﻮد اﻟﺘﺎﺑﻊ‪ .‬ﻳﻔﻴﺪﻧﺎ‬ ‫‪R‬‬
‫هﺬا اﻷﻣﺮ ﻣﻦ أﺟﻞ إﻋﺎدة اﻟﻘﻴﻢ ﻣﻦ ﺧﻼل اﻟﻮﺳﻄﺎء‪ .‬إن اﻟﻜﻠﻤﺔ اﻟﻤﺤﺠﻮزة ‪out‬‬
‫ﺿﺮورﻳﺔ ﻷن ﻟﻐﺔ ‪ HLSL‬ﻻ ﺗﺴﻤﺢ ﺑﺘﻤﺮﻳﺮ اﻟﻮﺳﻄﺎء ﻣﺮﺟﻌﻴًﺎ آﻤﺎ ﻻ ﺗﺴﻤﺢ ﺑﺘﻤﺮﻳﺮ‬
‫اﻟﻤﺆﺷﺮات‪ .‬ﻧﻼﺣﻆ أﻧﻪ ﻟﻤﺎ ﻳﻜﻮن اﻟﻮﺳﻴﻂ اﻟﻤﺤﺪد ﻋﻠﻰ أﻧﻪ ‪ ،out‬ﻻ ﻳُﻨﺴﺦ اﻟﻮﺳﻴﻂ‬
‫اﻟﻔﻌﻠﻲ إﻟﻰ اﻟﻮﺳﻴﻂ اﻟﺸﻜﻠﻲ ﻗﺒﻞ ﺑﺪء اﻟﺘﺎﺑﻊ‪ ،‬وﺑﺎﻟﺘﺎﻟﻲ ﻻ ﻳﻤﻜﻨﻨﺎ اﻓﺘﺮاض وﺟﻮد ﻗﻴﻤﺔ‬
‫أوﻟﻴﺔ ﻓﻴﻪ ذات ﻣﻌﻨﻰ ﻗﺒﻞ أن ﻧﻘﻮم ﺑﺈﺳﻨﺎد ﻗﻴﻤﺔ ﻣﺎ إﻟﻴﻪ‪ .‬ﺑﻜﻼم ﺁﺧﺮ‪ :‬ﻳﺴﺘﺨﺪم وﺳﻴﻂ ذو‬
‫‪ out‬ﻓﻘﻂ ﻣﻦ أﺟﻞ إﺧﺮاج اﻟﻤﻌﻄﻴﺎت وﻻ ﻳﺴﺘﺨﺪم أﺑﺪًا آﺪﺧﻞ‪.‬‬
‫)‪void square(in float x, out float y‬‬
‫{‬
‫;‪y = x * x‬‬
‫}‬

‫وﻧﺄﺧﺬ اﻟﻘﻴﻤﺔ اﻟﻤﻌﺎدة )ﻣﺮﺑﻊ‬ ‫‪x‬‬ ‫هﻨﺎ ﻧﺪﺧﻞ اﻟﻌﺪد اﻟﺬي ﻧﺮﻳﺪ ﺗﺮﺑﻴﻌﻪ ﻣﻦ ﺧﻼل اﻟﻮﺳﻴﻂ‬
‫‪ (x‬ﻣﻦ ﺧﻼل اﻟﻮﺳﻴﻂ ‪.y‬‬
‫‪٣٥٣‬‬ ‫‪ :16‬ﻣﺪﺧﻞ إﻟﻰ ﻟﻐﺔ اﻟﺘﻈﻠﻴﻞ ﻋﺎﻟﻴﺔ اﻟﻤﺴﺘﻮى‬

‫إذا أردت أن‬ ‫‪inout‬‬ ‫ﻓﻲ ﻧﻔﺲ اﻟﻮﻗﺖ‪ .‬اﺳﺘﻌﻤﻞ‬ ‫‪ in‬و‪out‬‬ ‫‪ :inout‬ﻳﻌﻨﻲ ﺑﺄن اﻟﻮﺳﻴﻂ هﻮ‬ ‫‪R‬‬
‫ﺗﺴﺘﺨﺪم وﺳﻴﻄًﺎ ﻣﺎ آﺪﺧﻞ وﺧﺮج ﻣﻌًﺎ‪.‬‬
‫)‪void square(inout float x‬‬
‫{‬
‫;‪x = x * x‬‬
‫}‬

‫هﻨﺎ ﻧﺪﺧﻞ اﻟﻌﺪد اﻟﺬي ﻧﺮﻳﺪ ﺗﺮﺑﻴﻌﻪ ﻣﻦ ﺧﻼل اﻟﻮﺳﻴﻂ ‪ ،x‬وﻧﺤﺼﻞ ﻋﻠﻰ اﻟﻨﺘﻴﺠﺔ أﻳﻀًﺎ ﻣﻦ‬
‫ﺧﻼل اﻟﻮﺳﻴﻂ ‪.x‬‬

‫@@ @‬ ‫‪@òîäà›Ûa@ÉiaìnÛa@Z16.7‬‬
‫إن ﻟﻐﺔ ‪ HLSL‬ﻏﻨﻴﺔ ﺑﺎﻟﺘﻮاﺑﻊ اﻟﻀﻤﻨﻴﺔ اﻟﻤﻔﻴﺪة ﻓﻲ اﻟﺮﺳﻮﻣﻴﺎت ﺛﻼﺛﻴﺔ اﻷﺑﻌﺎد‪ .‬اﻟﺠﺪول اﻟﺘﺎﻟﻲ‬
‫ﻋﺒﺎرة ﻋﻦ ﻻﺋﺤﺔ ﻣﻮﺟﺰة ﻣﻦ هﺬﻩ اﻟﺘﻮاﺑﻊ‪ .‬ﺳﻨﺘﻤﺮن ﻋﻠﻰ اﺳﺘﺨﺪام ﺑﻌﺾ هﺬﻩ اﻟﺘﻮاﺑﻊ ﻓﻲ‬
‫اﻟﻔﺼﻠﻴﻦ اﻟﺘﺎﻟﻴﻴﻦ‪ .‬أﻣﺎ ﺣﺎﻟﻴًﺎ ﻓﻘﻢ ﺑﺎﻟﺘﻌﺮف إﻟﻴﻬﺎ ﻓﻘﻂ‪.‬‬

‫‪DirectX‬‬ ‫اﻟﻀﻤﻨﻴﺔ ﻣﻦ وﺛﺎﺋﻖ‬ ‫‪HLSL‬‬ ‫ﻳﻤﻜﻦ اﻟﺤﺼﻮل ﻋﻠﻰ ﻻﺋﺤﺔ آﺎﻣﻠﺔ ﺑﺘﻮاﺑﻊ‬
‫ﺗﺤﺖ اﻟﺒﻨﺪ ‪ Contents‬ﺛﻢ‬
‫‪DirectX Graphics\Reference\Shader Reference\High Level‬‬
‫‪Shader Language\Intrinsic Functions.‬‬

‫وﺻﻔﻪ‬ ‫اﻟﺘﺎﺑﻊ‬

‫ﻳﻌﻴﺪ |‪.|x‬‬ ‫)‪abs(x‬‬


‫ﻳﻌﻴﺪ أﺻﻐﺮ ﻋﺪد ﺻﺤﻴﺢ أآﺒﺮ أو ﻳﺴﺎوي ‪.x‬‬ ‫)‪ceil(x‬‬
‫ﻳﺠﻌﻞ ‪ x‬ﺿﻤﻦ اﻟﻤﺠﺎل ]‪ [a, b‬إذا آﺎن ﺧﺎرﺟﻪ )إذا آﺎن ‪ x > b‬ﻳﺼﻴﺮ‬ ‫)‪clamp(x, a, b‬‬
‫‪ x = b‬وإذا آﺎن ‪ x < a‬ﻳﺼﻴﺮ ‪ (x = a‬وﻳﻌﻴﺪ اﻟﻨﺎﺗﺞ‪.‬‬
‫ﻳﻌﻴﺪ ﺟﻴﺐ اﻟﺘﻤﺎم ﻟﻠﺰاوﻳﺔ ‪) x‬ﺣﻴﺚ ‪ x‬ﻣﻘﺪرة ﺑﺎﻟﺮادﻳﺎن(‪.‬‬ ‫)‪cos(x‬‬
‫ﻳﻌﻴﺪ ‪.u×v‬‬ ‫)‪cross(u, v‬‬
‫ﻳﺤﻮل ‪ x‬ﻣﻦ اﻟﺮادﻳﺎن إﻟﻰ اﻟﺪرﺟﺎت‪.‬‬ ‫)‪degrees(x‬‬
‫ﻳﻌﻴﺪ ﻗﻴﻤﺔ ﻣﺤﺪد اﻟﻤﺼﻔﻮﻓﺔ ‪) M‬أي )‪.(det(M‬‬ ‫)‪determinant(M‬‬
‫ﻳﻌﻴﺪ اﻟﻤﺴﺎﻓﺔ ||‪ ||u-v‬ﺑﻴﻦ اﻟﻨﻘﻄﺘﻴﻦ ‪.v, u‬‬ ‫)‪distance(u, v‬‬
‫ﻳﻌﻴﺪ ‪.u.v‬‬ ‫)‪dot(u, v‬‬
‫ﻳﻌﻴﺪ أآﺒﺮ ﻋﺪد ﺻﺤﻴﺢ أﺻﻐﺮ أو ﻳﺴﺎوي ‪.x‬‬ ‫)‪floor(x‬‬
‫اﻟﻤﻈﻠﻼت واﻟﺘﺄﺛﻴﺮات‬ ‫‪٣٥٤‬‬

‫وﺻﻔﻪ‬ ‫اﻟﺘﺎﺑﻊ‬

‫ﻳﻌﻴﺪ ||‪.||v‬‬ ‫)‪length(v‬‬


‫ﻳﻮﺟﺪ اﻟﺘﺮآﻴﺐ اﻟﺨﻄﻲ ﻟﻜﻞ ﻣﻦ ‪ u‬و‪ v‬اﻋﺘﻤﺎداً ﻋﻠﻰ اﻟﻮﺳﻴﻂ ‪ t‬ﺣﻴﺚ‬ ‫)‪lerp(u, v, t‬‬
‫]‪t∈ [0,1‬‬
‫ﻳﻌﻴﺪ )‪.ln(x‬‬ ‫)‪log(x‬‬
‫ﻳﻌﻴﺪ )‪.log10(x‬‬ ‫)‪log10(x‬‬
‫ﻳﻌﻴﺪ )‪.log2(x‬‬ ‫)‪log2(x‬‬
‫ﻳﻌﻴﺪ اﻟﻘﻴﻤﺔ اﻟﻌﻈﻤﻰ ﻣﻦ اﻟﻘﻴﻤﺘﻴﻦ ‪.y, x‬‬ ‫)‪max(x, y‬‬
‫ﻳﻌﻴﺪ اﻟﻘﻴﻤﺔ اﻟﺼﻐﺮى ﻣﻦ اﻟﻘﻴﻤﺘﻴﻦ ‪.y, x‬‬ ‫)‪min(x, y‬‬
‫ﻳﻌﻴﺪ ﺟﺪاء اﻟﻤﺼﻔﻮﻓﺘﻴﻦ ‪ .MN‬ﻻﺣﻆ أﻧﻪ ﻳﺠﺐ أن ﻳﻜﻮن اﻟﺠﺪاء ‪MN‬‬ ‫)‪mul(M, N‬‬
‫ﻣﻌﺮﻓﺎً‪ .‬إذا آﺎن ‪ M‬ﻋﺒﺎرة ﻋﻦ ﺷﻌﺎع ﻋﻨﺪﺋﺬ ﻳُﻌﺎﻣﻞ آﺸﻌﺎع ﺳﻄﺮ‬
‫ﺑﺸﺮط أن ﻳﻜﻮن ﺟﺪاء اﻟﺸﻌﺎع ﺑﻤﺼﻔﻮﻓﺔ ﻣﻌﺮﻓﺎً‪ .‬آﺬﻟﻚ إذا آﺎن ‪ N‬ﻋﺒﺎرة‬
‫ﻋﻦ ﺷﻌﺎع ﻋﻨﺪﺋﺬ ﻳُﻌﺎﻣﻞ آﺸﻌﺎع ﻋﻤﻮد ﺑﺸﺮط أن ﻳﻜﻮن ﺟﺪاء‬
‫اﻟﻤﺼﻔﻮﻓﺔ ﺑﺸﻌﺎع ﻣﻌﺮﻓﺎً‪.‬‬
‫ﻳﻌﻴﺪ ||‪.v/||v‬‬ ‫)‪normalize(v‬‬
‫‪n‬‬
‫ﻳﻌﻴﺪ ‪.b‬‬ ‫)‪pow(b, n‬‬
‫ﻳﺤﻮل ‪ x‬ﻣﻦ اﻟﺪرﺟﺎت إﻟﻰ اﻟﺮادﻳﺎن‪.‬‬ ‫)‪radians(x‬‬
‫ﻳﻮﺟﺪ ﺷﻌﺎع اﻻﻧﻌﻜﺎس اﻋﺘﺒﺎراً ﻣﻦ ﺷﻌﺎع اﻟﻮرود ‪ v‬وﻧﺎﻇﻢ اﻟﺴﻄﺢ ‪.n‬‬ ‫)‪reflect(v, n‬‬
‫ﻳﻮﺟﺪ ﺷﻌﺎع اﻻﻧﻜﺴﺎر اﻋﺘﺒﺎراً ﻣﻦ ﺷﻌﺎع اﻟﻮرود ‪ v‬وﻧﺎﻇﻢ اﻟﺴﻄﺢ ‪n‬‬ ‫)‪refract(v, n, eta‬‬
‫وﻋﺎﻣﻞ اﻻﻧﻜﺴﺎراﻟﻨﺴﺒﻲ ﺑﻴﻦ اﻟﻤﺎدﺗﻴﻦ ‪.eta‬‬
‫ﻳﻌﻴﺪ ‪1/ x‬‬ ‫)‪rsqrt(x‬‬
‫ﻳﻌﻴﺪ )‪.clamp(x, 0.0, 1.0‬‬ ‫)‪saturate(x‬‬
‫ﻳﻌﻴﺪ ﺟﻴﺐ اﻟﺰاوﻳﺔ ‪) x‬ﺣﻴﺚ ‪ x‬ﻣﻘﺪرة ﺑﺎﻟﺮادﻳﺎن(‪.‬‬ ‫)‪sin(x‬‬
‫ﻳﻌﻴﺪ ﺟﻴﺐ وﺟﻴﺐ اﻟﺘﻤﺎم ﻟﻠﺰاوﻳﺔ ‪) x‬ﺣﻴﺚ ‪ x‬ﻣﻘﺪرة ﺑﺎﻟﺮادﻳﺎن(‪.‬‬ ‫)‪sincos(in x, out s, out c‬‬
‫ﻳﻌﻴﺪ ‪. x‬‬ ‫)‪sqrt(x‬‬
‫ﻳﻌﻴﺪ ﻇﻞ اﻟﺰاوﻳﺔ ‪) x‬ﺣﻴﺚ ‪ x‬ﻣﻘﺪرة ﺑﺎﻟﺮادﻳﺎن(‪.‬‬ ‫)‪tan(x‬‬
‫‪T‬‬
‫ﻳﻌﻴﺪ اﻟﻤﻨﻘﻮل ‪.M‬‬ ‫)‪transpose(M‬‬

‫ﻗﺪ أُﺟﺮي اﻟﺘﺤﻤﻴﻞ اﻟﺰاﺋﺪ ﻋﻠﻰ ﻣﻌﻈﻢ هﺬﻩ اﻟﺘﻮاﺑﻊ ﺑﻐﻴﺔ اﺳﺘﺨﺪاﻣﻬﺎ ﻣﻊ آﻞ اﻷﻧﻮاع اﻟﻀﻤﻨﻴﺔ‬
‫ﻼ ﻳﺴﺘﺨﺪم اﻟﺘﺎﺑﻊ ‪ abs‬ﻣﻊ آﻞ اﻷﻧﻮاع اﻟﺴﻠﻤﻴﺔ‪ ،‬أﻣﺎ اﻟﺠﺪاء اﻟﺸﻌﺎﻋﻲ ‪cross‬‬ ‫اﻟﻤﻤﻜﻨﺔ‪ .‬ﻣﺜ ً‬
‫ﻓﻴﺴﺘﺨﺪم ﻓﻘﻂ ﻣﻊ اﻷﺷﻌﺔ ﺛﻼﺛﻴﺔ اﻷﺑﻌﺎد ﻣﻦ أي ﻧﻮع )أي أﺷﻌﺔ ﺛﻼﺛﻴﺔ اﻷﺑﻌﺎد ﻣﺮآﺒﺎﺗﻬﺎ ‪int‬‬
‫أو ‪ ...float‬اﻟﺦ(‪.‬‬
‫ﻓﺈﻧﻪ ﻳُﺴﺘﺨﺪم ﻣﻊ اﻟﻘﻴﻢ اﻟﺴﻠﻤﻴﺔ واﻷﺷﻌﺔ ﺛﻨﺎﺋﻴﺔ وﺛﻼﺛﻴﺔ ورﺑﺎﻋﻴﺔ‬ ‫‪lerp‬‬ ‫أﻣﺎ ﺑﺎﻟﻨﺴﺒﺔ إﻟﻰ اﻟﺘﺎﺑﻊ‬
‫‪٣٥٥‬‬ ‫‪ :16‬ﻣﺪﺧﻞ إﻟﻰ ﻟﻐﺔ اﻟﺘﻈﻠﻴﻞ ﻋﺎﻟﻴﺔ اﻟﻤﺴﺘﻮى‬

‫اﻷﺑﻌﺎد وﺑﺎﻟﺘﺎﻟﻲ ﻳﺘﻢ إﺟﺮاء اﻟﺘﺤﻤﻴﻞ اﻟﺰاﺋﺪ ﻟﻬﺎ ﻣﻦ أﺟﻞ آﻞ اﻷﻧﻮاع‪.‬‬


‫إذا ﻗﻤﺖ ﺑﺘﻤﺮﻳﺮ ﻗﻴﻤﺔ ﻏﻴﺮ ﺳﻠﻤﻴﺔ إﻟﻰ ﺗﺎﺑﻊ ذو وﺳﻴﻂ ﺳﻠﻤﻲ )أي‪ :‬ﺗﺎﺑﻊ ﻳﺄﺧﺬ‬
‫ﻋﺎدة وﺳﻴﻄًﺎ ﺳﻠﻤﻴًﺎ ﻣﺜﻞ )‪ (cos(x‬ﻋﻨﺪهﺎ ﺳﻴﻌﻤﻞ اﻟﺘﺎﺑﻊ ﻋﻠﻰ آﻞ ﻣﺮآﺒﺔ ﻋﻠﻰ‬
‫ﻼ إذا آﺘﺒﺖ‪:‬‬
‫ﺣﺪة‪ .‬ﻣﺜ ً‬
‫;)‪float3 v = float3(0.0f, 0.0f, 0.0f‬‬

‫;)‪v = cos(v‬‬

‫ﻋﻨﺪﺋﺬ ﺳﻴﻜﻮن‪.v = (cos(x), cos(y), cos(z)) :‬‬


‫ﺗﻮﺿﺢ اﻷﻣﺜﻠﺔ اﻟﺘﺎﻟﻴﺔ آﻴﻒ ﻳﺘﻢ اﺳﺘﺪﻋﺎء ﺑﻌﻀًﺎ ﻣﻦ اﻟﺘﻮاﺑﻊ اﻟﺴﺎﺑﻘﺔ‪:‬‬
‫;)‪float x = sin(1.0f‬‬
‫;)‪float y = sqrt(4.0f‬‬

‫;}‪vector u = {1.0f, 2.0f, -3.0f, 0.0f‬‬


‫;}‪vector v = {3.0f, -1.0f, 0.0f, 2.0f‬‬
‫;)‪float s = dot(u, v‬‬

‫;}‪float3 i = {1.0f, 0.0f, 0.0f‬‬


‫;}‪float3 j = {0.0f, 1.0f, 0.0f‬‬
‫;)‪float3 k = cross(i, j‬‬

‫;}‪matrix<float, 2, 2> M = {1.0f, 2.0f, 3.0f, 4.0f‬‬


‫;)‪matrix<float, 2, 2> T = transpose(M‬‬

‫@@‬ ‫@@‬ ‫‪@ò–ý©a@Z16.8‬‬


‫وﻳﺘﻢ ﺗﺮﺟﻤﺘﻬﺎ ﻓﻲ ﺗﻄﺒﻴﻘﺎﺗﻨﺎ ﺑﺎﺳﺘﺨﺪام‬ ‫‪ASCII‬‬ ‫ﺗُﻜﺘﺐ ﺑﺮاﻣﺞ ﻟﻐﺔ ‪ HLSL‬ﻓﻲ ﻣﻠﻔﺎت ﻧﺼﻴﺔ‬ ‫‪R‬‬
‫اﻟﺘﺎﺑﻊ ‪.D3DXCompileShaderFromFile‬‬
‫ﺗﺴﻤﺢ ﻟﻨﺎ اﻟﻮاﺟﻬﺔ ‪ ID3DXConstantTable‬ﺑﺘﺤﺪﻳﺪ ﻗﻴﻢ ﻣﺘﺤﻮﻻت ﺑﺮﻧﺎﻣﺞ اﻟﻤﻈﻠﻞ ﻣﻦ‬ ‫‪R‬‬
‫داﺧﻞ اﻟﺘﻄﺒﻴﻖ‪ .‬ﻋﻤﻠﻴﺔ اﻻﺗﺼﺎل ﺿﺮورﻳﺔ ﻷن اﻟﻤﺘﺤﻮﻻت ﻓﻲ اﻟﻤﻈﻠﻞ ﻗﺪ ﺗﺘﻐﻴﺮ ﻣﻦ‬
‫إﻃﺎر إﻟﻰ إﻃﺎر‪ .‬ﻣﺜﻼً‪ ،‬إذا ﺗﻐﻴﺮت ﻣﺼﻔﻮﻓﺔ اﻟﻌﺮض ﻓﻲ اﻟﺘﻄﺒﻴﻖ‪ ،‬ﻋﻨﺪهﺎ ﺳﻨﺤﺘﺎج إﻟﻰ‬
‫ﺗﺤﺪﻳﺚ ﻣﺘﺤﻮل ﻣﺼﻔﻮﻓﺔ اﻟﻌﺮض ﻓﻲ اﻟﻤﻈﻠﻞ‪ .‬ﺣﻴﺚ ﻳﻤﻜﻨﻨﺎ ﻓﻌﻞ ذﻟﻚ ﻣﻦ ﺧﻼل‬
‫‪.ID3DXConstantTable‬‬
‫ﻳﺠﺐ ﺗﻌﺮﻳﻒ ﺑﻨﻴﺘﺎ دﺧﻞ وﺧﺮج ﻣﻦ أﺟﻞ آﻞ ﻣﻈﻠﻞ ﻧﻜﺘﺒﻪ وذﻟﻚ ﻟﻮﺻﻒ ﺗﻨﺴﻴﻖ‬ ‫‪R‬‬
‫اﻟﻤﻌﻄﻴﺎت اﻟﺘﻲ ﺗﺪﺧﻞ إﻟﻰ اﻟﻤﻈﻠﻞ واﻟﺘﻲ ﺗﺨﺮج ﻣﻨﻪ‪.‬‬
‫اﻟﻤﻈﻠﻼت واﻟﺘﺄﺛﻴﺮات‬ ‫‪٣٥٦‬‬

‫ﻳﻮﺟﺪ ﻟﻜﻞ ﻣﻈﻠﻞ ﺗﺎﺑﻊ ﻧﻘﻄﺔ دﺧﻮل ﻳﺄﺧﺬ وﺳﻴﻄًﺎ ﻋﺒﺎرة ﻋﻦ ﺑﻨﻴﺔ دﺧﻞ ﺗُﺴﺘﺨﺪم ﻟﺘﻤﺮﻳﺮ‬ ‫‪R‬‬
‫ﻣﻌﻄﻴﺎت اﻟﺪﺧﻞ إﻟﻰ اﻟﻤﻈﻠﻞ‪ .‬آﻤﺎ ﻳﻌﻴﺪ آﻞ ﻣﻈﻠﻞ ﺑﻨﻴ َﺔ رأس ﺗُﺴﺘﺨﺪم ﻹﺧﺮاج‬
‫اﻟﻤﻌﻄﻴﺎت ﻣﻦ اﻟﻤﻈﻠﻞ‪.‬‬

You might also like