ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

《HarmonyOS 7 ArkGraphics 3D 空间设计开发实战》04:材质、纹理与灯光如何决定3D场景质感【鸿蒙心迹】

《HarmonyOS 7 ArkGraphics 3D 空间设计开发实战》04:材质、纹理与灯光如何决定3D场景质感【鸿蒙心迹】 东西都放好了为什么看起来像塑料前言前几篇把工程骨架、坐标体系、模型加载都搞定了。房间里有桌子、椅子、沙发、台灯结构上看起来像那么回事了。但跑起来一看总觉得哪里不对东西都有就是看起来特别假像塑料玩具。我一开始以为是模型质量不好换了几个模型还是一样。后来调了半天灯光才发现问题不在模型也不在灯光而是材质和灯光配合的方式不对。3D 渲染里有个基本常识你看到的颜色不是物体本身的颜色而是物体表面反射出来的光。材质决定了表面怎么反射光灯光决定了有多少光打在表面上。这两个东西是配合工作的单独调哪个都没用。这一篇就解决这个问题为什么同一个沙发模型别人做出来像真的布料我做出来像塑料材质、纹理、灯光之间到底是怎么配合的。一、先搞清楚你看到的颜色是怎么来的很多人刚开始做 3D 的时候以为材质就是给物体上个色沙发是灰色的桌子是木色的墙是白色的。但真实的渲染不是这么回事。打个比方晚上关灯的时候你看不到任何东西不是因为物体没有颜色是没有光用红色灯光照白墙墙就变成红色的粗糙的墙看起来是哑光的光滑的金属看起来是亮的这就是材质和灯光配合的结果。材质描述的是这个表面怎么反射光不是这个表面是什么颜色。先把基础概念列清楚概念作用举个例子漫反射Diffuse光线打到表面后向各个方向反射墙面、布料看起来哑光高光Specular光线像镜子一样反射出去金属、玻璃有亮斑粗糙度Roughness表面有多粗糙粗糙的漫反射多光滑的高光强环境光Ambient整个场景的基础亮度阴影里也不会全黑主光源Key Light主要的照明方向太阳、主台灯很多初学者只加一个方向光强度拉满结果整个场景平得像一张纸没有明暗层次。就是因为只考虑了主光源没考虑环境光和材质的反射特性。二、第一版只有颜色的材质先写第一版的材质设置看看为什么看起来像塑料import{scene}fromkit.ArkGraphics3DKit;exportclassMaterialManager{/** * 给家具设置基础材质 */setupBasicMaterial(node:scene.Node,color:{r:number,g:number,b:number}):void{constmaterialnode.createComponent(scene.NodeComponentType.MATERIAL)asscene.Material;// 只设置了基础颜色material.albedocolor;console.info(MaterialManager: basic material set,color);}}然后调用它// 沙发设成灰色materialMgr.setupBasicMaterial(sofaNode,{r:0.6,g:0.6,b:0.6});// 桌子设成木色materialMgr.setupBasicMaterial(deskNode,{r:0.5,g:0.35,b:0.2});这个代码跑起来东西是有颜色的但看起来就是塑料感。为什么因为只有漫反射颜色没有粗糙度没有高光没有纹理。所有东西都像塑料球一样表面光滑均匀。这就是塑料感的来源表面太完美了没有任何细节没有粗糙度变化没有纹理。三、加纹理和粗糙度马上就不一样了改进一下给材质加上纹理和粗糙度参数。exportclassMaterialManager{/** * 设置布料材质 */setupFabricMaterial(node:scene.Node,texturePath:string):void{constmaterialnode.createComponent(scene.NodeComponentType.MATERIAL)asscene.Material;// 基础颜色material.albedo{r:0.6,g:0.6,b:0.6};// 加载纹理贴图material.loadAlbedoTexture(texturePath);// 布料是粗糙的粗糙度设高一点material.roughness0.8;// 布料没有金属感金属度设0material.metallic0.0;console.info(MaterialManager: fabric material set);}/** * 设置木质材质 */setupWoodMaterial(node:scene.Node,texturePath:string):void{constmaterialnode.createComponent(scene.NodeComponentType.MATERIAL)asscene.Material;material.albedo{r:0.5,g:0.35,b:0.2};material.loadAlbedoTexture(texturePath);// 木头有一点光泽但不是金属material.roughness0.6;material.metallic0.0;console.info(MaterialManager: wood material set);}/** * 设置金属材质 */setupMetalMaterial(node:scene.Node):void{constmaterialnode.createComponent(scene.NodeComponentType.MATERIAL)asscene.Material;material.albedo{r:0.8,g:0.8,b:0.8};// 金属很光滑金属度高material.roughness0.2;material.metallic0.9;console.info(MaterialManager: metal material set);}}现在沙发是布料材质粗糙度 0.8看起来就哑光了桌子是木头粗糙度 0.6有一点自然的光泽台灯支架是金属粗糙度 0.2高光就出来了。这时候再看场景塑料感就少了很多。因为不同材质有不同的反射特性不再是所有东西都一个样子。四、灯光不是越多越好材质调好了接下来调灯光。很多人以为灯光越多越亮越好结果加了五六个方向光场景更假了。灯光太多有两个问题所有阴影都被照亮了没有明暗层次像个白板渲染性能下降每个光源都要算一遍光照正确的做法是分层次布光灯光类型作用数量例子主光源Key Light主要照明决定方向和阴影1个从窗户照进来的自然光补光Fill Light照亮阴影区域不要全黑1个环境反射的光轮廓光Rim Light从背后打光突出物体边缘可选让物体从背景里分离出来环境光Ambient整体基础亮度1个天空和地面反射的环境光写个 LightManagerexportclassLightManager{setupSceneLights(scene:scene.Scene):void{// 1. 主光源从斜上方照下来constkeyLightscene.createNode(KeyLight);constkeyLightCompkeyLight.createComponent(scene.NodeComponentType.LIGHT)asscene.Light;keyLightComp.lightTypescene.LightType.DIRECTIONAL;keyLightComp.intensity1.2;// 主光源最亮keyLight.position{x:5,y:8,z:3};keyLight.rotation{x:-45,y:30,z:0};scene.getRoot().addChild(keyLight);// 2. 补光从另一侧补一点constfillLightscene.createNode(FillLight);constfillLightCompfillLight.createComponent(scene.NodeComponentType.LIGHT)asscene.Light;fillLightComp.lightTypescene.LightType.DIRECTIONAL;fillLightComp.intensity0.4;// 补光弱一点fillLight.position{x:-3,y:4,z:-2};scene.getRoot().addChild(fillLight);// 3. 环境光整体基础亮度constambientLightscene.createNode(AmbientLight);constambientCompambientLight.createComponent(scene.NodeComponentType.LIGHT)asscene.Light;ambientComp.lightTypescene.LightType.AMBIENT;ambientComp.intensity0.3;// 环境光不要太亮不然阴影没了scene.getRoot().addChild(ambientLight);console.info(LightManager: 3 lights setup done);}}主光源 1.2补光 0.4环境光 0.3。这个比例大概能做出自然的明暗层次主光面亮背光面有补光不会全黑环境光保证最暗的地方也能看到细节。五、做几个预设模式日间、暖光、展示真实应用里用户可能想要不同的灯光氛围白天模式、晚上暖光模式、展示模式。做一个 SceneThemeManager提供几个预设exportclassSceneThemeManager{// 日间模式applyDaylight(scene:scene.Scene):void{// 冷色调亮度高this.setLightColor(scene,{r:1.0,g:1.0,b:1.0});this.setLightIntensity(scene,{key:1.5,fill:0.5,ambient:0.4});}// 暖光模式晚上applyWarmLight(scene:scene.Scene):void{// 暖黄色亮度低this.setLightColor(scene,{r:1.0,g:0.9,b:0.7});this.setLightIntensity(scene,{key:0.8,fill:0.3,ambient:0.2});}// 展示模式产品展示用applyShowcase(scene:scene.Scene):void{// 均匀照亮突出产品this.setLightColor(scene,{r:1.0,g:1.0,b:1.0});this.setLightIntensity(scene,{key:1.0,fill:0.8,ambient:0.5});}}这样用户可以一键切换场景氛围不用手动调每个灯光参数。六、几个最容易踩的质感坑把这一篇遇到的坑总结一下坑现象解决办法只有基础颜色没有粗糙度所有东西都像塑料不同材质设不同粗糙度布料高、金属低灯光越多越好场景平得像白板没有阴影分层布光1主光1补光1环境光就够环境光太亮阴影全没了没有立体感环境光别太亮0.2~0.4差不多纹理分辨率太高内存涨加载慢家具纹理不用4K1024足够白色家具高光过曝白家具一块死白降低曝光或者把粗糙度调高一点所有材质都一个样整个场景材质没有区分布料、木头、金属、玻璃分别设参数这些问题都不是 API 用错了是对材质灯光怎么配合没有概念。3D 渲染本质上是在模拟物理世界的光传播不是简单地给物体上个颜色。总结第四篇的核心就一句话质感不是靠模型好是靠材质和灯光配合出来的。材质描述的是表面怎么反射光不是表面是什么颜色不同材质布料、木头、金属有不同的粗糙度和金属度质感就不一样灯光不是越多越好分层布光主光补光环境光就够了可以做几个灯光预设模式让用户一键切换氛围塑料感通常是因为所有材质都一样光滑加上灯光太平SpaceRoom 现在看起来像个真实房间了。下一篇开始做交互让用户能拖动视角、缩放、平移真正走进这个 3D 房间里看看。
返回列表