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 Shader】片段着色器(Fragment Shader)的概念及其使用方法

在Unity和图形编程中,片段着色器(Fragment Shader)是渲染管线中的一个阶段,负责计算屏幕上每个像素(片段)的颜色和特性。片段着色器通常在顶点着色器和任何几何处理之后运行,是决定最终像素颜色的关键步骤。 Fragment Shader的概念: 像素处理:片段着色器处理经过顶点着色器和几何着色器处理后,映射到屏幕空间的像素。颜色计算:它计算每个像素的颜色值,这可能包括纹理采样、光

【Unity Shader】Alpha Blend(Alpha混合)的概念及其使用示例

在Unity和图形编程中,Alpha Blend(也称为Alpha混合)是一种用于处理像素透明度的技术。它允许像素与背景像素融合,从而实现透明或半透明的效果。Alpha Blend在渲染具有透明度的物体(如窗户、玻璃、水、雾等)时非常重要。 Alpha Blend的概念: Alpha值:Alpha值是一个介于0(完全透明)和1(完全不透明)的数值,用于表示像素的透明度。混合模式:Alpha B

Apple - Media Playback Programming Guide

本文翻译整理自:Media Playback Programming Guide(Updated: 2018-01-16 https://developer.apple.com/library/archive/documentation/AudioVideo/Conceptual/MediaPlaybackGuide/Contents/Resources/en.lproj/Introduction

Unity Meta Quest 开发:关闭 MR 应用的安全边界

社区链接: SpatialXR社区:完整课程、项目下载、项目孵化宣发、答疑、投融资、专属圈子 📕教程说明 这期教程我将介绍如何在应用中关闭 Quest 系统的安全边界。 视频讲解: https://www.bilibili.com/video/BV1Gm42157Zi 在 Unity 中导入 Meta XR SDK,进行环境配置后,打开 Assets > Plugins > An

Unity 字体创建时候容易导致字体文件不正确的一种情况

上面得到了两种字体格式,一种是TextMeshPro的,另一种是Unity UI系统中默认使用的字体资源。其原因是创建的位置不同导致的。 1.下面是TextMeshPro字体创建的位置 2:下面是Unity UI系统中默认使用的字体资源

摄像头画面显示于unity场景

🐾 个人主页 🐾 🪧阿松爱睡觉,横竖醒不来 🏅你可以不屠龙,但不能不磨剑🗡 目录 一、前言二、UI画面三、显示于场景四、结语 一、前言 由于标题限制,这篇文章主要是讲在unity中调用摄像头,然后将摄像头捕捉到的画面显示到场景中,无论是UI画面还是场景中的某个物体上;至于应用的场景可以用于AR增强现实。 那么话不多说,直接开始今

unity开发 --------- NGUI (UITable)

unity开发 --------- NGUI UITable与UIGrid相似,都是实现自动排序的。但UIGrid的元素大小是由我们来指定的,而Table中的元素的大小是根据元素本身计算出来的。 UITable还保存了元素的顺序List<Transform>。每次重排序,都会更新此List。除了要计算元素的Bound和保存List外,其他基本与UIGrid一致。 unity开发 ---

unity开发 --------- NGUI (UIGrid)

unity开发 --------- NGUI  UIGrid可以实现多个gameobject自动排序。可以设定其排序方向、每个元素的宽度,高度等。 public Arrangement arrangement = Arrangement.Horizontal;public int maxPerLine = 0;public float cellWi

unity开发 --------- NGUI(Localization、UILocalize)

unity开发 --------- NGUI NGUI支持动态加载资源功能。比如语言选择:假如当前语言为中文,当将语言更改为英文时,所有UI上的文字也立即变成了英文。此功能是用Localization和UILocalize两个脚本配合完成的。 Localization中记录多种配置方案,当更改配置方案时,由Localization发送通知,通知各UILocalize更新。 NGU

unity开发 --------- NGUI (UIViewPort、UIDraggableCamera)

unity开发 --------- NGUI 前面提到一种实现ScrollView的方法:unity开发 --------- NGUI (UIDragPanelContents、UIDraggablePanel、UICenterOnChild、UIScollBar、SpringPanel) 但上面那种发放有一个缺陷!它要用到shader。也就是说,对于低端设备,就不能以上面那种方式实现拖