SchultzGames
Para tirar dúvidas, crie um tópico especifico na área "Dúvidas em Geral" e aguarde ser respondido. Evite comentar em tópicos não relacionados a sua dúvida :D
TÓPICOS RECENTES:
Tópico:
Postado em:
Postado por:
Unity Admob Erro
Mais Um jogo!
DEATH ISLAND 0.2.5 SURVIVAL GAME 4 ANOS EM DESENVOLVIMENTO
Player travando na colisão com o chão Unity 2D
Sombras estão quadradas na build
nao consigo fazer o player sentar no sofa alguem me ajuda
Unity - Ao mudar de scene, todas as Lights são deletadas
210 Linhas de código para inimigo é muito grande?
modelar avatar e skins para um jogo web
Collider (mesh?)
ShapeKeys do Blender para a Unity altera áreas próximas
COMO EVITAR QUE UM OBJETO (PLAYER,ITEM ETC...) ATRAVESSE UMA PAREDE.
Ajuda em Script de Verificação de Ação e Reação
unity Failed to load PlayerSettings (internal index #0). Most likely data f
PRECISO FAZER QUE MEU GAME FIQUE ONLINE
Materiais do Blander não aparecem no MeshRendere do Objeto na Unity
Repetiçoes de Textura no Terreno
SERVER IS DOWN - UNITY+MSQL
Procuro programadores - Novo jogo
Problema com o MS VEHICLES
Preciso de ajuda com a Unity
Problema com vídeo em 360° na Unity
Problemas no MS Vehicles
unity- eventos na Animação com Armature/Bones vinda do blender não funciona
ajuda exibir resultados simulados em uma liga Game Unity
Unity - ParticleSystem não é redirecionado no rawimage no canvas
Como resolver o problema de "face orientation" no Blender.
[DÚVIDA] Tive um problema com meu Canvas
erro na Directional Light
Problemas com o Directional Light da Unity 3D
Novo jogo da franquia Sphere game em desenvolvimento
malha da roda não girando com wheel collider unity
Problemas com ambiguidade
Touch mobile
INVALID TOKEN
Como acessar o "HD Render Pipeline" do HDRP por script?
CHAT GPT PRA JOGO DE TIRO? comentem
Tutorial script inimigo segue e foge do player
Ainda vale a pena lançar Asset na Asset Store?
Ajuda com tabela de historico de pontuaçao.
[TUTORIAL] Entrar no carro estilo GTA
Como derrapar um Whell Collider
Como altertar o valor do "Asymptote Value" do Whell Collider via Script
Preciso de ajuda para substituir valor de variavel em outro script
Ajuda com Top Down Shooter utilizando Photon
Duvida com Netcode
[RESOLVIDO] Unity - Movendo a Câmera na Horizontal/Vertical com Touch
Alguém me ajuda com os anúncios pfv
Segundo Trailer do jogo Dark Age, Feliz Natal a todos!
Unity - ScrollRect, Viewport, Content - O Conteúdo ñ inicia no topo
Coleta de itens
Unity - Cadastro do email do jogador
[GRATIS] PACK DE MODELOS 3D PARA JOGO DE TERROR
Onde Conseguir músicas para meu Jogo?
error CS0246 em Script
Alguem teve ja esse problema?
[Projeto em Andamento] Draug, um jogo de hordas
DISPONIVEL PARA FAZER MODELOS 3D
Unity-Loja.Como os Jogadores terão acesso aos ítens comprados na PlayStore?
Bugando depois do Build.
Primeiro Trailer do jogo Dark Age
Problema com sombra
Mesh e Material do objeto trocando para uma instancia no inicio do jogo
[RESOLVIDO] Unity - RawImages_Layer_Camera
INVESTIMENTO EM JOGOS E BANCO DE TALENTO
Teaser do meu novo projeto pessoal, Dark Age
Preciso de ajuda com mudança para mobile androide.
[RESOLVIDO] Posição final do objeto em jogo 2D
Input.GetAxis() obedercer a orientação de um objeto.
Interação com elementos UI
Meu primeiro jogo na steam
Minimap/Radar/GPS Estilo GTA V
[RESOLVIDO] Erro no console depois que formatei o pc
PACK GRÁTIS de Músicas ELETRÔNICAS para ajudar vocês em seus Jogos Indies!
[TUTORIAL] Entenda como funciona: ENUM, SWITCH, BREAK, CASE no C#
O Labirinto II - Baixe o Jogo
Qual e o codigo de Botões na unity para saber seus estados?
Como carregar itens pequenos dentro do carro sem que atravesse os colliders
[Duvida] Script pegar itens
Travamento ao trocar de cena
Colisão zoada e movimentação
Salvar objetos que foram destruidos entre cenas na unity
Quero começa a desenvolver um jogo de luta porem eu queria aprender a faze
Pegar qual objeto colidiu com o Linecast.
movimentação e camera?
[RESOLVIDO] Unity - SceneManager.LoadScene abre scene com objeto "vazio"
[RESOLVIDO] ajuda sobre skybox
MEU SIMULADOR DE CARRO
[_____IMPORTANTE_____] ALTERAÇÕES NA POLÍTICA DE COBRANÇA DA UNITY
[RESOLVIDO] Ausencia da funçao NavMesh na Unity 2022.2.12
[_____IMPORTANTE_____] ALTERAÇÕES NA POLÍTICA DE COBRANÇA DA UNITY - 2
Roll Up Um jogo de aventura e desáfios
Terminologia da Unity em outras engines
Como criar a iluminação do Sol no Sistema Solar?
Conexão de lobby pelo OnConnectedToMaster
Problema na exportção de projeto unity
[RESOLVIDO] Unity - Áudios estão emitindo som só Depois do Botão ser solto
Unity - Banco de Dados Online junto ao Jogo
Player virar para o inimigo(Prefab)
Seg Abr 15, 2024 12:23 pm
Sáb Abr 13, 2024 11:37 am
Qua Abr 10, 2024 1:33 am
Ter Abr 09, 2024 10:28 am
Seg Abr 08, 2024 9:27 pm
Seg Abr 08, 2024 8:01 am
Sáb Abr 06, 2024 8:05 pm
Qui Abr 04, 2024 11:34 pm
Qui Abr 04, 2024 11:13 pm
Qui Abr 04, 2024 11:10 pm
Sex Mar 22, 2024 2:41 pm
Dom Mar 10, 2024 2:30 pm
Sex Mar 01, 2024 1:27 pm
Qui Fev 22, 2024 9:57 pm
Ter Fev 20, 2024 9:28 am
Ter Fev 20, 2024 12:15 am
Seg Fev 19, 2024 1:06 pm
Seg Fev 12, 2024 1:56 pm
Seg Fev 12, 2024 1:17 pm
Dom Fev 11, 2024 8:55 pm
Dom Fev 11, 2024 11:16 am
Seg Fev 05, 2024 4:18 pm
Dom Fev 04, 2024 9:39 pm
Qua Jan 31, 2024 11:59 pm
Ter Jan 30, 2024 7:37 pm
Ter Jan 23, 2024 6:33 pm
Dom Jan 21, 2024 6:03 pm
Sáb Jan 20, 2024 7:03 pm
Sáb Jan 20, 2024 6:58 pm
Sáb Jan 20, 2024 6:39 pm
Sex Jan 19, 2024 8:40 am
Dom Jan 14, 2024 5:30 pm
Qua Jan 10, 2024 10:29 pm
Qua Jan 10, 2024 8:55 pm
Qua Jan 10, 2024 7:14 pm
Ter Jan 09, 2024 3:55 pm
Ter Jan 09, 2024 8:04 am
Sáb Jan 06, 2024 8:02 pm
Sex Jan 05, 2024 7:01 am
Sex Jan 05, 2024 12:12 am
Qui Jan 04, 2024 6:55 pm
Qui Jan 04, 2024 12:52 pm
Qui Jan 04, 2024 4:34 am
Ter Jan 02, 2024 11:48 pm
Dom Dez 31, 2023 7:25 pm
Qua Dez 27, 2023 5:44 pm
Qua Dez 27, 2023 3:08 pm
Sáb Dez 23, 2023 7:27 pm
Sáb Dez 23, 2023 5:06 pm
Qui Dez 21, 2023 8:10 pm
Seg Dez 18, 2023 2:04 pm
Sex Dez 15, 2023 5:11 pm
Qui Dez 14, 2023 9:13 pm
Qui Dez 14, 2023 2:47 pm
Qui Dez 14, 2023 1:48 pm
Qua Dez 13, 2023 8:58 pm
Ter Dez 12, 2023 2:32 pm
Seg Dez 11, 2023 1:53 pm
Qua Dez 06, 2023 8:13 pm
Sáb Dez 02, 2023 8:06 pm
Qui Nov 30, 2023 7:49 am
Seg Nov 27, 2023 1:35 am
Qua Nov 22, 2023 7:37 am
Qui Nov 09, 2023 1:22 pm
Seg Nov 06, 2023 11:59 am
Ter Out 31, 2023 9:53 am
Dom Out 29, 2023 8:05 pm
Dom Out 29, 2023 3:03 am
Sex Out 27, 2023 3:43 pm
Sex Out 27, 2023 3:28 pm
Qua Out 25, 2023 1:20 pm
Seg Out 23, 2023 10:34 am
Dom Out 22, 2023 6:55 pm
Qui Out 19, 2023 11:57 pm
Qui Out 19, 2023 6:39 pm
Ter Out 17, 2023 6:37 pm
Ter Out 17, 2023 6:18 pm
Seg Out 16, 2023 1:59 pm
Sáb Out 14, 2023 12:15 pm
Qua Out 11, 2023 6:07 pm
Seg Out 09, 2023 4:19 pm
Qua Out 04, 2023 12:12 pm
Qua Out 04, 2023 12:11 pm
Ter Out 03, 2023 9:18 pm
Ter Out 03, 2023 9:08 pm
Ter Out 03, 2023 6:05 pm
Ter Set 26, 2023 12:45 pm
Seg Set 25, 2023 9:02 pm
Seg Set 25, 2023 9:47 am
Sáb Set 23, 2023 2:10 pm
Sex Set 22, 2023 9:01 pm
Qui Set 21, 2023 11:04 am
Qua Set 20, 2023 4:40 pm
Qua Set 20, 2023 9:15 am
Dom Set 17, 2023 12:17 pm
Sex Set 15, 2023 7:24 pm
Sex Set 15, 2023 5:41 pm
Sex Set 15, 2023 4:28 pm
Sex Set 15, 2023 10:56 am



































































































[TUTORIAL] Shader de renderização baseada em física

3 participantes

Ir para baixo

TUTORIAL [TUTORIAL] Shader de renderização baseada em física

Mensagem por Matrirxp Sex Out 16, 2020 11:39 pm

Bom dia! Boa tarde! Boa Noite!
Hoje venho trazer um tutorial de HLSL para shader PBR na unity.

[TUTORIAL] Shader de renderização baseada em física IlRe0Vk

E recomendado que você saiba o pelo menos básico de shader e hlsl, já que nesse tutorial não será abordado a criação de shaders.
Eu vou usar uma API própria + Render Pipelines Core para o shader, já que estou usando um SRP (Scriptable Render Pipeline), isso facilita no uso de Global Illumination, nas conversões de espaço, etc.

[TUTORIAL] Shader de renderização baseada em física XxsZQyv
Mas você pode fazer isso com as ferramentas padrões da unity, porem vai dar um pouco mais de trabalho.
Dito isso vamos começar!

Estrutura Base do shader:

Criei 2 arquivos para deixar mais organizado.
O primeiro e o Shader. (Arquivo .shader)
O segundo serão nossos Pass [Pixel Shader e Vertex Shader]. (Arquivo .hlsl)

[TUTORIAL] Shader de renderização baseada em física KA0AAVN
[TUTORIAL] Shader de renderização baseada em física JLnQSuO

PBR.shader

Código:
Shader "Magic Byte/Standard PBR" {
 
 Properties {

 /*Blend options*/
 [Enum(UnityEngine.Rendering.BlendMode)] _SrcBlend ("Src Blend", Float) = 1 //One
 [Enum(UnityEngine.Rendering.BlendMode)] _DstBlend ("Dst Blend", Float) = 0 //Zero
 [Enum(Off, 0, On, 1)] _ZWrite ("Z Write", Float) = 1 //On
 /*Blend options*/

 [HideInInspector] _MainTex("Lightmap Texture", 2D) = "white" {} // Uso de GI em SRP (Retrire essas propriedades)
 [HideInInspector] _Color("Lightmap Color", Color) = (0.5, 0.5, 0.5, 1.0) // Uso de GI em SRP (Retrire essas propriedades)
 }
 
 SubShader {
 HLSLINCLUDE
 #include "../../ShaderLibrary/Common.hlsl" //API de graficos da MB (Retire esse include)
 ENDHLSL

 Pass {
 Tags {
 "LightMode" = "MBLit"
 }

 /*Blend*/
 Blend [_SrcBlend] [_DstBlend]
 ZWrite [_ZWrite]
 /*Blend*/

 HLSLPROGRAM
 /*Features para SRP*/
 #pragma target 3.5
 #pragma shader_feature _CLIPPING
 #pragma shader_feature _RECEIVE_SHADOWS
 #pragma shader_feature _PREMULTIPLY_ALPHA
 #pragma multi_compile _ LOD_FADE_CROSSFADE
 #pragma multi_compile _ _DIRECTIONAL_PCF3 _DIRECTIONAL_PCF5 _DIRECTIONAL_PCF7
 #pragma multi_compile _ _CASCADE_BLEND_SOFT _CASCADE_BLEND_DITHER
 #pragma multi_compile _ _SHADOW_MASK_ALWAYS _SHADOW_MASK_DISTANCE 
 #pragma multi_compile _ LIGHTMAP_ON
 #pragma multi_compile _ DYNAMICLIGHTMAP_ON
 #pragma multi_compile_instancing
 /*Features para SRP*/

 #pragma vertex PBRPassVertex // <-- VERTEX SHADER
 #pragma fragment PBRPassFragment // <-- PIXEL SHADER
 #include "PBRPass.hlsl" // <-- Incluir Arquivo com os Pass
 ENDHLSL
 }

 }
}

PBRPass.hlsl

Código:
#ifndef PBR_PASS_INCLUDED
#define PBR_PASS_INCLUDED

/* API GRAFICA MB */
#include "../../ShaderLibrary/Surface.hlsl"
#include "../../ShaderLibrary/Shadows.hlsl"
#include "../../ShaderLibrary/Light.hlsl"
#include "../../ShaderLibrary/BRDF.hlsl"
#include "../../ShaderLibrary/GI.hlsl"
#include "../../ShaderLibrary/Lighting.hlsl"
#include "../../ShaderLibrary/ClearCoat.hlsl"
/* API GRAFICA MB */

struct Attributes {
 float3 positionOS : POSITION;
 float3 normalOS : NORMAL;
 float4 tangentOS : TANGENT;
 float2 baseUV : TEXCOORD0;
 float2 lightmapUV: TEXCOORD1;
 float2 dynamicLightmapUV : TEXCOORD2;
 UNITY_VERTEX_INPUT_INSTANCE_ID
};

struct Varyings {
 float4 positionCS : SV_POSITION;
 float3 positionWS : VAR_POSITION;
 float3 normalWS : VAR_NORMAL;
 float4 tangentWS : VAR_TANGENT;
 float2 baseUV : VAR_BASE_UV;
 float2 lightmapUV : TEXCOORD4;
 float2 dynamicLightmapUV : TEXCOORD5;
 UNITY_VERTEX_INPUT_INSTANCE_ID
};

Varyings PBRPassVertex (Attributes input) {
 Varyings output;

 /* API GRAFICA MB */
 output.lightmapUV = input.lightmapUV * unity_LightmapST.xy + unity_LightmapST.zw;
 output.dynamicLightmapUV = input.dynamicLightmapUV * unity_DynamicLightmapST.xy + unity_DynamicLightmapST.zw;
 /* API GRAFICA MB */

 /* Render Pipelines Core */
 output.positionWS = TransformObjectToWorld(input.positionOS); // MULTIPLICACOES DE MATRIZES PARA A CONVERSAO DE ESPACO
 output.positionCS = TransformWorldToHClip(output.positionWS);
 output.normalWS = TransformObjectToWorldNormal(input.normalOS);
 output.tangentWS = float4(TransformObjectToWorldDir(input.tangentOS.xyz), input.tangentOS.w);
 output.baseUV = input.baseUV;
 /* Render Pipelines Core */

 return output;
}
float4 _Time; //Funcao tempo importada da unity por buffer
float4 PBRPassFragment(Varyings input) : SV_TARGET{
 float3 color = (0,0,0);



 return float4(color,1);
}

#endif
Buffer _Time

Definições de propriedades:
Antes de começarmos o PBR vamos definir as propriedades do nosso shader.


PBR.shader

Código:
Properties {

 _BaseMap("Texture", 2D) = "white" {} //Mapa de textura
 _BaseColor("Color", Color) = (0.5, 0.5, 0.5, 1.0) //Cor de material

 _Metallic("Metallic", Range(0, 1)) = 0 //Nivel metalico (0,1)
 _Smoothness("Smoothness", Range(0, 1)) = 0.5 //Nivel de "superficie aspera" ou nivel de suavidade
 _Occlusion("Occlusion", Range(0, 1)) = 1 //Nivel de microsombras do mapa de oclusao

 [NoScaleOffset] _OcclusionMap("Occlusion Map(AO)", 2D) = "white" {} //Mapa de Oclusao

 [NoScaleOffset] _SmoothnessMap("Smoothness Map(Specular)", 2D) = "white" {} //Mapa de nivel de suavidade
 [NoScaleOffset] _MetalMap("Metallic Map", 2D) = "white" {} //Mapa de nivel metalico

 [NoScaleOffset] _EmissionMap("Emission", 2D) = "white" {} //Mapa de emissao
 [HDR] _EmissionColor("Emission", Color) = (0.0, 0.0, 0.0, 0.0) //Cor da emissao

 [NoScaleOffset] _NormalMap("Normals", 2D) = "bump" {} //Mapa normal
 _NormalStrength("Normal Strength", Range(0, 1)) = 1 //Nivel de mapa normal
 
    _Fresnel("Reflectance", Range(0,3)) = 0.0 //Reflectancia do material. (0,3) Para fins artisticos

}

No arquivo "PBRPass.hlsl" vamos definir uma struct para armazenar as propriedades do nosso material (superficie).

PBRPass.hsls

Código:
struct Surface {
 float3 position; //Posicao no espaco de mundo
 float3 normal; //Vetor Normal
 float3 interpolatedNormal; //Normal de espaco de mundo
 float3 viewDirection; //Direcao de visao
 float4 tangent; //Vetor de tangentes de superficie
 float3 binormal; //Vetor de binormal Produto cruzado -- > cross(vetor normal, vetor tangente) * vetor tangente
 float3 color; //Cor da superficie
 float alpha; //Nivel de transparencia
 float metallic; //Nivel Metalico
 float smoothness; //Nivel de suavidade
 float occlusion; //Nivel de oclusao
 float fresnelStrength; //Nivel de reflectancia
};

Agora vamos adicionar os valores dessas propriedades no nosso struct de superficie:

PBRPass.hlsl

Código:
TEXTURE2D(_BaseMap);
SAMPLER(sampler_BaseMap);

TEXTURE2D(_NormalMap);
SAMPLER(sampler_NormalMap);

TEXTURE2D(_OcclusionMap);
SAMPLER(sampler_OcclusionMap);

TEXTURE2D(_SmoothnessMap);
SAMPLER(sampler_SmoothnessMap);

TEXTURE2D(_MetalMap);
SAMPLER(sampler_MetalMap);

TEXTURE2D(_EmissionMap);
SAMPLER(sampler_EmissionMap);

float4 _BaseColor;
float _NormalStrength;
float _Metallic;
float _Smoothness;
float _Occlusion;
float4 _EmissionColor;
float _Fresnel;

float4 PBRPassFragment(Varyings input) : SV_TARGET{
 float3 color = (0,0,0);

 Surface surface;
 surface.position = input.positionWS;

 float4 Nmap = SAMPLE_TEXTURE2D(_NormalMap, sampler_NormalMap, input.baseUV);
 float3 normal = DecodeNormal(Nmap, _NormalStrength);

 surface.normal = NormalTangentToWorld(normal, input.normalWS, input.tangentWS); // <---- Transformacao de espaco do Render Pipelines Core
 surface.interpolatedNormal = input.normalWS;
 surface.viewDirection = normalize(_WorldSpaceCameraPos - input.positionWS); //Normalizar posicao da camera - posicao de objeto
 surface.tangent = input.tangentWS;
 surface.binormal = cross(NormalTangentToWorld(normal, input.normalWS, input.tangentWS), input.tangentWS.xyz) * input.tangentWS.w;
 surface.color = SAMPLE_TEXTURE2D(_BaseMap, sampler_BaseMap, input.baseUV) * _BaseColor.rgb;
 surface.alpha = _BaseColor.a;

 float metallic = _Metallic;
 metallic *= pow(abs(SAMPLE_TEXTURE2D(_MetalMap, sampler_MetalMap, input.baseUV).r), 2.2); //Correcao de Gamma do mapa (Fins artisticos)

 float smoothness = _Smoothness;
 smoothness *= pow(abs(SAMPLE_TEXTURE2D(_SmoothnessMap, sampler_SmoothnessMap, input.baseUV).r), 2.2); //Correcao de Gamma do mapa (Fins artisticos)
 //Usamos o nivel de red da textura para definir o nivel de smootheness a partir de uma mascara de smoothness, o mesmo e feito com a mascara(mapa) de metal e de oclusao
 
 float occlusion = _Occlusion;
 occlusion *= pow(abs(SAMPLE_TEXTURE2D(_OcclusionMap, sampler_OcclusionMap, input.baseUV).r), 2.2); //Correcao de Gamma do mapa (Fins artisticos)

 surface.metallic = metallic;
 surface.smoothness = smoothness;
 surface.occlusion = occlusion;

 surface.fresnelStrength = _Fresnel;

 color += SAMPLE_TEXTURE2D(_EmissionMap, sampler_EmissionMap, input.baseUV) * _EmissionColor;

 return float4(color, surface.alpha);
}


Iluminação Bruta

Como dito acima, estou utilizando um SRP, logo toda a iluminação do meu objeto tem que ser feita por mim. Por esse motivo, o próximo tópico mostra como a iluminação bruta do objeto foi gerada.
Esse tópico serve apenas para mostrar com mais clareza como a luz esta sendo gerada nesse shader, por isso, pode ser ignorado no caso de você estar fazendo um shader com a iluminação da unity.

Por enquanto nosso shader está todo preto, isso acontece pois a única cor adicionada é a emissão.


[TUTORIAL] Shader de renderização baseada em física CifZyGD


Então precisamos adicionar a luz da Directional Light, faremos isso a partir dos dados que o pipeline está mandando para a GPU.


[TUTORIAL] Shader de renderização baseada em física 5DAiAmg
c#

Vamos criar uma função para tratar a iluminação de cada Directional Light e também dar suporte a Iluminação Global no PBRPass.
A iluminação bruta será calculada a partir do produto escalar (cosseno) entre o vetor normal e o vetor de direção da luz vezes a atenuação da luz (definida individualmente em cada luz). Depois disso, multiplicamos pela cor da luz, assim as partes escuras permanecem escuras (pois na escala de cor o preto e igual a 0), a as partes claras ganham cor.

Produto escalar é o cosseno para a maioria dos propósitos de Computação Gráfica, já que estamos lidando com vetores de comprimento unitário.

Função Dot:


[TUTORIAL] Shader de renderização baseada em física BWRo7yQ

PBRPass.hlsl

Código:
float3 Lighting(Surface surface, GI gi) {
 ShadowData shadowData = GetShadowData(surface);//Preparar GI
 shadowData.shadowMask = gi.shadowMask;

 float3 color = (0, 0, 0);
 for (int i = 0; i < GetDirectionalLightCount(); i++) {
 Light light = GetDirectionalLight(i, surface, shadowData);//Compilar Luz
 color += saturate(dot(surface.normal, light.direction) * light.attenuation) * light.color;//Adicionar sombra propria
 }
 return color;
}

Feito isso, já podemos adicionar a iluminação na cor final do pixel shader:
Arquivo de GI utilizado: GI.hlsl
Código:
GI gi = GetGI(input.lightmapUV, input.dynamicLightmapUV, surface,  (1 - surface.smoothness), 1);
 color = Lighting(surface, gi);

Agora já temos nossa primeira iluminação:
[TUTORIAL] Shader de renderização baseada em física Xbfg2FV

Oque é PBR:

PBR ou Physically based rendering (Renderização baseada em física) são técnicas de renderização que tem como objetivo simular aproximações físicas do mundo real na iluminação gerada em computador
Para que um modelo de iluminação seja considerado fisicamente baseado ele deve seguir 3 condições básicas.

1- Conservar sua energia
2- Simulação de microfacetes
3- Modelo de BRDF fisicamente baseado

Nesse tutorial o modelo adotado será um modelo usado na Magic Byte RP parecido com o modelo de BRDF da Disney, que aborda um estilo mais artístico do que físico.

Simulação de Microfacetes:


A teoria de microfacetes nos mostra que toda superfície em uma escala microscópica possui pequenas ranhuras que funcionam como espelhos perfeitamente reflexivos. Em algumas superfícies chamadas de dielétricas, essas ranhuras não são alinhadas espalhando a luz de forma aleatória, assim mantendo uma iluminação difusa.

Já as superfícies metálicas espelham a luz de forma uniforme, criando um brilho especular.





[TUTORIAL] Shader de renderização baseada em física Pz59Iif
[TUTORIAL] Shader de renderização baseada em física TzuDL3H[TUTORIAL] Shader de renderização baseada em física 8FgWji6
Dielétrica / Metálica
[TUTORIAL] Shader de renderização baseada em física YvA2k0c


Em resumo, quando mais áspera for a superfície, mais desalinhado as microfissuras estarão.

Modelo de microfacetes:
[TUTORIAL] Shader de renderização baseada em física D9uOj4K
D(h): Função de distribuição (Modelo usado GGX)
G(n,l,v): Termo geometrico (Modelo usado Smith)
F(n,v): Termo Fresnel (Modelo usado Schlick)


Calcular BRDF

Primeiro temos que criar uma estrutura para armazenar os dados do BRDF, assim como fizemos para a superfície.

PBRPass.hlsl

Código:
struct BRDF{
 float3 diffuse;
 float3 specular;
 float perceptualRoughness;
 float roughness;
};

Agora vamos criar uma função para tratar os dados do BRDF.

Código:
BRDF GetBRDF(Surface surface) {
 BRDF brdf;

 brdf.diffuse = surface.color * (1 - surface.metallic);
 brdf.specular = lerp(0, surface.color, surface.metallic);

 brdf.perceptualRoughness = PerceptualSmoothnessToPerceptualRoughness(surface.smoothness);
 brdf.roughness = PerceptualRoughnessToRoughness(brdf.perceptualRoughness);

 return brdf;
}

E uma função para retornar a simulação de microfacetes (Chamaremos de Iluminação direta).

Código:
float3 DirectIllumination(Surface surface, BRDF brdf, Light light) {
 
 return brdf.diffuse;

}


Agora vamos adicionar a iluminação direta na nossa função de iluminação bruta

Código:
float3 Lighting(Surface surface, GI gi) {
 ShadowData shadowData = GetShadowData(surface);
 shadowData.shadowMask = gi.shadowMask;

 BRDF brdf = GetBRDF(surface);

 float3 color = (0,0,0);
 for (int i = 0; i < GetDirectionalLightCount(); i++) {
 Light light = GetDirectionalLight(i, surface, shadowData);//Compilar Luz
 color += dot(surface.normal, light.direction) * light.attenuation * light.color * DirectIllumination(surface, brdf, light);//Adicionar sombra propria
 }
 return color;
}


Com isso já estamos prontos para começar as simulações. 
No entanto, quando tentamos usar um material quase 100% metálico o resultado é uma parte difusa completamente preta, oque para fins fisicos não e interessante.
[TUTORIAL] Shader de renderização baseada em física KL8xEqv

Temos que criar uma função que limite o nível metálico em 0.04 (Nível mínimo definido pela Unity na URP).

Código:
#define MIN_REFLECTIVITY 0.04 // <--Nivel minimo

float OneMinReflectivity(float metallic) {
 float size = 1.0 - MIN_REFLECTIVITY; // <-- Inverter nivel (One Minus)
 return size - metallic * size; // <-- Para pequenos niveis retornar inverso da reflexão minima
}

BRDFGetBRDF(Surface surface) {
 BRDF brdf;

 brdf.diffuse = surface.color * OneMinReflectivity(surface.metallic); //<-- Brilho difuso (com base no nivel metalico)
 brdf.specular = lerp(MIN_REFLECTIVITY, surface.color, surface.metallic);

 brdf.perceptualRoughness = PerceptualSmoothnessToPerceptualRoughness(surface.smoothness);
 brdf.roughness = PerceptualRoughnessToRoughness(brdf.perceptualRoughness);

 return brdf;
}


Função de Distribuição

Para calcular a termo D vamos usar a função GGX, que utiliza o produto escalar entre vetor mediano, entre o vetor de direção da luz e o vetor normal, e o vetor normal.
[TUTORIAL] Shader de renderização baseada em física 9Tqx41r
[TUTORIAL] Shader de renderização baseada em física ZqrYkld

NxH = produto cruzado entre o vetor Normal e o vetor Mediano
[TUTORIAL] Shader de renderização baseada em física 3RSLl1n

Nosso hlsl vai ficar assim:

Código:
//GGX
float GGX(Surface surface, BRDF brdf, Light light) {
 float3 h = SafeNormalize(light.direction + surface.viewDirection); //Half Vector (Vetor Mediano)
 float NoH = dot(surface.normal, h); //Produto escalar entre vetor normal e vetor mediano
 float3 NxH = cross(surface.normal, h);//Produto cruzado entre vetor normal e vetor mediano
 float a = NoH * brdf.roughness;
 float k = brdf.roughness / (dot(NxH, NxH) + a * a);
 float d = k * k * (1.0 / PI);//  1/PI <-- Essa e a funcao lambertiana | A divisão por pi existe para normalizar a luz
 return d;
}

float3 DirectIllumination(Surface surface, BRDF brdf, Light light) {
 
 return GGX(surface, brdf, light) + brdf.diffuse;

}

[TUTORIAL] Shader de renderização baseada em física LpbPDsK
Já temos nosso brilho especular definido.

Termo de Geometria

Para calcular o quanto um microfacete é bloqueado por outro nos usamos o Termo G ou termo de geometria, assim conseguimos calcular a influencia de um microfacete na iluminação do objeto.
No entanto, esse termo é caro em relação a processamento e seu beneficio é pequeno. Por isso, ele não será usado nesse tutorial.
Mas segue métodos de implementação para interessados:
[TUTORIAL] Shader de renderização baseada em física 3I2uNZz

Código:
 float Rough2Max = max(brdf.roughness * brdf.roughness, 2.0e-3);
 float k = Rough2Max * 0.5f;
 float GSmithL = NoL * (1.0f - k) + k;
 float GSmithV = dot(surface.normal, surface.viewDirection) * (1.0f - k) + k;
 float G = 0.25f / (GSmithL * GSmithV);



Termo Fresnel


Esse termo será responsável pela distribuição da luz em torno do material de acordo com o nível metálico.

[TUTORIAL] Shader de renderização baseada em física EQw8KA5
f0 = Nível refletância especular a 0 graus

Vamos criar uma função para processar os dados do fresnel

Código:
float FresnelSchlick(Surface surface) {
 float NoV = dot(surface.normal, surface.viewDirection);
 float f0 = pow(1.0 - NoV, 4.0);//Potencia da 4 grau no inverso (OneMinus) do produto escalar
 return f0 + NoV * (1.0 - f0) * surface.metallic;
}

Por fim, nosso função de Iluminacao direta fica assim:
Código:
float3 DirectIllumination(Surface surface, BRDF brdf, Light light) {

 return GGX(surface, brdf, light) * FresnelSchlick(surface) + brdf.diffuse;

}

[TUTORIAL] Shader de renderização baseada em física DA2eTic


Iluminação Indireta
Mais uma parte do tutorial onde a leitura é opcional, asse parte serve para adicionar a iluminação indireta da Iluminação Global ao shader, já que, estou utilizando uma SRP.

Criei uma função para processar as informações vindas do arquivo de GI.

Código:
float3 IndirectIllumination(Surface surface, BRDF brdf, float3 diffuse, float3 specular) {

 float3 reflection = specular * lerp(brdf.specular, brdf.fresnel, FresnelBRDF(surface));
 reflection /= brdf.roughness * brdf.roughness + 1.0;

 return (diffuse * (brdf.diffuse / PI) + reflection) * surface.occlusion;
}


Adicionando luz indireta na iluminacao bruta:

Código:
float3 Lighting(Surface surface, GI gi) {
 ShadowData shadowData = GetShadowData(surface);
 shadowData.shadowMask = gi.shadowMask;

 BRDF brdf = GetBRDF(surface);

 float3 color = IndirectIllumination(surface, brdf, gi.diffuse, gi.specular);
 for (int i = 0; i < GetDirectionalLightCount(); i++) {
 Light light = GetDirectionalLight(i, surface, shadowData);//Compilar Luz
 color += dot(surface.normal, light.direction) * light.attenuation * light.color * DirectIllumination(surface, brdf, light);//Adicionar sombra propria
 }
 return color;
}

[TUTORIAL] Shader de renderização baseada em física RUezSho


Conservação de Energia


A conservação de energia é um dos principais componentes de um bom BRDF, ele serve para manter os níveis de luz refletida menor do que os níveis de luz que incide no material.  
Deixando assim a termodinâmica bem feliz.


Vamos adicionar uma equação simples de conservação de energia ao nosso shader PBR.

Código:
float3 DirectIllumination(Surface surface, BRDF brdf, Light light) {

 float NoL = dot(surface.normal, light.direction);//Produto escalar entre o vetor Normal e o vetor de direcao da luz
 float3 energyCompensation = 1.0 + NoL * (1.0 / (1.1 - brdf.roughness) - 1.0); // <----

 return GGX(surface, brdf, light) * FresnelSchlick(surface) * energyCompensation + brdf.diffuse;

}

Resultado:
[TUTORIAL] Shader de renderização baseada em física L6saPVx



Nível Difuso da Disney


[TUTORIAL] Shader de renderização baseada em física Gt1JwIV
Sem Nivel Difuso da Disney

A disney usa métodos diferentes para determinar a cor difusa de um material.
Por isso, vamos criar uma propriedade para controlar o uso dessa função.

PBR.shader



Código:
[Enum(Off, 0, On, 1)] _DisneyDiffuse("Disney Diffuse", Float) = 1 //On

Agora no arquivo PBRPass.hlsl, vamos criar a função e adicionar uma variável para essa propriedade:

PBRPass.hlsl

Código:
float _DisneyDiffuse;

Esse função requer um fresnel de Schlick próprio para transmissão de energia, então vamos coloca-lo tambem:

Código:
float FresnelTransmission(float f0, float f90, float u)
{
 real x = 1.0 - u;
 real x2 = x * x;
 real x5 = x * x2 * x2;
 return (1.0 - f90 * x5) - f0 * (1.0 - x5);
}

Código:
float disneyDiffuse(float NoV, float NoL, float LoH, float roughness)
{
 float  energyBias = lerp(0, 0.7, roughness);
 float  energyFactor = lerp(1.0, 1.0 / 1.51, roughness);
 float  fd90 = energyBias + 1.0 * LoH * LoH * roughness;
 float f0 = 1.0f;
 float lightScatter = FresnelTransmission(f0, fd90, NoL);//Controle de transmissao de energia
 float viewScatter = FresnelTransmission(f0, fd90, NoV);
 return  lightScatter * viewScatter * energyFactor;
}


Implementação:
Código:
float3 DirectIllumination(Surface surface, BRDF brdf, Light light) {

 float NoL = dot(surface.normal, light.direction);//Produto escalar entre o vetor Normal e o vetor de direcao da luz
 float3 energyCompensation = 1.0 + NoL * (1.0 / (1.1 - brdf.roughness) - 1.0);

 float3 h = SafeNormalize(light.direction + surface.viewDirection);
 float LoH = dot(light.direction, h);

 if(_DisneyDiffuse == 0)
 return GGX(surface, brdf, light) * FresnelSchlick(surface) * energyCompensation + brdf.diffuse;
 else
 return GGX(surface, brdf, light) * FresnelSchlick(surface) * energyCompensation + (1 / PI * disneyDiffuse(dot(surface.normal, surface.viewDirection), NoL, LoH, brdf.roughness) * brdf.diffuse);

}

Com isso também vamos implementar uma opção para mapas de Roughness em vez de Smoothnes

PBR.shader

Código:
[Enum(Smoothness, 0, Roughness, 1)] _UseRoughness("Smoothness/Roughness", Float) = 0
 [NoScaleOffset] _SmoothnessMap("Smoothness Map(Specular)", 2D) = "white" {} //Mapa de nivel de suavidade

PBRPass.hlsl

Código:
float _UseRoughness;
Código:
 if (_UseRoughness == 0)
 surface.smoothness = smoothness;
 else
 surface.smoothness = PerceptualRoughnessToPerceptualSmoothness(smoothness);

[TUTORIAL] Shader de renderização baseada em física Wiv61ly
Com nivel difuso da Disney


Shader Completo:

Código:
Shader "Magic Byte/Standard PBR" {
 
 Properties {

 _BaseMap("Texture", 2D) = "white" {} //Mapa de textura
 _BaseColor("Color", Color) = (0.5, 0.5, 0.5, 1.0) //Cor de material

 [Enum(Off, 0, On, 1)] _DisneyDiffuse("Disney Diffuse", Float) = 1 //On

 _Metallic("Metallic", Range(0, 1)) = 0 //Nivel metalico (0,1)
 _Smoothness("Smoothness", Range(0, 1)) = 0.5 //Nivel de "superficie aspera" ou nivel de suavidade
 _Occlusion("Occlusion", Range(0, 1)) = 1 //Nivel de microsombras do mapa de oclusao

 [NoScaleOffset] _OcclusionMap("Occlusion Map(AO)", 2D) = "white" {} //Mapa de Oclusao
 [Enum(Smoothness, 0, Roughness, 1)] _UseRoughness("Smoothness/Roughness", Float) = 0
 [NoScaleOffset] _SmoothnessMap("Smoothness Map(Specular)", 2D) = "white" {} //Mapa de nivel de suavidade
 [NoScaleOffset] _MetalMap("Metallic Map", 2D) = "white" {} //Mapa de nivel metalico

 [NoScaleOffset] _EmissionMap("Emission", 2D) = "white" {} //Mapa de emissao
 [HDR] _EmissionColor("Emission", Color) = (0.0, 0.0, 0.0, 0.0) //Cor da emissao

 [NoScaleOffset] _NormalMap("Normals", 2D) = "bump" {} //Mapa normal
 _NormalStrength("Normal Strength", Range(0, 1)) = 1 //Nivel de mapa normal
 
     _Fresnel("Reflectance", Range(0,3)) = 0.0 //Reflectancia do material. (0,3) Para fins artisticos

 /*Blend options*/
 [Enum(UnityEngine.Rendering.BlendMode)] _SrcBlend ("Src Blend", Float) = 1 //One
 [Enum(UnityEngine.Rendering.BlendMode)] _DstBlend ("Dst Blend", Float) = 0 //Zero
 [Enum(Off, 0, On, 1)] _ZWrite ("Z Write", Float) = 1 //On
 /*Blend options*/

 [HideInInspector] _MainTex("Lightmap Texture", 2D) = "white" {} // Uso de GI em SRP (Retrire essas propriedades)
 [HideInInspector] _Color("Lightmap Color", Color) = (0.5, 0.5, 0.5, 1.0) // Uso de GI em SRP (Retrire essas propriedades)
 }
 
 SubShader {
 HLSLINCLUDE
 #include "../../ShaderLibrary/Common.hlsl" //API de graficos da MB (Retire esse include)
 ENDHLSL

 Pass {
 Tags {
 "LightMode" = "MBLit"
 }

 /*Blend*/
 Blend [_SrcBlend] [_DstBlend]
 ZWrite [_ZWrite]
 /*Blend*/

 HLSLPROGRAM
 /*Features para SRP*/
 #pragma target 3.5
 #pragma shader_feature _CLIPPING
 #pragma shader_feature _RECEIVE_SHADOWS
 #pragma shader_feature _PREMULTIPLY_ALPHA
 #pragma multi_compile _ LOD_FADE_CROSSFADE
 #pragma multi_compile _ _DIRECTIONAL_PCF3 _DIRECTIONAL_PCF5 _DIRECTIONAL_PCF7
 #pragma multi_compile _ _CASCADE_BLEND_SOFT _CASCADE_BLEND_DITHER
 #pragma multi_compile _ _SHADOW_MASK_ALWAYS _SHADOW_MASK_DISTANCE 
 #pragma multi_compile _ LIGHTMAP_ON
 #pragma multi_compile _ DYNAMICLIGHTMAP_ON
 #pragma multi_compile_instancing
 /*Features para SRP*/

 #pragma vertex PBRPassVertex // <-- VERTEX SHADER
 #pragma fragment PBRPassFragment // <-- PIXEL SHADER
 #include "PBRPass.hlsl" // <-- Incluir Arquivo com os Pass
 ENDHLSL
 }

 }
}


Código:
#ifndef PBR_PASS_INCLUDED
#define PBR_PASS_INCLUDED

/* API GRAFICA MB */
#include "../../ShaderLibrary/Surface.hlsl"
#include "../../ShaderLibrary/Shadows.hlsl"
#include "../../ShaderLibrary/Light.hlsl"
#include "../../ShaderLibrary/BRDF.hlsl"
#include "../../ShaderLibrary/GI.hlsl"
#include "../../ShaderLibrary/Lighting.hlsl"
#include "../../ShaderLibrary/ClearCoat.hlsl"
/* API GRAFICA MB */

TEXTURE2D(_BaseMap);
SAMPLER(sampler_BaseMap);

TEXTURE2D(_NormalMap);
SAMPLER(sampler_NormalMap);

TEXTURE2D(_OcclusionMap);
SAMPLER(sampler_OcclusionMap);

TEXTURE2D(_SmoothnessMap);
SAMPLER(sampler_SmoothnessMap);

TEXTURE2D(_MetalMap);
SAMPLER(sampler_MetalMap);

TEXTURE2D(_EmissionMap);
SAMPLER(sampler_EmissionMap);

float4 _BaseColor;
float _NormalStrength;
float _Metallic;
float _Smoothness;
float _Occlusion;
float4 _EmissionColor;
float _Fresnel;
float _DisneyDiffuse;
float _UseRoughness;

struct BRDFstruct {
 float3 diffuse;
 float3 specular;
 float perceptualRoughness;
 float roughness;
};

#define MIN_REFLECTIVITY 0.04

float OneMinReflectivity(float metallic) {
 float size = 1.0 - MIN_REFLECTIVITY;
 return size - metallic * size;
}

BRDFstruct GetBRDFstruct(Surface surface) {
 BRDFstruct brdf;

 brdf.diffuse = surface.color * OneMinReflectivity(surface.metallic);
 brdf.specular = lerp(MIN_REFLECTIVITY, surface.color, surface.metallic);

 brdf.perceptualRoughness = PerceptualSmoothnessToPerceptualRoughness(surface.smoothness);
 brdf.roughness = PerceptualRoughnessToRoughness(brdf.perceptualRoughness);

 return brdf;
}

//GGX
float GGX(Surface surface, BRDFstruct brdf, Light light) {
 float3 h = SafeNormalize(light.direction + surface.viewDirection); //Half Vector (Vetor Mediano)
 float NoH = dot(surface.normal, h); //Produto escalar entre vetor normal e vetor mediano
 float3 NxH = cross(surface.normal, h);//Produto cruzado entre vetor normal e vetor mediano
 float a = NoH * brdf.roughness;
 float k = brdf.roughness / (dot(NxH, NxH) + a * a);
 float d = k * k * (1.0 / PI);//  1/PI <-- Essa e a funcao lambertiana | A divisão por pi existe para normalizar a luz
 return d;
}

float FresnelSchlick(Surface surface) {
 float NoV = dot(surface.normal, surface.viewDirection);
 float f0 = pow(1.0 - NoV, 4.0);//Potencia da 4 grau no inverso (OneMinus) do produto escalar
 return f0 + NoV * (1.0 - f0) * surface.metallic;
}

float FresnelTransmission(float f0, float f90, float u)
{
 real x = 1.0 - u;
 real x2 = x * x;
 real x5 = x * x2 * x2;
 return (1.0 - f90 * x5) - f0 * (1.0 - x5);
}

float Diffuse(float NoV, float NoL, float LoH, float roughness)
{
 float  energyBias = lerp(0, 0.7, roughness);
 float  energyFactor = lerp(1.0, 1.0 / 1.51, roughness);
 float  fd90 = energyBias + 1.0 * LoH * LoH * roughness;
 float f0 = 1.0f;
 float lightScatter = FresnelTransmission(f0, fd90, NoL);//Controle de transmissao de energia
 float viewScatter = FresnelTransmission(f0, fd90, NoV);
 return  lightScatter * viewScatter * energyFactor;
}

float3 DirectIllumination(Surface surface, BRDFstruct brdf, Light light) {

 float NoL = dot(surface.normal, light.direction);//Produto escalar entre o vetor Normal e o vetor de direcao da luz
 float3 energyCompensation = 1.0 + NoL * (1.0 / (1.1 - brdf.roughness) - 1.0);

 float3 h = SafeNormalize(light.direction + surface.viewDirection);
 float LoH = dot(light.direction, h);

 if(_DisneyDiffuse == 0)
 return GGX(surface, brdf, light) * FresnelSchlick(surface) * energyCompensation + brdf.diffuse;
 else
 return GGX(surface, brdf, light) * FresnelSchlick(surface) * energyCompensation + (1 / PI * Diffuse(dot(surface.normal, surface.viewDirection), NoL, LoH, brdf.roughness) * brdf.diffuse);

}

float3 IndirectIllumination(Surface surface, BRDFstruct brdf, float3 diffuse, float3 specular) {

 float3 reflection = specular * lerp(brdf.specular, saturate(surface.smoothness + 1.0 - OneMinReflectivity(surface.metallic)), FresnelSchlick(surface));
 reflection /= brdf.roughness * brdf.roughness + 1.0;

 return (diffuse * (brdf.diffuse / PI) + reflection) * surface.occlusion;
}

struct Attributes {
 float3 positionOS : POSITION;
 float3 normalOS : NORMAL;
 float4 tangentOS : TANGENT;
 float2 baseUV : TEXCOORD0;
 float2 lightmapUV: TEXCOORD1;
 float2 dynamicLightmapUV : TEXCOORD2;
 UNITY_VERTEX_INPUT_INSTANCE_ID
};

struct Varyings {
 float4 positionCS : SV_POSITION;
 float3 positionWS : VAR_POSITION;
 float3 normalWS : VAR_NORMAL;
 float4 tangentWS : VAR_TANGENT;
 float2 baseUV : VAR_BASE_UV;
 float2 lightmapUV : TEXCOORD4;
 float2 dynamicLightmapUV : TEXCOORD5;
 UNITY_VERTEX_INPUT_INSTANCE_ID
};

Varyings PBRPassVertex (Attributes input) {
 Varyings output;

 /* API GRAFICA MB */
 output.lightmapUV = input.lightmapUV * unity_LightmapST.xy + unity_LightmapST.zw;
 output.dynamicLightmapUV = input.dynamicLightmapUV * unity_DynamicLightmapST.xy + unity_DynamicLightmapST.zw;
 /* API GRAFICA MB */

 /* Render Pipelines Core */
 output.positionWS = TransformObjectToWorld(input.positionOS);
 output.positionCS = TransformWorldToHClip(output.positionWS);
 output.normalWS = TransformObjectToWorldNormal(input.normalOS);
 output.tangentWS = float4(TransformObjectToWorldDir(input.tangentOS.xyz), input.tangentOS.w);
 output.baseUV = input.baseUV;
 /* Render Pipelines Core */

 return output;
}

float4 _Time; //Funcao tempo importada da unity por buffer

float3 Lighting(Surface surface, GI gi) {
 ShadowData shadowData = GetShadowData(surface);
 shadowData.shadowMask = gi.shadowMask;

 BRDFstruct brdf = GetBRDFstruct(surface);

 float3 color = IndirectIllumination(surface, brdf, gi.diffuse, gi.specular);
 for (int i = 0; i < GetDirectionalLightCount(); i++) {
 Light light = GetDirectionalLight(i, surface, shadowData);//Compilar Luz
 color += dot(surface.normal, light.direction) * light.attenuation * light.color;
 color *= DirectIllumination(surface, brdf, light);//Adicionar sombra propria
 }
 return color;
}

float4 PBRPassFragment(Varyings input) : SV_TARGET{
 float3 color = (0,0,0);

 Surface surface;
 surface.position = input.positionWS;

 float4 Nmap = SAMPLE_TEXTURE2D(_NormalMap, sampler_NormalMap, input.baseUV);
 float3 normal = DecodeNormal(Nmap, _NormalStrength);

 surface.normal = NormalTangentToWorld(normal, input.normalWS, input.tangentWS); // <---- Transformacao de espaco do Render Pipelines Core
 surface.interpolatedNormal = input.normalWS;
 surface.viewDirection = normalize(_WorldSpaceCameraPos - input.positionWS); //Normalizar posicao da camera - posicao de objeto
 surface.tangent = input.tangentWS;
 surface.binormal = cross(NormalTangentToWorld(normal, input.normalWS, input.tangentWS), input.tangentWS.xyz) * input.tangentWS.w;
 surface.color = SAMPLE_TEXTURE2D(_BaseMap, sampler_BaseMap, input.baseUV) * _BaseColor.rgb;
 surface.alpha = _BaseColor.a;

 float metallic = _Metallic;
 metallic *= pow(abs(SAMPLE_TEXTURE2D(_MetalMap, sampler_MetalMap, input.baseUV).r), 2.2); //Correcao de Gamma do mapa (Fins artisticos)

 float smoothness = _Smoothness;
 smoothness *= pow(abs(SAMPLE_TEXTURE2D(_SmoothnessMap, sampler_SmoothnessMap, input.baseUV).r), 2.2); //Correcao de Gamma do mapa (Fins artisticos)
 
 float occlusion = _Occlusion;
 occlusion *= pow(abs(SAMPLE_TEXTURE2D(_OcclusionMap, sampler_OcclusionMap, input.baseUV).r), 2.2); //Correcao de Gamma do mapa (Fins artisticos)

 surface.metallic = metallic;
 if (_UseRoughness == 0)
 surface.smoothness = smoothness;
 else
 surface.smoothness = PerceptualRoughnessToPerceptualSmoothness(smoothness);
 surface.occlusion = occlusion;

 surface.fresnelStrength = _Fresnel;

 GI gi = GetGI(input.lightmapUV, input.dynamicLightmapUV, surface, (1 - surface.smoothness), 1);
 color = Lighting(surface, gi);

 color += SAMPLE_TEXTURE2D(_EmissionMap, sampler_EmissionMap, input.baseUV) * _EmissionColor;

 return float4(color, surface.alpha);
}

#endif

Na Magic Byte, os shader PBR recebem ainda o Clear Coat e o especular anisotrópico, que não serão abordados nesse tutorial por fugirem um pouco da parte que eu queria mostrar.



Esse foi a tutorial sobre teoria de PBR! Espero que seja útil!


Última edição por Matrirxp em Ter Mar 16, 2021 9:42 pm, editado 5 vez(es)
Matrirxp
Matrirxp
ProgramadorMaster

Masculino PONTOS : 3175
REPUTAÇÃO : 86
Idade : 21
Áreas de atuação : Programação: C#, Java, HLSL, CG, GLSL.
Modelagem 3D.
Respeito as regras : [TUTORIAL] Shader de renderização baseada em física Aad8pUi

https://www.youtube.com/channel/UCkngjEDMx9y_vW0t7Io05gg

Ir para o topo Ir para baixo

TUTORIAL Re: [TUTORIAL] Shader de renderização baseada em física

Mensagem por NKKF Dom Out 18, 2020 1:17 am

Código:

//
/*    */


Sem comentários 

[TUTORIAL] Shader de renderização baseada em física E795d3bfaa35b8843bf27b83e65a111d
NKKF
NKKF
ProgramadorMaster

Masculino PONTOS : 4601
REPUTAÇÃO : 574
Idade : 19
Áreas de atuação : Desenvolvedor na Unity, NodeJS, React, ReactJS, React Native, MongoDB e Firebase.
Respeito as regras : [TUTORIAL] Shader de renderização baseada em física Aad8pUi

Ir para o topo Ir para baixo

TUTORIAL Re: [TUTORIAL] Shader de renderização baseada em física

Mensagem por Crash Psycho Qui Out 22, 2020 11:50 am

Parabéns!!!!!!!!!!!!!!

Caralho eu como uma pesosa "leiga" não consigo entender direito kk

Eu lí o seu tópico e percebi que está bem detalhado e explicado, ficou muito bom mesmo kkk

Fico até triste por não conseguir encontrar um amigo do seu nivel kk
Crash Psycho
Crash Psycho
Modelador

Masculino PONTOS : 3541
REPUTAÇÃO : 170
Idade : 24
Áreas de atuação : unity 3D...
Game Design .
Modelador 3d, uso o blender.
se aperfeiçoando na unity 3D.

Respeito as regras : [TUTORIAL] Shader de renderização baseada em física WvDYdlf

https://www.instagram.com/crash_psycho/

Ir para o topo Ir para baixo

Ir para o topo

- Tópicos semelhantes

 
Permissões neste sub-fórum
Não podes responder a tópicos