Cg Programming/Unity/Translucent Bodies半透明体

2024-03-11 09:08

本文主要是介绍Cg Programming/Unity/Translucent Bodies半透明体,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

本教程涵盖了半透明体。

这是几个关于光照教程中的其中之一,这个光照超出了Phone反射模型的范围。但是,它是基于章节“光滑镜面高光”中描述的用Phone反射模型实现的逐像素光照。如果你没阅读过那章,建议先阅读一下。

蜡质效果

这里写图片描述
不幸的是,在实时游戏引擎中,光线在半透明体中的传输是相当大的挑战。从光源的视点渲染一张深度图可能会有用,但这已不在本章的范围。因此,我们将会伪造一些次表面的效果。

第一种效果被称为“蜡质”,它描述了蜡的光滑、有光泽的外观,缺乏漫反射能提供的硬对比。理论上,我们在计算漫反射(但不是镜面反射)之前会平滑法线向量,并且实际上使用法线贴图还是有可能的。但是,这里采用另一种方法。为了柔化漫反射的由max(0, N·L)(参考章节“漫反射”)这项造成的硬对比,我们把蜡质w从0增加到1来减少这项的影响。更具体地说,我们会用1- w去乘以max(0, N·L)这项。但是,这样不只是会减弱硬对比还会减弱整个照明的亮度。为了避免这种情况,由于次表面散射我们添加蜡质w来伪造额外的灯光,这是更强大的“蜡质”材质。

于是,我们把漫反射等式
这里写图片描述
替换成这个等式:
这里写图片描述

蜡质w介于0(也就是正规的漫反射)到1(也就是不依赖于N·L)之间。

这个方法实现起来很简单,对GPU来说容易计算,容易控制,并且它确实像蜡和玉的样子,特别是它跟有高光的镜面高光结合起来的时候。

背光的半透明

这里写图片描述

这里写图片描述
我们要伪造的第二种效果就是背光,它穿透一个物体并且在物体可见的前面出去。这种效果越强烈,背面和前面的距离就越近,也就是特别在轮廓处,背面和前面的距离实际上变成了0.因此,我们可以使用章节“轮廓增强”中讨论过的技术来轮廓处生成更多的光照。但是,如果我们把一个封闭网格的背面的实际漫射照明考虑进来的话,这个效果就会更有说服力。最后,我们这样做:

  • 我们只渲染背面,然后用一个描述点(在背面)距离轮廓多远的加权因子来计算漫反射。我们用不透明度为0来标记这个像素。(通常在帧缓冲中的像素不透明度为1。通过设置它们的不透明度为0来标记像素的技术是基于在后面通道中的混合方程中的帧缓冲中使用alpha值的可能性;参考章节“透明度”。)
  • 我们只渲染正面,然后把所有不透明度为1的像素的颜色设置为黑色(也就是我们在第一步中没有被光栅化的所有像素)。当另一个物体跟网格相交时,这是必要的。
  • 我们用来自正面的光照再次渲染正面,并且把帧缓冲中的颜色乘以描述点(在正面)距离轮廓有多远的系数。在第一和第三步中,我们使用轮廓系数1 - | N·L |,它在轮廓处的值为1并且在观察者直视表面时值为0。(可以引入点积的指数来允许更多的艺术控制。)于是,所有的计算实际上就相当简单了。最复杂的部分就是混合。

实现

The implementation relies heavily on blending, which is discussed in Section “Transparency”. In addition to three passes corresponding to the steps mentioned above, we also need two more additional passes for additional light sources on the back and the front. With so many passes, it makes sense to get a clear idea of what the render passes are supposed to do. To this end, a skeleton of the shader without the Cg code is very helpful:
这个实现严重依赖于混合,它在章节“透明度”中有过讨论。除了上面提到的步骤对应的三个通道以外,我们也需要为在背面和正面的额外光源准备两个额外的通道。有了这么多通道,我们对于渲染通道应该做什么有了一个清晰的认识。最后,没有Cg代码的着色器框架是很有用的:

Shader "Cg translucent bodies" {Properties {_Color ("Diffuse Color", Color) = (1,1,1,1) _Waxiness ("Waxiness", Range(0,1)) = 0_SpecColor ("Specular Color", Color) = (1,1,1,1) _Shininess ("Shininess", Float) = 10_TranslucentColor ("Translucent Color", Color) = (0,0,0,1)}SubShader {Pass {      Tags { "LightMode" = "ForwardBase" } // pass for // ambient light and first light source on back facesCull Front // render back faces onlyBlend One Zero // mark rasterized pixels in framebuffer // with alpha = 0 (usually they have alpha = 1)CGPROGRAM[...]ENDCG}Pass {      Tags { "LightMode" = "ForwardAdd" } // pass for additional light sources on back facesCull Front // render back faces onlyBlend One One // additive blending CGPROGRAM[...]ENDCG}Pass {    Tags { "LightMode" = "ForwardBase" } // pass for // setting pixels that were not rasterized to blackCull Back // render front faces only (default behavior)Blend Zero OneMinusDstAlpha // set colors of pixels // with alpha = 1 to black by multiplying with 1-alphaCGPROGRAM#pragma vertex vert #pragma fragment fragfloat4 vert(float4 vertexPos : POSITION) : SV_POSITION {return mul(UNITY_MATRIX_MVP, vertexPos);}float4 frag(void) : COLOR {return float4(0.0, 0.0, 0.0, 0.0); }ENDCG  }Pass {      Tags { "LightMode" = "ForwardBase" } // pass for // ambient light and first light source on front facesCull Back // render front faces onlyBlend One SrcAlpha // multiply color in framebuffer // with silhouetteness in fragment's alpha and add colorsCGPROGRAM[...]ENDCG }Pass {      Tags { "LightMode" = "ForwardAdd" } // pass for additional light sources on front facesCull Back // render front faces onlyBlend One One // additive blending CGPROGRAM[...]ENDCG }} Fallback "Specular"
}

这个框架还是相当长的;但是,它提供给我们一个完整着色器是怎么组织的好想法。

完整的着色器代码

在以下的完整着色器代码中,请注意替换_Color的属性_TranslucentColor被用在背面漫射和环境部分的计算中。也要注意“轮廓”是如何跟在正面一样在背面计算的。但是,它只是直接地跟背面的片段颜色相乘。在正面,它只是间接地跟片段颜色的alpha分量相乘,并且把alpha跟最终颜色(在帧缓冲中像素的颜色)进行混合。最终,这个“蜡质”只是被用在正面的漫反射中。

Shader "Cg translucent bodies" {Properties {_Color ("Diffuse Color", Color) = (1,1,1,1) _Waxiness ("Waxiness", Range(0,1)) = 0_SpecColor ("Specular Color", Color) = (1,1,1,1) _Shininess ("Shininess", Float) = 10_TranslucentColor ("Translucent Color", Color) = (0,0,0,1)}SubShader {Pass {      Tags { "LightMode" = "ForwardBase" } // pass for // ambient light and first light source on back facesCull Front // render back faces onlyBlend One Zero // mark rasterized pixels in framebuffer // with alpha = 0 (usually they should have alpha = 1)CGPROGRAM#pragma vertex vert  #pragma fragment frag #include "UnityCG.cginc"uniform float4 _LightColor0; // color of light source (from "Lighting.cginc")// User-specified propertiesuniform float4 _Color; uniform float _Waxiness;uniform float4 _SpecColor; uniform float _Shininess;uniform float4 _TranslucentColor; struct vertexInput {float4 vertex : POSITION;float3 normal : NORMAL;};struct vertexOutput {float4 pos : SV_POSITION;float4 posWorld : TEXCOORD0;float3 normalDir : TEXCOORD1;};vertexOutput vert(vertexInput input) {vertexOutput output;float4x4 modelMatrix = _Object2World;float4x4 modelMatrixInverse = _World2Object; output.posWorld = mul(modelMatrix, input.vertex);output.normalDir = normalize(mul(float4(input.normal, 0.0), modelMatrixInverse).xyz);output.pos = mul(UNITY_MATRIX_MVP, input.vertex);return output;}float4 frag(vertexOutput input) : COLOR{float3 normalDirection = normalize(input.normalDir);float3 viewDirection = normalize(_WorldSpaceCameraPos - input.posWorld.xyz);float3 lightDirection;float attenuation;if (0.0 == _WorldSpaceLightPos0.w) // directional light?{attenuation = 1.0; // no attenuationlightDirection = normalize(_WorldSpaceLightPos0.xyz);} else // point or spot light{float3 vertexToLightSource = _WorldSpaceLightPos0.xyz - input.posWorld.xyz;float distance = length(vertexToLightSource);attenuation = 1.0 / distance; // linear attenuation lightDirection = normalize(vertexToLightSource);}float3 ambientLighting = _TranslucentColor.rgb* UNITY_LIGHTMODEL_AMBIENT.rgb;float3 diffuseReflection = _TranslucentColor.rgb* attenuation * _LightColor0.rgb* max(0.0, dot(normalDirection, lightDirection));float silhouetteness = 1.0 - abs(dot(viewDirection, normalDirection));return float4(silhouetteness * (ambientLighting + diffuseReflection), 0.0);}ENDCG}Pass {      Tags { "LightMode" = "ForwardAdd" } // pass for additional light sources on back facesCull Front // render back faces onlyBlend One One // additive blending CGPROGRAM#pragma vertex vert  #pragma fragment frag #include "UnityCG.cginc"uniform float4 _LightColor0; // color of light source (from "Lighting.cginc")// User-specified propertiesuniform float4 _Color; uniform float _Waxiness;uniform float4 _SpecColor; uniform float _Shininess;uniform float4 _TranslucentColor; struct vertexInput {float4 vertex : POSITION;float3 normal : NORMAL;};struct vertexOutput {float4 pos : SV_POSITION;float4 posWorld : TEXCOORD0;float3 normalDir : TEXCOORD1;};vertexOutput vert(vertexInput input) {vertexOutput output;float4x4 modelMatrix = _Object2World;float4x4 modelMatrixInverse = _World2Object;output.posWorld = mul(modelMatrix, input.vertex);output.normalDir = normalize(mul(float4(input.normal, 0.0), modelMatrixInverse).xyz);output.pos = mul(UNITY_MATRIX_MVP, input.vertex);return output;}float4 frag(vertexOutput input) : COLOR{float3 normalDirection = normalize(input.normalDir);float3 viewDirection = normalize(_WorldSpaceCameraPos - input.posWorld.xyz);float3 lightDirection;float attenuation;if (0.0 == _WorldSpaceLightPos0.w) // directional light?{attenuation = 1.0; // no attenuationlightDirection = normalize(_WorldSpaceLightPos0.xyz);} else // point or spot light{float3 vertexToLightSource = _WorldSpaceLightPos0.xyz - input.posWorld.xyz;float distance = length(vertexToLightSource);attenuation = 1.0 / distance; // linear attenuation lightDirection = normalize(vertexToLightSource);}float3 diffuseReflection = _TranslucentColor.rgb* attenuation * _LightColor0.rgb* max(0.0, dot(normalDirection, lightDirection));float silhouetteness = 1.0 - abs(dot(viewDirection, normalDirection));return float4(silhouetteness * diffuseReflection, 0.0);}ENDCG}Pass {    Tags { "LightMode" = "ForwardBase" } // pass for // setting pixels that were not rasterized to blackCull Back // render front faces only (default behavior)Blend Zero OneMinusDstAlpha // set colors of pixels // with alpha = 1 to black by multiplying with 1-alphaCGPROGRAM #pragma vertex vert #pragma fragment fragfloat4 vert(float4 vertexPos : POSITION) : SV_POSITION {return mul(UNITY_MATRIX_MVP, vertexPos);}float4 frag(void) : COLOR {return float4(0.0, 0.0, 0.0, 0.0); }ENDCG  }Pass {      Tags { "LightMode" = "ForwardBase" } // pass for // ambient light and first light source on front facesCull Back // render front faces onlyBlend One SrcAlpha // multiply color in framebuffer // with silhouetteness in fragment's alpha and add colorsCGPROGRAM#pragma vertex vert  #pragma fragment frag #include "UnityCG.cginc"uniform float4 _LightColor0; // color of light source (from "Lighting.cginc")// User-specified propertiesuniform float4 _Color; uniform float _Waxiness;uniform float4 _SpecColor; uniform float _Shininess;uniform float4 _TranslucentColor; struct vertexInput {float4 vertex : POSITION;float3 normal : NORMAL;};struct vertexOutput {float4 pos : SV_POSITION;float4 posWorld : TEXCOORD0;float3 normalDir : TEXCOORD1;};vertexOutput vert(vertexInput input) {vertexOutput output;float4x4 modelMatrix = _Object2World;float4x4 modelMatrixInverse = _World2Object;output.posWorld = mul(modelMatrix, input.vertex);output.normalDir = normalize(mul(float4(input.normal, 0.0), modelMatrixInverse).xyz);output.pos = mul(UNITY_MATRIX_MVP, input.vertex);return output;}float4 frag(vertexOutput input) : COLOR{float3 normalDirection = normalize(input.normalDir);float3 viewDirection = normalize(_WorldSpaceCameraPos - input.posWorld.xyz);float3 lightDirection;float attenuation;if (0.0 == _WorldSpaceLightPos0.w) // directional light?{attenuation = 1.0; // no attenuationlightDirection = normalize(_WorldSpaceLightPos0.xyz);} else // point or spot light{float3 vertexToLightSource = _WorldSpaceLightPos0.xyz - input.posWorld.xyz;float distance = length(vertexToLightSource);attenuation = 1.0 / distance; // linear attenuation lightDirection = normalize(vertexToLightSource);}float3 ambientLighting = UNITY_LIGHTMODEL_AMBIENT.rgb * _Color.rgb;float3 diffuseReflection = attenuation * _LightColor0.rgb * _Color.rgb* (_Waxiness + (1.0 - _Waxiness) * max(0.0, dot(normalDirection, lightDirection)));float3 specularReflection;if (dot(normalDirection, lightDirection) < 0.0) // light source on the wrong side?{specularReflection = float3(0.0, 0.0, 0.0); // no specular reflection}else // light source on the right side{specularReflection = attenuation * _LightColor0.rgb * _SpecColor.rgb * pow(max(0.0, dot(reflect(-lightDirection, normalDirection), viewDirection)), _Shininess);}float silhouetteness = 1.0 - abs(dot(viewDirection, normalDirection));return float4(ambientLighting + diffuseReflection + specularReflection, silhouetteness);}ENDCG }Pass {      Tags { "LightMode" = "ForwardAdd" } // pass for additional light sources on front facesCull Back // render front faces onlyBlend One One // additive blending CGPROGRAM#pragma vertex vert  #pragma fragment frag #include "UnityCG.cginc"uniform float4 _LightColor0; // color of light source (from "Lighting.cginc")// User-specified propertiesuniform float4 _Color; uniform float _Waxiness;uniform float4 _SpecColor; uniform float _Shininess;uniform float4 _TranslucentColor; struct vertexInput {float4 vertex : POSITION;float3 normal : NORMAL;};struct vertexOutput {float4 pos : SV_POSITION;float4 posWorld : TEXCOORD0;float3 normalDir : TEXCOORD1;};vertexOutput vert(vertexInput input) {vertexOutput output;float4x4 modelMatrix = _Object2World;float4x4 modelMatrixInverse = _World2Object;output.posWorld = mul(modelMatrix, input.vertex);output.normalDir = normalize(mul(float4(input.normal, 0.0), modelMatrixInverse).xyz);output.pos = mul(UNITY_MATRIX_MVP, input.vertex);return output;}float4 frag(vertexOutput input) : COLOR{float3 normalDirection = normalize(input.normalDir);float3 viewDirection = normalize(_WorldSpaceCameraPos - input.posWorld.xyz);float3 lightDirection;float attenuation;if (0.0 == _WorldSpaceLightPos0.w) // directional light?{attenuation = 1.0; // no attenuationlightDirection = normalize(_WorldSpaceLightPos0.xyz);} else // point or spot light{float3 vertexToLightSource = _WorldSpaceLightPos0.xyz - input.posWorld.xyz;float distance = length(vertexToLightSource);attenuation = 1.0 / distance; // linear attenuation lightDirection = normalize(vertexToLightSource);}float3 diffuseReflection = attenuation * _LightColor0.rgb * _Color.rgb* (_Waxiness + (1.0 - _Waxiness) * max(0.0, dot(normalDirection, lightDirection)));float3 specularReflection;if (dot(normalDirection, lightDirection) < 0.0) // light source on the wrong side?{specularReflection = float3(0.0, 0.0, 0.0); // no specular reflection}else // light source on the right side{specularReflection = attenuation * _LightColor0.rgb * _SpecColor.rgb * pow(max(0.0, dot(reflect(-lightDirection, normalDirection), viewDirection)), _Shininess);}float silhouetteness = 1.0 - abs(dot(viewDirection, normalDirection));return float4(diffuseReflection + specularReflection, silhouetteness);}ENDCG }} Fallback "Specular"
}

总结

恭喜!你完成了关于半透明体的教程,我们学到了:

  • 如何伪造蜡的外观。
  • 如何伪造背光照射的半透明材质的轮廓的外观。
  • 如何实现这些技术。

这篇关于Cg Programming/Unity/Translucent Bodies半透明体的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/797359

相关文章

Unity Post Process Unity后处理学习日志

Unity Post Process Unity后处理学习日志 在现代游戏开发中,后处理(Post Processing)技术已经成为提升游戏画面质量的关键工具。Unity的后处理栈(Post Processing Stack)是一个强大的插件,它允许开发者为游戏场景添加各种视觉效果,如景深、色彩校正、辉光、模糊等。这些效果不仅能够增强游戏的视觉吸引力,还能帮助传达特定的情感和氛围。 文档

Unity协程搭配队列开发Tips弹窗模块

概述 在Unity游戏开发过程中,提示系统是提升用户体验的重要组成部分。一个设计良好的提示窗口不仅能及时传达信息给玩家,还应当做到不干扰游戏流程。本文将探讨如何使用Unity的协程(Coroutine)配合队列(Queue)数据结构来构建一个高效且可扩展的Tips弹窗模块。 技术模块介绍 1. Unity协程(Coroutines) 协程是Unity中的一种特殊函数类型,允许异步操作的实现

Unity 资源 之 Super Confetti FX:点亮项目的璀璨粒子之光

Unity 资源 之 Super Confetti FX:点亮项目的璀璨粒子之光 一,前言二,资源包内容三,免费获取资源包 一,前言 在创意的世界里,每一个细节都能决定一个项目的独特魅力。今天,要向大家介绍一款令人惊艳的粒子效果包 ——Super Confetti FX。 二,资源包内容 💥充满活力与动态,是 Super Confetti FX 最显著的标签。它宛如一位

Unity数据持久化 之 一个通过2进制读取Excel并存储的轮子(4)

本文仅作笔记学习和分享,不用做任何商业用途 本文包括但不限于unity官方手册,unity唐老狮等教程知识,如有不足还请斧正​​ Unity数据持久化 之 一个通过2进制读取Excel并存储的轮子(3)-CSDN博客  这节就是真正的存储数据了   理清一下思路: 1.存储路径并检查 //2进制文件类存储private static string Data_Binary_Pa

Unity Adressables 使用说明(一)概述

使用 Adressables 组织管理 Asset Addressables 包基于 Unity 的 AssetBundles 系统,并提供了一个用户界面来管理您的 AssetBundles。当您使一个资源可寻址(Addressable)时,您可以使用该资源的地址从任何地方加载它。无论资源是在本地应用程序中可用还是存储在远程内容分发网络上,Addressable 系统都会定位并返回该资源。 您

Unity Adressables 使用说明(六)加载(Load) Addressable Assets

【概述】Load Addressable Assets Addressables类提供了加载 Addressable assets 的方法。你可以一次加载一个资源或批量加载资源。为了识别要加载的资源,你需要向加载方法传递一个键或键列表。键可以是以下对象之一: Address:包含你分配给资源的地址的字符串。Label:包含分配给一个或多个资源的标签的字符串。AssetReference Obj

在Unity环境中使用UTF-8编码

为什么要讨论这个问题         为了避免乱码和更好的跨平台         我刚开始开发时是使用VS开发,Unity自身默认使用UTF-8 without BOM格式,但是在Unity中创建一个脚本,使用VS打开,VS自身默认使用GB2312(它应该是对应了你电脑的window版本默认选取了国标编码,或者是因为一些其他的原因)读取脚本,默认是看不到在VS中的编码格式,下面我介绍一种简单快

Unity数据持久化 之 一个通过2进制读取Excel并存储的轮子(3)

本文仅作笔记学习和分享,不用做任何商业用途 本文包括但不限于unity官方手册,unity唐老狮等教程知识,如有不足还请斧正​​ Unity数据持久化 之 一个通过2进制读取Excel并存储的轮子(2) (*****生成数据结构类的方式特别有趣****)-CSDN博客 做完了数据结构类,该做一个存储类了,也就是生成一个字典类(只是声明)  实现和上一节的数据结构类的方式大同小异,所

【Unity小技巧】URP管线遮挡高亮效果

前言 在URP渲染管线环境下实现物体遮挡高亮显示效果,效果如下: Unity URP遮挡高亮 实现步骤 创建层级,为需要显示高亮效果的物体添加层级,比如Player 创建一个材质球,也就是高亮效果显示的材质球找到Universal Renderer Data Assets 4.在Assets上添加两个Render Objects组件 第一个做如下三处设置 指定遮挡层级指

【Unity面经】实习篇:面试官常问的一百个面试题

👨‍💻个人主页:@元宇宙-秩沅 👨‍💻 hallo 欢迎 点赞👍 收藏⭐ 留言📝 加关注✅! 👨‍💻 本文由 秩沅 原创 👨‍💻 专栏交流🧧🟥Unity100个实战基础✨🎁🟦 Unity100个精华一记✨🎁🟩 Unity50个demo案例教程✨🎁🟨 Unity100个精华细节BUG✨🎁🟨 Unity100个面试题✨🎁 文章