【GLSL教程】(三)在OpenGL中向shader傳遞資訊
一個OpenGL程式可以用多種方式和shader通訊。注意這種通訊是單向的,因為shader的輸出只能是渲染到某些目標,比如顏色和深度快取。
OpenGL的部分狀態可以被shader訪問,因此程式改變OpenGL某些狀態就可以與shader進行通訊了。例如一個程式想把光的顏色傳給shader,可以直接呼叫OpenGL介面,就像使用固定功能流水線時做的那樣。
不過,使用OpenGL狀態並不是設定shader中使用資料的直觀方式。比如一個shader需要一個表示時間變化的變數來計算動畫,在OpenGL狀態中就沒有現成的變數可用。當然,你可以使用沒有用到的“鏡面光截止角度(cutoffangle)”這樣一個變數表示時間,但顯然讓人難以接受。
幸運的是,GLSL允許使用者自定義變數,實現OpenGL應用程式與shader通訊。有了這個功能,你就可以命名一個叫做timeElapsed的變數表示經過的時間。
上文的討論涉及到了GLSL提供的兩種型別修飾符(更多的型別將在後面提到):
·一致變數(Uniform)
·屬性(Attribute)
在shader中定義的變數如果用這兩種型別修飾符,表示對shader來說,它們是隻讀的。下面將詳細講述怎樣使用這些型別的變數。
還有一種將變數送給shader的方法:使用紋理。一個紋理不止可以表示一張圖片,它還可以表示一個陣列。事實上,你完全可以決定如何在shader中解釋紋理資料,即使它真是一幅圖片。
資料型別和變數
下面是GLSL中的基本資料型別:·float
·bool
·int
浮點型別與C中類似,布林型別可以為true或false。這些基本型別可以組成2、3或4維向量,如下所示:
·vec{2,3,4} a vector of 2,3,or 4 floats
·bvec{2,3,4} bool vector
·ivec{2,3,4} vector of integers
GLSL還包括2×2、3×3或4×4型矩陣,因為這些矩陣型別在圖形處理中很常用:
·mat2
·mat3
·mat4
此外,還有一組用來實現紋理訪問的特殊型別,它們被稱為取樣器(sampler),在讀取紋理值(也稱為紋素texel)時用到。下面就是紋理取樣用到的資料型別:
·sampler1D – for 1D textures
·sampler2D – for 2D textures
·sampler3D – for 3D textures
·samplerCube – for cube map textures
·sampler1DShadow – for shadow maps
·sampler2DShadow – for shadow maps
在GLSL中,可以像C一樣宣告和訪問陣列,但是不能在宣告時初始化陣列。GLSL還可以定義結構體:
- struct dirlight
- {
- vec3 direction;
- vec3 color;
- };
struct dirlight
{
vec3 direction;
vec3 color;
};
變數
宣告一個基本型別變數的方法與C類似,你還可以在宣告它的同時進行初始化。
- float a,b; // two vector (yes, the comments are like in C)
- int c = 2; // c is initialized with 2
- bool d = true; // d is true
float a,b; // two vector (yes, the comments are like in C)
int c = 2; // c is initialized with 2
bool d = true; // d is true
宣告其它型別變數也是按照這種方法,但是初始化與C語言有區別。GLSL非常依賴建構函式實現初始化和型別轉換。
- float b = 2; // incorrect, there is no automatic type casting
- float e = (float)2; // incorrect, requires constructors for type casting
- int a = 2;
- float c = float(a); // correct. c is 2.0
- vec3 f; // declaring f as a vec3
- vec3 g = vec3(1.0,2.0,3.0); // declaring and initializing g
float b = 2; // incorrect, there is no automatic type casting
float e = (float)2; // incorrect, requires constructors for type casting
int a = 2;
float c = float(a); // correct. c is 2.0
vec3 f; // declaring f as a vec3
vec3 g = vec3(1.0,2.0,3.0); // declaring and initializing g
在GLSL中使用一些變數初始化其它變數是非常靈活的。你只需要給出需要的資料成員即可。請看下面的例子:
- vec2 a = vec2(1.0,2.0);
- vec2 b = vec2(3.0,4.0);
- vec4 c = vec4(a,b) // c = vec4(1.0,2.0,3.0,4.0);
- vec2 g = vec2(1.0,2.0);
- float h = 3.0;
- vec3 j = vec3(g,h);
vec2 a = vec2(1.0,2.0);
vec2 b = vec2(3.0,4.0);
vec4 c = vec4(a,b) // c = vec4(1.0,2.0,3.0,4.0);
vec2 g = vec2(1.0,2.0);
float h = 3.0;
vec3 j = vec3(g,h);
矩陣的初始化也是類似方法,矩陣包含很多種建構函式,下面的例子給出了一些初始化矩陣的建構函式:
- mat4 m = mat4(1.0) // initializing the diagonal of the matrix with 1.0
- vec2 a = vec2(1.0,2.0);
- vec2 b = vec2(3.0,4.0);
- mat2 n = mat2(a,b); // matrices are assigned in column major order
- mat2 k = mat2(1.0,0.0,1.0,0.0); // all elements are specified
mat4 m = mat4(1.0) // initializing the diagonal of the matrix with 1.0
vec2 a = vec2(1.0,2.0);
vec2 b = vec2(3.0,4.0);
mat2 n = mat2(a,b); // matrices are assigned in column major order
mat2 k = mat2(1.0,0.0,1.0,0.0); // all elements are specified
下面的例子給出了初始化結構體的方法:
- struct dirlight // type definition
- {
- vec3 direction;
- vec3 color;
- };
- dirlight d1;
- dirlight d2 = dirlight(vec3(1.0,1.0,0.0),vec3(0.8,0.8,0.4));
struct dirlight // type definition
{
vec3 direction;
vec3 color;
};
dirlight d1;
dirlight d2 = dirlight(vec3(1.0,1.0,0.0),vec3(0.8,0.8,0.4));
在GLSL中還有一些實用的選擇子(selector),可以簡化我們的操作並讓程式碼更簡潔。訪問一個向量可以使用如下的方法:
- vec4 a = vec4(1.0,2.0,3.0,4.0);
- float posX = a.x;
- float posY = a[1];
- vec2 posXY = a.xy;
- float depth = a.w
vec4 a = vec4(1.0,2.0,3.0,4.0);
float posX = a.x;
float posY = a[1];
vec2 posXY = a.xy;
float depth = a.w
在上面的程式碼片段中,可以使用x、y、z、w來訪問向量成員。如果是顏色的話可以使用r、g、b、a,如果是紋理座標的話可以使用s、t、p、q。注意表示紋理座標通常是使用s、t、r、q,但r已經表示顏色中的紅色(red)了,所以紋理座標中需要使用p來代替。
矩陣的選擇子可以使用一個或兩個引數,比如m[0]或者m[2][3]。第一種情況選擇了第一列,第二種情況選擇了一個資料成員。
對於結構體來說,可以像在C語言中一樣訪問其成員。所以訪問前面定義的結構體,可以使用如下的程式碼:
- d1.direction = vec3(1.0,1.0,1.0);
d1.direction = vec3(1.0,1.0,1.0);
變數修飾符
修飾符給出了變數的特殊含義,GLSL中有如下修飾符:
·const – 宣告一個編譯期常量。
·attribute– 隨不同頂點變化的全域性變數,由OpenGL應用程式傳給頂點shader。這個修飾符只能用在頂點shader中,在shader中它是一個只讀變數。
·uniform– 隨不同圖元變化的全域性變數(即不能在glBegin/glEnd中設定),由OpenGL應用程式傳給shader。這個修飾符能用在頂點和片斷shader中,在shader中它是一個只讀變數。
·varying –用於頂點shader和片斷shader間傳遞的插值資料,在頂點shader中可寫,在片斷shader中只讀。
一致變數(Uniform Variables)
不同於頂點屬性在每個頂點有其自己的值,一個一致變數在一個圖元的繪製過程中是不會改變的,所以其值不能在glBegin/glEnd中設定。一致變數適合描述在一個圖元中、一幀中甚至一個場景中都不變的值。一致變數在頂點shader和片斷shader中都是隻讀的。
首先你需要獲得變數在記憶體中的位置,這個資訊只有在連線程式之後才可獲得。注意,對某些驅動程式,在獲得儲存位置前還必須使用程式(呼叫glUseProgram)。
獲取一個一致變數的儲存位置只需要給出其在shader中定義的變數名即可:
- GLint glGetUniformLocation(GLuint program, const char *name);
- 引數:
- ·program – the hanuler to the program
- ·name – the name of the variable
GLint glGetUniformLocation(GLuint program, const char *name);
引數:
·program – the hanuler to the program
·name – the name of the variable
返回值就是變數位置,可以用此資訊設定變數的值。根據變數的資料型別不同,有一系列函式可以用來設定一致變數。用來設定浮點值的一組函式如下:
- void glUniform1f(GLint location, GLfloat v0);
- void glUniform2f(GLint location, GLfloat v0, GLfloat v1);
- void glUniform3f(GLint location, GLfloat v0, GLfloat v1, GLfloat v2);
- void glUniform4f(GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3);
- 或者
- GLint glUniform{1,2,3,4}fv(GLint location, GLsizei count, GLfloat *v);
- 引數:
- ·location – the previously queried location
- ·v0,v1,v2,v3 – float values
- ·count – the number of elements in the array
- ·v – an array of floats
void glUniform1f(GLint location, GLfloat v0);
void glUniform2f(GLint location, GLfloat v0, GLfloat v1);
void glUniform3f(GLint location, GLfloat v0, GLfloat v1, GLfloat v2);
void glUniform4f(GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3);
或者
GLint glUniform{1,2,3,4}fv(GLint location, GLsizei count, GLfloat *v);
引數:
·location – the previously queried location
·v0,v1,v2,v3 – float values
·count – the number of elements in the array
·v – an array of floats
對integer型別也有一組類似的函式,不過要用i替換函式中的f。對bool型別沒有專門的函式,但可以使用整數的0和1來表示真假。一旦你使用了一致變數陣列,那麼就必須使用向量版本的函式。
對sampler變數,使用函式glUniform1i和glUniform1iv。
矩陣也是一種GLSL的資料型別,所以也有一組針對矩陣的函式:
- GLint glUniformMatrix{2,3,4}fv(GLint location, GLsizei count, GLboolean transpose, GLfloat *v);
- 引數:
- location – the previously queried location.
- count – the number of matrices. 1 if a single matrix is being set, or n for an array of n matrices.
- transpose – wheter to transpose the matrix values. A value of 1 indicates that the matrix values are specified in row major order, zero is column major order
- v – an array of floats.
GLint glUniformMatrix{2,3,4}fv(GLint location, GLsizei count, GLboolean transpose, GLfloat *v);
引數:
location – the previously queried location.
count – the number of matrices. 1 if a single matrix is being set, or n for an array of n matrices.
transpose – wheter to transpose the matrix values. A value of 1 indicates that the matrix values are specified in row major order, zero is column major order
v – an array of floats.
還有一點要注意的是:使用這些函式之後,變數的值將保持到程式再次連線之時。一旦進行重新連線,所有變數的值將被重置為0。
最後是一些示例程式碼。假設一個shader中使用瞭如下變數:
- uniform float specIntensity;
- uniform vec4 specColor;
- uniform float t[2];
- uniform vec4 colors[3];
uniform float specIntensity;
uniform vec4 specColor;
uniform float t[2];
uniform vec4 colors[3];
在OpenGL程式中可以使用下面的程式碼設定這些變數:
- GLint loc1,loc2,loc3,loc4;
- float specIntensity = 0.98;
- float sc[4] = {0.8,0.8,0.8,1.0};
- float threshold[2] = {0.5,0.25};
- float colors[12] = {0.4,0.4,0.8,1.0,
- 0.2,0.2,0.4,1.0,
- 0.1,0.1,0.1,1.0};
- loc1 = glGetUniformLocation(p,"specIntensity");
- glUniform1f(loc1,specIntensity);
- loc2 = glGetUniformLocation(p,"specColor");
- glUniform4fv(loc2,1,sc);
- loc3 = glGetUniformLocation(p,"t");
- glUniform1fv(loc3,2,threshold);
- loc4 = glGetUniformLocation(p,"colors");
- glUniform4fv(loc4,3,colors);
GLint loc1,loc2,loc3,loc4;
float specIntensity = 0.98;
float sc[4] = {0.8,0.8,0.8,1.0};
float threshold[2] = {0.5,0.25};
float colors[12] = {0.4,0.4,0.8,1.0,
0.2,0.2,0.4,1.0,
0.1,0.1,0.1,1.0};
loc1 = glGetUniformLocation(p,"specIntensity");
glUniform1f(loc1,specIntensity);
loc2 = glGetUniformLocation(p,"specColor");
glUniform4fv(loc2,1,sc);
loc3 = glGetUniformLocation(p,"t");
glUniform1fv(loc3,2,threshold);
loc4 = glGetUniformLocation(p,"colors");
glUniform4fv(loc4,3,colors);
例子程式碼的下載地址:
http://lighthouse3d.com/wptest/wp-content/uploads/2011/03/glutglsl2_2.0.zip
注意設定一個陣列(例子中的t)與設定四元向量(例子中的colors和specColor)的區別。中間的count引數指在shader中宣告的陣列元素數量,而不是在OpenGL程式中宣告的。所以雖然specColor包含4個值,但glUniform4fv函式中的引數是1,因為它只是一個向量。另一種設定specColor的方法:
- loc2 = glGetUniformLocation(p,"specColor");
- glUniform4f(loc2,sc[0],sc[1],sc[2],sc[3]);
loc2 = glGetUniformLocation(p,"specColor");
glUniform4f(loc2,sc[0],sc[1],sc[2],sc[3]);
GLSL中還可以獲取陣列中某個變數的地址。比如,可以獲得t[1]的地址。下面的程式碼片段展示了設定t陣列元素的另一種方法:
- loct0 = glGetUniformLocation(p,"t[0]");
- glUniform1f(loct0,threshold[0]);
- loct1 = glGetUniformLocation(p,"t[1]");
- glUniform1f(loct1,threshold[1]);
loct0 = glGetUniformLocation(p,"t[0]");
glUniform1f(loct0,threshold[0]);
loct1 = glGetUniformLocation(p,"t[1]");
glUniform1f(loct1,threshold[1]);
注意在glGetUniformLocation中使用方括號指示的變數。
屬性變數(Attribute Variables)
在前一節提到,一致變數只能針對一個圖元全體,就是說不能在glBegin和glEnd之間改變。
如果要針對每個頂點設定變數,那就需要屬性變數了。事實上屬性變數可以在任何時刻更新。在頂點shader中屬性變數是隻讀的。因為它包含的是頂點資料,所以在片斷shader中不能直接應用。
與一致變數相似,首先你需要獲得變數在記憶體中的位置,這個資訊只有在連線程式之後才可獲得。注意,對某些驅動程式,在獲得儲存位置前還必須使用程式。
- GLint glGetAttribLocation(GLuint program,char *name);
- 引數:
- program – the handle to the program.
- name – the name of the variable
GLint glGetAttribLocation(GLuint program,char *name);
引數:
program – the handle to the program.
name – the name of the variable
上述函式呼叫的返回變數在儲存器中的地址。下面就可以為它指定一個值,類似一致變數,每種資料型別都有對應的函式。
- void glVertexAttrib1f(GLint location, GLfloat v0);
- void glVertexAttrib2f(GLint location, GLfloat v0, GLfloat v1);
- void glVertexAttrib3f(GLint location, GLfloat v0, GLfloat v1,GLfloat v2);
- void glVertexAttrib4f(GLint location, GLfloat v0, GLfloat v1,,GLfloat v2, GLfloat v3);
- 或者
- GLint glVertexAttrib{1,2,3,4}fv(GLint location, GLfloat *v);
- 引數:
- location – the previously queried location.
- v0,v1,v2,v3 – float values.
- v – an array of floats.
void glVertexAttrib1f(GLint location, GLfloat v0);
void glVertexAttrib2f(GLint location, GLfloat v0, GLfloat v1);
void glVertexAttrib3f(GLint location, GLfloat v0, GLfloat v1,GLfloat v2);
void glVertexAttrib4f(GLint location, GLfloat v0, GLfloat v1,,GLfloat v2, GLfloat v3);
或者
GLint glVertexAttrib{1,2,3,4}fv(GLint location, GLfloat *v);
引數:
location – the previously queried location.
v0,v1,v2,v3 – float values.
v – an array of floats.
對於integer型別,也有一組類似的函式。與一致變數不同,這裡向量版的函式並不支援對向量陣列的賦值,所以函式引數用向量或是分別指定的效果沒有太大區別,就好像OpenGL中glColor3f和glColor3fv的關係。
下面是一個簡單的例子,假定頂點shader中宣告瞭一個名為height的浮點屬性變數,在程式連線之後可以進行如下操作:
- loc = glGetAttribLocation(p,"height");
loc = glGetAttribLocation(p,"height");
在執行渲染的程式碼中間可以為shader中的變數賦值:
- glBegin(GL_TRIANGLE_STRIP);
- glVertexAttrib1f(loc,2.0);
- glVertex2f(-1,1);
- glVertexAttrib1f(loc,2.0);
- glVertex2f(1,1);
- glVertexAttrib1f(loc,-2.0);
- glVertex2f(-1,-1);
- glVertexAttrib1f(loc,-2.0);
- glVertex2f(1,-1);
- glEnd();
glBegin(GL_TRIANGLE_STRIP);
glVertexAttrib1f(loc,2.0);
glVertex2f(-1,1);
glVertexAttrib1f(loc,2.0);
glVertex2f(1,1);
glVertexAttrib1f(loc,-2.0);
glVertex2f(-1,-1);
glVertexAttrib1f(loc,-2.0);
glVertex2f(1,-1);
glEnd();
例子程式碼的下載地址:
http://lighthouse3d.com/wptest/wp-content/uploads/2011/03/glutglsl3_2.0.zip、
頂點陣列和屬性變數也可以一起使用。首先需要使能陣列,使用如下函式:
- void glEnableVertexAttribArray(GLint loc);
- 引數:
- loc – the location of the variable.
void glEnableVertexAttribArray(GLint loc);
引數:
loc – the location of the variable.
接下來使用函式提交包含資料的陣列指標:
- void glVertexAttribPointer(GLint loc, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const void *pointer);
- 引數:
- loc – the location of the variable.
- size – the number of components per element, for instance: 1 for float; 2 for vec2; 3 for vec3, and so on.
- type – The data type associated: GL_FLOAT is an example.
- normalized – if set to 1 then the array values will be normalized, converted to a range from -1 to 1 for signed data, or 0 to 1 for unsigned data.
- stride – the spacing between elements. Exactly the same as in OpenGL.
- pointer – pointer to the array containing the data.
void glVertexAttribPointer(GLint loc, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const void *pointer);
引數:
loc – the location of the variable.
size – the number of components per element, for instance: 1 for float; 2 for vec2; 3 for vec3, and so on.
type – The data type associated: GL_FLOAT is an example.
normalized – if set to 1 then the array values will be normalized, converted to a range from -1 to 1 for signed data, or 0 to 1 for unsigned data.
stride – the spacing between elements. Exactly the same as in OpenGL.
pointer – pointer to the array containing the data.
下面是示例程式碼,首先執行初始化,定義了頂點陣列和屬性陣列。
- float vertices[8] = {-1,1, 1,1, -1,-1, 1,-1};
- float heights[4] = {2,2,-2,-2};
- ...
- loc = glGetAttribLocation(p,"height");
- glEnableClientState(GL_VERTEX_ARRAY);
- glEnableVertexAttribArray(loc);
- glVertexPointer(2,GL_FLOAT,0,vertices);
- glVertexAttribPointer(loc,1,GL_FLOAT,0,0,heights);
float vertices[8] = {-1,1, 1,1, -1,-1, 1,-1};
float heights[4] = {2,2,-2,-2};
...
loc = glGetAttribLocation(p,"height");
glEnableClientState(GL_VERTEX_ARRAY);
glEnableVertexAttribArray(loc);
glVertexPointer(2,GL_FLOAT,0,vertices);
glVertexAttribPointer(loc,1,GL_FLOAT,0,0,heights);
接下來的渲染步驟與OpenGL中的通常做法一致,比如呼叫glDrawArrays。示例原始碼下載地址:
http://lighthouse3d.com/wptest/wp-content/uploads/2011/03/glutglsl4_2.0.zip
易變變數(Varying Variables)
前面說過,shader包括兩種型別:頂點shader和片斷shader。為了計算片斷的值,往往需要訪問頂點的插值資料。例如,當使用逐片斷光照時,我們需要知道當前片斷的法線,但是在OpenGL中只為每個頂點指定了法線。頂點shader可以訪問這些法線,而片斷shader不能,因為法線是OpenGL程式作為屬性變數指定的。
頂點變換後的資料移動到流水線的下一個階段,在這個階段通過使用連線資訊,生成了所有圖元並完成片斷化。對每個片斷,有一組變數會被自動進行插值並提供給片斷shader,這些都是固定功能。片斷的顏色就是這麼處理的,到達片斷shader的顏色就是組成圖元的頂點顏色插值的結果。
像片斷shader接收到的這種插值產生的變數,就是“易變變數”型別。GLSL包含一些預先定義的易變變數,例如前面提到的顏色。使用者也可以自己定義易變變數,它們必須同時在頂點shader和片斷shader中宣告:
- varying float intensity;
varying float intensity;
一個易變變數必須先在頂點shader中宣告,然後計算每個頂點的變數值。在片斷shader中,接收這個變數通過插值得到的結果,注意此時這個變數是隻讀的。
語句和函式
控制流語句
與C語言類似,GLSL中有類似if-else的條件語句,for,while,do-while等迴圈語句。
- if (bool expression)
- ...
- else
- ...
- for (initialization; bool expression; loop expression)
- ...
- while (bool expression)
- ...
- do
- ...
- while (bool expression)
if (bool expression)
...
else
...
for (initialization; bool expression; loop expression)
...
while (bool expression)
...
do
...
while (bool expression)
GLSL也有跳轉語句:
·continue – available in loops, causes a jump to thenext iteration of the loop
·break – available in loops, causes an exit of theloop
·discard
最後的discard關鍵字只能在片斷shader中使用,它將在不寫入幀快取或者深度快取的情況下,終止當前片斷的shader程式。
函式
與C語言類似,shader也是由函式組成的結構化程式。至少每類shader都必須包含一個如下方式宣告的主函式:
- void main()
void main()
此外使用者還可以自定義函式。這些函式像C函式一樣,一般都會有返回值,返回值的型別沒有限制,但不能是陣列。函式引數可以有如下修飾符:
·in – for input parameters
·out – for outputs of the function. The returnstatement is also an option for sending the result of a function.
·inout – for parameters that are both input andoutput of a function
如果沒有指定修飾符,預設情況下為in型別。
最後還有兩點要注意:
·允許函式過載,只要引數不同。
·在標準中沒有定義遞迴行為。
結束本節之前來看一個函式的例子:
- vec4 toonify(in float intensity)
- {
- vec4 color;
- if (intensity > 0.98)
- color = vec4(0.8,0.8,0.8,1.0);
- else if (intensity > 0.5)
- color = vec4(0.4,0.4,0.8,1.0);
- else if (intensity > 0.25)
- color = vec4(0.2,0.2,0.4,1.0);
- else
- color = vec4(0.1,0.1,0.1,1.0);
- return(color);
- }
相關文章
- 【GLSL教程】(二)在OpenGL中使用GLSL
- 向Vertex Shader傳遞vertex attribute
- opengl 教程(5) shader(2) uniform變數ORM變數
- OpenGL Shader例項,OpenGL 粒子系統
- OpenGL 4.0 GLSL 採用平行光照模型模型
- 資訊傳遞
- OpenGL shader 程式基礎
- Tessellation Shader的GLSL入門實現: 平面
- shuffle過程中的資訊傳遞
- 可否在JSP中向applet傳遞多個引數?JSAPP
- Shader學習筆記,通過GLSL實現(一)筆記
- 父子元件資訊傳遞元件
- 【GLSL教程】(五)卡通著色
- 用雞蛋和腦袋傳遞資訊 以及你想象不到資訊傳遞方式
- OpenGL 和 GLSL 在頂點著色器中動態調整裁剪平面引數的簡單程式碼示例
- 向檢視傳遞變數變數
- 從request中傳遞過來的引數資訊
- LCP 07. 傳遞資訊
- [轉]Shell向Perl指令碼中傳遞變數的方法指令碼變數
- Unity3D Shader官方教程翻譯(三)----Shader語法:屬性Unity3D
- 兄弟元件之間資訊傳遞元件
- Java中的值傳遞和引用傳遞Java
- 【GLSL教程】(一)圖形流水線
- 在 PO 模式中,driver 如何通過 basePage 在各個 testcase 中傳遞?模式
- Omi教程 - 傳遞javascript表示式JavaScript
- vue子元件向父元件傳遞值Vue元件
- 【GLSL教程】(四)shder的簡單示例
- 【GLSL教程】(六)逐頂點的光照
- C,C++中如何向main(int argc , char argv[])傳遞引數C++AIGC
- chan中傳遞map資料,傳遞的是引用
- java方法中只有值傳遞,沒有引用傳遞Java
- 簡單的在兩個activity中傳遞資料
- react篇章-React 元件-向元件傳遞引數React元件
- 向路由元件傳遞引數2種方法路由元件
- Service實時向Activity傳遞資料案例
- OpenGL系列教程之一:OpenGL(轉)
- 面試官問:Go 中的引數傳遞是值傳遞還是引用傳遞?面試Go
- js中函式引數值傳遞和引用傳遞JS函式