[{"data":1,"prerenderedAt":731},["ShallowReactive",2],{"page-\u002Fcpp\u002Fopengel\u002F材质":3},{"id":4,"title":5,"body":6,"description":12,"extension":725,"meta":726,"navigation":72,"path":727,"seo":728,"stem":729,"__hash__":730},"content\u002Fcpp\u002Fopengel\u002F材质.md","材质",{"type":7,"value":8,"toc":722},"minimark",[9,13,80,83,99,126,132,135,344,351,358,361,421,426,429,440,460,474,483,500,544,564,569,589,592,652,656,663,718],[10,11,12],"p",{},"材质也就是将我们之前使用的三个光照结合起来，增加一个反光度分量，差不多像这样：",[14,15,20],"pre",{"className":16,"code":17,"language":18,"meta":19,"style":19},"language-glsl shiki shiki-themes github-light github-dark","#version 330 core\nstruct Material {\n    vec3 ambient;\n    vec3 diffuse;\n    vec3 specular;\n    float shininess;\n}; \n\nuniform Material material;\n","glsl","",[21,22,23,31,37,43,49,55,61,67,74],"code",{"__ignoreMap":19},[24,25,28],"span",{"class":26,"line":27},"line",1,[24,29,30],{},"#version 330 core\n",[24,32,34],{"class":26,"line":33},2,[24,35,36],{},"struct Material {\n",[24,38,40],{"class":26,"line":39},3,[24,41,42],{},"    vec3 ambient;\n",[24,44,46],{"class":26,"line":45},4,[24,47,48],{},"    vec3 diffuse;\n",[24,50,52],{"class":26,"line":51},5,[24,53,54],{},"    vec3 specular;\n",[24,56,58],{"class":26,"line":57},6,[24,59,60],{},"    float shininess;\n",[24,62,64],{"class":26,"line":63},7,[24,65,66],{},"}; \n",[24,68,70],{"class":26,"line":69},8,[24,71,73],{"emptyLinePlaceholder":72},true,"\n",[24,75,77],{"class":26,"line":76},9,[24,78,79],{},"uniform Material material;\n",[10,81,82],{},"分别是 环境光照、漫反射光照、镜面光照、反光度分量",[10,84,85,86,90,91,94,95,98],{},"在",[87,88,89],"strong",{},"片段着色器","中，我们",[87,92,93],{},"创建一个结构体(Struct)来储存物体的材质属性","。我们",[87,96,97],{},"也可以把它们储存为独立的uniform值","，但是作为一个结构体来储存会更有条理一些。我们首先定义结构体的布局(Layout)，然后简单地以刚创建的结构体作为类型声明一个uniform变量。",[10,100,101,102,105,106,109,110,113,114,117,118,121,122,125],{},"我们为风氏光照模型的",[87,103,104],{},"每个分量都定义一个颜色向量","。ambient材质向量",[87,107,108],{},"定义了在环境光照下这个表面反射的是什么颜色","，",[87,111,112],{},"通常与表面的颜色相同","。diffuse材质向量定义了在",[87,115,116],{},"漫反射光照下表面的颜色","。漫反射颜色（和环境光照一样）也被设置为我们期望的物体颜色。",[87,119,120],{},"specular材质向量设置的是表面上镜面高光的颜色","（或者甚至可能反映一个特定表面的颜色）。最后，",[87,123,124],{},"shininess影响镜面高光的散射\u002F半径","。",[10,127,128],{},[129,130],"img",{"alt":129,"src":131},".\u002Fassets\u002Fmaterials_real_world.png",[10,133,134],{},"我们可以从uniform变量material中访问它们：",[14,136,140],{"className":137,"code":138,"language":139,"meta":19,"style":19},"language-c++ shiki shiki-themes github-light github-dark","#version 330 core\nout vec4 FragColor;\n\nstruct Material{\n    vec3 ambient;\n    vec3 diffuse;\n    vec3 specular;\n    float shininess;\n};\n\nuniform vec3 lightColor;\nuniform vec3 lightPos;\nuniform vec3 viewPos;\nuniform Material material;\nin vec3 Normal;\nin vec3 FragPos;\n\nvoid main()\n{\n    vec3 ambient = lightColor * material.ambient;\n    \n    \u002F\u002F 漫反射\n    vec3 norm = normalize(Normal);\n    vec3 lightDir = normalize(lightPos - FragPos);\n    float diff = max(dot(norm, lightDir), 0.0);\n    vec3 diffuse = lightColor * (diff * material.diffuse);\n    \n    \u002F\u002F 镜面反射\n    vec3 viewDir = normalize(viewPos - FragPos);\n    vec3 reflectDir = reflect(-lightDir, norm);\n    float spec = pow(max(dot(viewDir, reflectDir), 0.0), material.shininess);\n    vec3 specular = lightColor * (spec * material.specular);\n    \n    \u002F\u002F 最终结果\n    vec3 result = ambient + diffuse + specular;\n    FragColor = vec4(result, 1.0);\n}\n\n","c++",[21,141,142,146,151,155,160,164,168,172,176,181,186,192,198,204,209,215,221,226,232,238,244,250,256,262,268,274,280,285,291,297,303,309,315,320,326,332,338],{"__ignoreMap":19},[24,143,144],{"class":26,"line":27},[24,145,30],{},[24,147,148],{"class":26,"line":33},[24,149,150],{},"out vec4 FragColor;\n",[24,152,153],{"class":26,"line":39},[24,154,73],{"emptyLinePlaceholder":72},[24,156,157],{"class":26,"line":45},[24,158,159],{},"struct Material{\n",[24,161,162],{"class":26,"line":51},[24,163,42],{},[24,165,166],{"class":26,"line":57},[24,167,48],{},[24,169,170],{"class":26,"line":63},[24,171,54],{},[24,173,174],{"class":26,"line":69},[24,175,60],{},[24,177,178],{"class":26,"line":76},[24,179,180],{},"};\n",[24,182,184],{"class":26,"line":183},10,[24,185,73],{"emptyLinePlaceholder":72},[24,187,189],{"class":26,"line":188},11,[24,190,191],{},"uniform vec3 lightColor;\n",[24,193,195],{"class":26,"line":194},12,[24,196,197],{},"uniform vec3 lightPos;\n",[24,199,201],{"class":26,"line":200},13,[24,202,203],{},"uniform vec3 viewPos;\n",[24,205,207],{"class":26,"line":206},14,[24,208,79],{},[24,210,212],{"class":26,"line":211},15,[24,213,214],{},"in vec3 Normal;\n",[24,216,218],{"class":26,"line":217},16,[24,219,220],{},"in vec3 FragPos;\n",[24,222,224],{"class":26,"line":223},17,[24,225,73],{"emptyLinePlaceholder":72},[24,227,229],{"class":26,"line":228},18,[24,230,231],{},"void main()\n",[24,233,235],{"class":26,"line":234},19,[24,236,237],{},"{\n",[24,239,241],{"class":26,"line":240},20,[24,242,243],{},"    vec3 ambient = lightColor * material.ambient;\n",[24,245,247],{"class":26,"line":246},21,[24,248,249],{},"    \n",[24,251,253],{"class":26,"line":252},22,[24,254,255],{},"    \u002F\u002F 漫反射\n",[24,257,259],{"class":26,"line":258},23,[24,260,261],{},"    vec3 norm = normalize(Normal);\n",[24,263,265],{"class":26,"line":264},24,[24,266,267],{},"    vec3 lightDir = normalize(lightPos - FragPos);\n",[24,269,271],{"class":26,"line":270},25,[24,272,273],{},"    float diff = max(dot(norm, lightDir), 0.0);\n",[24,275,277],{"class":26,"line":276},26,[24,278,279],{},"    vec3 diffuse = lightColor * (diff * material.diffuse);\n",[24,281,283],{"class":26,"line":282},27,[24,284,249],{},[24,286,288],{"class":26,"line":287},28,[24,289,290],{},"    \u002F\u002F 镜面反射\n",[24,292,294],{"class":26,"line":293},29,[24,295,296],{},"    vec3 viewDir = normalize(viewPos - FragPos);\n",[24,298,300],{"class":26,"line":299},30,[24,301,302],{},"    vec3 reflectDir = reflect(-lightDir, norm);\n",[24,304,306],{"class":26,"line":305},31,[24,307,308],{},"    float spec = pow(max(dot(viewDir, reflectDir), 0.0), material.shininess);\n",[24,310,312],{"class":26,"line":311},32,[24,313,314],{},"    vec3 specular = lightColor * (spec * material.specular);\n",[24,316,318],{"class":26,"line":317},33,[24,319,249],{},[24,321,323],{"class":26,"line":322},34,[24,324,325],{},"    \u002F\u002F 最终结果\n",[24,327,329],{"class":26,"line":328},35,[24,330,331],{},"    vec3 result = ambient + diffuse + specular;\n",[24,333,335],{"class":26,"line":334},36,[24,336,337],{},"    FragColor = vec4(result, 1.0);\n",[24,339,341],{"class":26,"line":340},37,[24,342,343],{},"}\n",[10,345,346,347,350],{},"可以看到，我们现在",[87,348,349],{},"在需要的地方访问了材质结构体中的所有属性","，并且这次是根据材质的颜色来计算最终的输出颜色的。物体的每个材质属性都乘上了它们各自对应的光照分量。",[10,352,353,354,357],{},"我们现在可以",[87,355,356],{},"通过设置适当的uniform来设置应用中物体的材质了","。GLSL中一个结构体在设置uniform时并无任何区别，结构体只是充当uniform变量们的一个命名空间。所以如果想填充这个结构体的话，我们必须设置每个单独的uniform，但要以结构体名为前缀：",[10,359,360],{},"然后我们去给unifrom去赋值，这样就可以看到效果了：",[14,362,364],{"className":137,"code":363,"language":139,"meta":19,"style":19},"        \u002F\u002F 使用光照着色器绘制物体\n        lightingShader.use();\n        lightingShader.setMat4(\"projection\", projection);\n        lightingShader.setMat4(\"view\", view);\n        lightingShader.setMat4(\"model\", model);\n        lightingShader.setVec3(\"lightColor\", 1.0f, 1.0f, 1.0f);   \u002F\u002F 白色光源\n        lightingShader.setVec3(\"lightPos\", lightPos.x, lightPos.y, lightPos.z);\n        lightingShader.setVec3(\"material.ambient\", 1.0f, 0.5f, 0.31f);\n        lightingShader.setVec3(\"material.diffuse\", 1.0f, 0.5f, 0.31f);\n        lightingShader.setVec3(\"material.specular\", 1.0f, 1.0f, 1.0f);\n        lightingShader.setFloat(\"material.shininess\", 32.0f);\n",[21,365,366,371,376,381,386,391,396,401,406,411,416],{"__ignoreMap":19},[24,367,368],{"class":26,"line":27},[24,369,370],{},"        \u002F\u002F 使用光照着色器绘制物体\n",[24,372,373],{"class":26,"line":33},[24,374,375],{},"        lightingShader.use();\n",[24,377,378],{"class":26,"line":39},[24,379,380],{},"        lightingShader.setMat4(\"projection\", projection);\n",[24,382,383],{"class":26,"line":45},[24,384,385],{},"        lightingShader.setMat4(\"view\", view);\n",[24,387,388],{"class":26,"line":51},[24,389,390],{},"        lightingShader.setMat4(\"model\", model);\n",[24,392,393],{"class":26,"line":57},[24,394,395],{},"        lightingShader.setVec3(\"lightColor\", 1.0f, 1.0f, 1.0f);   \u002F\u002F 白色光源\n",[24,397,398],{"class":26,"line":63},[24,399,400],{},"        lightingShader.setVec3(\"lightPos\", lightPos.x, lightPos.y, lightPos.z);\n",[24,402,403],{"class":26,"line":69},[24,404,405],{},"        lightingShader.setVec3(\"material.ambient\", 1.0f, 0.5f, 0.31f);\n",[24,407,408],{"class":26,"line":76},[24,409,410],{},"        lightingShader.setVec3(\"material.diffuse\", 1.0f, 0.5f, 0.31f);\n",[24,412,413],{"class":26,"line":183},[24,414,415],{},"        lightingShader.setVec3(\"material.specular\", 1.0f, 1.0f, 1.0f);\n",[24,417,418],{"class":26,"line":188},[24,419,420],{},"        lightingShader.setFloat(\"material.shininess\", 32.0f);\n",[10,422,423],{},[129,424],{"alt":129,"src":425},".\u002Fassets\u002Fmaterials_with_material.png",[10,427,428],{},"效果如上，但这个真的非常的亮眼，因为环境光、漫反射、镜面光三个颜色对任何一个光源都是全力反射，光源对环境光和镜面光分量有不同的强度。",[10,430,431,432,435,436,439],{},"我们可以",[87,433,434],{},"为每个光照指定一个强度向量","，如果我们假设lightColor是",[21,437,438],{},"vec3(1.0)","，代码会看起来像这样：",[14,441,443],{"className":16,"code":442,"language":18,"meta":19,"style":19},"vec3 ambient  = vec3(1.0) * material.ambient;\nvec3 diffuse  = vec3(1.0) * (diff * material.diffuse);\nvec3 specular = vec3(1.0) * (spec * material.specular);\n",[21,444,445,450,455],{"__ignoreMap":19},[24,446,447],{"class":26,"line":27},[24,448,449],{},"vec3 ambient  = vec3(1.0) * material.ambient;\n",[24,451,452],{"class":26,"line":33},[24,453,454],{},"vec3 diffuse  = vec3(1.0) * (diff * material.diffuse);\n",[24,456,457],{"class":26,"line":39},[24,458,459],{},"vec3 specular = vec3(1.0) * (spec * material.specular);\n",[10,461,462,463,466,467,469,470,473],{},"所以物体的",[87,464,465],{},"每个材质属性对每一个光照分量都返回了最大的强度","。对单个光源来说，这些",[21,468,438],{},"值同样可以对每种光源分别改变，而这通常就是我们想要的。现在，物体的环境光分量完全地影响了立方体的颜色，可是环境光分量实际上不应该对最终的颜色有这么大的影响，",[87,471,472],{},"所以我们会将光源的环境光强度设置为一个小一点的值，从而限制环境光颜色","：",[14,475,477],{"className":16,"code":476,"language":18,"meta":19,"style":19},"vec3 ambient = vec3(0.1) * material.ambient;\n",[21,478,479],{"__ignoreMap":19},[24,480,481],{"class":26,"line":27},[24,482,476],{},[10,484,485,486,492,493,496,497,473],{},"我们可以用同样的方式影响光源的漫反射和镜面光强度。这和我们在[上一节](",[487,488,489],"a",{"href":489,"rel":490},"https:\u002F\u002Flearnopengl-cn.github.io\u002F02",[491],"nofollow"," Lighting\u002F02 Basic Lighting\u002F)中所做的极为相似，你可以认为我们已经",[87,494,495],{},"创建了一些光照属性来影响各个光照分量","。我们希望",[87,498,499],{},"为光照属性创建类似材质结构体的东西",[14,501,503],{"className":16,"code":502,"language":18,"meta":19,"style":19},"struct Light {\n    vec3 position;\n\n    vec3 ambient;\n    vec3 diffuse;\n    vec3 specular;\n};\n\nuniform Light light;\n",[21,504,505,510,515,519,523,527,531,535,539],{"__ignoreMap":19},[24,506,507],{"class":26,"line":27},[24,508,509],{},"struct Light {\n",[24,511,512],{"class":26,"line":33},[24,513,514],{},"    vec3 position;\n",[24,516,517],{"class":26,"line":39},[24,518,73],{"emptyLinePlaceholder":72},[24,520,521],{"class":26,"line":45},[24,522,42],{},[24,524,525],{"class":26,"line":51},[24,526,48],{},[24,528,529],{"class":26,"line":57},[24,530,54],{},[24,532,533],{"class":26,"line":63},[24,534,180],{},[24,536,537],{"class":26,"line":69},[24,538,73],{"emptyLinePlaceholder":72},[24,540,541],{"class":26,"line":76},[24,542,543],{},"uniform Light light;\n",[10,545,546,549,550,553,554,557,558,560,561,125],{},[87,547,548],{},"一个光源对它的ambient、diffuse和specular光照分量有着不同的强度","。环境光照通常",[87,551,552],{},"被设置为一个比较低的强度","，因为我们不希望环境光颜色太过主导。",[87,555,556],{},"光源的漫反射分量通常被设置为我们希望光所具有的那个颜色","，通常是一个比较明亮的白色。镜面光分量通常会保持为",[21,559,438],{},"，以最大强度发光。注意我们也",[87,562,563],{},"将光源的位置向量加入了结构体",[10,565,566],{},[87,567,568],{},"和材质uniform一样，我们需要更新片段着色器：",[14,570,572],{"className":16,"code":571,"language":18,"meta":19,"style":19},"vec3 ambient  = light.ambient * material.ambient;\nvec3 diffuse  = light.diffuse * (diff * material.diffuse);\nvec3 specular = light.specular * (spec * material.specular);\n",[21,573,574,579,584],{"__ignoreMap":19},[24,575,576],{"class":26,"line":27},[24,577,578],{},"vec3 ambient  = light.ambient * material.ambient;\n",[24,580,581],{"class":26,"line":33},[24,582,583],{},"vec3 diffuse  = light.diffuse * (diff * material.diffuse);\n",[24,585,586],{"class":26,"line":39},[24,587,588],{},"vec3 specular = light.specular * (spec * material.specular);\n",[10,590,591],{},"这样的话我们就不需要LightColor了，大致改动会变成这样：",[14,593,595],{"className":137,"code":594,"language":139,"meta":19,"style":19},"        \u002F\u002F 使用光照着色器绘制物体\n        lightingShader.use();\n        lightingShader.setMat4(\"projection\", projection);\n        lightingShader.setMat4(\"view\", view);\n        lightingShader.setMat4(\"model\", model);\n        lightingShader.setVec3(\"lightPos\", lightPos.x, lightPos.y, lightPos.z);\n        lightingShader.setVec3(\"light.ambient\",  0.2f, 0.2f, 0.2f);\n        lightingShader.setVec3(\"light.diffuse\",  0.5f, 0.5f, 0.5f);\n        lightingShader.setVec3(\"light.specular\", 1.0f, 1.0f, 1.0f); \n        lightingShader.setVec3(\"material.ambient\", 1.0f, 0.5f, 0.31f);\n        lightingShader.setVec3(\"material.diffuse\", 1.0f, 0.5f, 0.31f);\n        lightingShader.setVec3(\"material.specular\", 1.0f, 1.0f, 1.0f);\n        lightingShader.setFloat(\"material.shininess\", 32.0f);\n",[21,596,597,601,605,609,613,617,621,626,631,636,640,644,648],{"__ignoreMap":19},[24,598,599],{"class":26,"line":27},[24,600,370],{},[24,602,603],{"class":26,"line":33},[24,604,375],{},[24,606,607],{"class":26,"line":39},[24,608,380],{},[24,610,611],{"class":26,"line":45},[24,612,385],{},[24,614,615],{"class":26,"line":51},[24,616,390],{},[24,618,619],{"class":26,"line":57},[24,620,400],{},[24,622,623],{"class":26,"line":63},[24,624,625],{},"        lightingShader.setVec3(\"light.ambient\",  0.2f, 0.2f, 0.2f);\n",[24,627,628],{"class":26,"line":69},[24,629,630],{},"        lightingShader.setVec3(\"light.diffuse\",  0.5f, 0.5f, 0.5f);\n",[24,632,633],{"class":26,"line":76},[24,634,635],{},"        lightingShader.setVec3(\"light.specular\", 1.0f, 1.0f, 1.0f); \n",[24,637,638],{"class":26,"line":183},[24,639,405],{},[24,641,642],{"class":26,"line":188},[24,643,410],{},[24,645,646],{"class":26,"line":194},[24,647,415],{},[24,649,650],{"class":26,"line":200},[24,651,420],{},[653,654,655],"h2",{"id":655},"不同的光源颜色",[10,657,658,659,662],{},"到目前为止，",[87,660,661],{},"我们都只对光源设置了从白到灰到黑范围内的颜色","，这样只会改变物体各个分量的强度，而不是它的真正颜色。由于现在能够非常容易地访问光照的属性了，我们可以随着时间改变它们的颜色，从而获得一些非常有意思的效果。由于所有的东西都在片段着色器中配置好了，修改光源的颜色非常简单，并立刻创造一些很有趣的效果：",[14,664,668],{"className":665,"code":666,"language":667,"meta":19,"style":19},"language-csharp shiki shiki-themes github-light github-dark","glm::vec3 lightColor;\nlightColor.x = sin(glfwGetTime() * 2.0f);\nlightColor.y = sin(glfwGetTime() * 0.7f);\nlightColor.z = sin(glfwGetTime() * 1.3f);\n\nglm::vec3 diffuseColor = lightColor   * glm::vec3(0.5f); \u002F\u002F 降低影响\nglm::vec3 ambientColor = diffuseColor * glm::vec3(0.2f); \u002F\u002F 很低的影响\n\nlightingShader.setVec3(\"light.ambient\", ambientColor);\nlightingShader.setVec3(\"light.diffuse\", diffuseColor);\n","csharp",[21,669,670,675,680,685,690,694,699,704,708,713],{"__ignoreMap":19},[24,671,672],{"class":26,"line":27},[24,673,674],{},"glm::vec3 lightColor;\n",[24,676,677],{"class":26,"line":33},[24,678,679],{},"lightColor.x = sin(glfwGetTime() * 2.0f);\n",[24,681,682],{"class":26,"line":39},[24,683,684],{},"lightColor.y = sin(glfwGetTime() * 0.7f);\n",[24,686,687],{"class":26,"line":45},[24,688,689],{},"lightColor.z = sin(glfwGetTime() * 1.3f);\n",[24,691,692],{"class":26,"line":51},[24,693,73],{"emptyLinePlaceholder":72},[24,695,696],{"class":26,"line":57},[24,697,698],{},"glm::vec3 diffuseColor = lightColor   * glm::vec3(0.5f); \u002F\u002F 降低影响\n",[24,700,701],{"class":26,"line":63},[24,702,703],{},"glm::vec3 ambientColor = diffuseColor * glm::vec3(0.2f); \u002F\u002F 很低的影响\n",[24,705,706],{"class":26,"line":69},[24,707,73],{"emptyLinePlaceholder":72},[24,709,710],{"class":26,"line":76},[24,711,712],{},"lightingShader.setVec3(\"light.ambient\", ambientColor);\n",[24,714,715],{"class":26,"line":183},[24,716,717],{},"lightingShader.setVec3(\"light.diffuse\", diffuseColor);\n",[719,720,721],"style",{},"html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}",{"title":19,"searchDepth":33,"depth":33,"links":723},[724],{"id":655,"depth":33,"text":655},"md",{},"\u002Fcpp\u002Fopengel\u002F材质",{"description":12},"cpp\u002Fopengel\u002F材质","wKWhOET6GFXN-0R6fxiNDAesLMWndgywUSrwkCl28as",1791042463572]