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:
Quero começa a desenvolver um jogo de luta porem eu queria aprender a faze
ajuda sobre skybox
Salvar objetos que foram destruidos entre cenas na unity
MEU SIMULADOR DE CARRO
Unity - SceneManager.LoadScene abre scene com objeto "vazio"
[_____IMPORTANTE_____] ALTERAÇÕES NA POLÍTICA DE COBRANÇA DA UNITY
[RESOLVIDO] Ausencia da funçao NavMesh na Unity 2022.2.12
Interação com elementos UI
[_____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)
[TUTORIAL] Sistema De Save Game Ao Sair Da Fase
Problema de Sincronização de um objeto de um jogo multiplayer usa q Photon
Unity - Compartilhar meu Jogo
Alguém que manja do Google ADmob?
Unity - Avaliar meu Jogo
[RESOLVIDO] Destruir inimigo com o player.
Salvar e carregar dados na Unity de objetos prefabs sem sobrescrever os dad
Unity - Salvar os Dados do Jogador Online
Input.GetAxis() obedercer a orientação de um objeto.
ajuda com o sistema de drag and drop com controle no invetario
Como executar outros blocos fora do bloco static void Main()
Usando a biblioteca UnityEngine fora da Unity
Mixamo - Character Gratuito?
Touch mobile
Erro NullReferenceException Não consigo resolver
Criador de Sites Freelancer DISPONIVEL!!!
Unity - Não deixar o Jogador alterar o Jogo pelo regedit do pc?
Tiro com Botao UI (ME AJUDEM)
[Projeto em Andamento] Draug, um jogo de hordas
Vagas de programadores e modeladores para startup
Consigo herdar/ copiar parâmetros do animator da unity?
O que seriam os códigos-fonte?
[RESOLVIDO] Unity Vulkan - Out of memory! (allocating memory for image)
Unity Problema de Vírus
[TUTORIAL] Como fazer uma gota de água na Unity
Mirror ou Photon Pun 2 ??? para Mobile
Character Player Modular
Icones não aparecem na Interface da Unity
Verificar se player está posado em blogo
Logica para criar (Player, Inventario, Arma) - Mobile
Sistema de pegar passageiros
Trailer Final de O Labirinto II
Meu jogo não conecta no google play games
ALGUEM ME AJUDA PFV
Problema tentando inserir "Sprite"
Oferto Serviço Programação para Jogos
FAZER AÇÂO AO ENTRAR NO CAMPO DA CAMERA
[RESOLVIDO] QUEBRA DE LINHA NO PLACEHOLDER. Nao lembro como que faz
Unity - Qual o Limite Máximo de Linhas em um Script para q ele fique Leve?
movimento 2d
Alguém que ja publicou na steam pode me ajudar com isso?
Animação Unity toda bugada
UDaySurvival - Jogo de sobrevivência de mundo aberto para mobile!https://yo
Trailer do meu jogo O Labirinto II
Jogo Atisk (Trailer)
Adicionem meu jogo na lista de desejos
Discord!
Como executar a void de um outro scrypt
Shader não funciona no Unity URP
Jogo Mobile - Ultimate Flight Simulator - Real World SDK
Unity - FPS e CPU ???
Usar microfone na Unity
Jogo ficando escuro quando faço a Build pela cena menu
Dúvida sobre movimentação do personagem
[RESOLVIDO] ACESSAR SCRIPT DE OUTRO GAMEOBJECT
Para eu ter shader em meu projeto eu tenho que usar o hdrp ou o 3d padrao?
Rotate Camera Mobile
Sou modelador 3d (!!! Arquitetonico!!!) Disponivel !!!!!!
Preciso de alguém que saiba programação e Raycast
Servidor/cliente usando sockets
Assets carregados com addressables causando erro na versão "buildada"
Jogo multiplayer com salas - não vai para o lobby
Texto - Não escreve no 'play'. Clica mais não digita.
Câmera Não esta renderizando na segunda janela.
Movimento da Câmera No Android
[RESOLVIDO] - Unity não está mais funcionando o "Build and Run"
Precisa de modelador com ou sem experiência
Duvida com "mesclagem" de animação
Missoes Aparecerem aleatoriamente do nada
Dúvida pafra IOS
botoes não esta funcionando corretamente nem a fisica?
Duvida com NavMeshAgent
COMO AUMENTAR E DIMINUÍ A SENSIBILIDADE DO TOQUE POR CÓDICO (MOBILE)
A Licença da Unity só funciona se eu tiver Internet
Problema com OnTriggerEnter
Transparência ao colidir
bool para evitar de salvar frames repetido
Unity - Transições no AnimatorController rodando errado
problemas com "wall Jump" , atribuir força ao eixo X
Meu Jogo ja Esta Pronto! EXPERIMENTEM!!
JOSTICK NAO SE MOVE
botoes para mobile
Hoje à(s) 3:33 pm
Hoje à(s) 12:45 pm
Hoje à(s) 9:24 am
Ontem à(s) 9:02 pm
Ontem à(s) 1:37 pm
Ontem à(s) 9:47 am
Sáb Set 23, 2023 2:10 pm
Sáb Set 23, 2023 12:32 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
Sex Set 15, 2023 10:15 am
Seg Set 11, 2023 11:43 am
Seg Set 11, 2023 11:31 am
Sáb Set 09, 2023 4:53 pm
Sáb Set 09, 2023 1:44 pm
Ter Set 05, 2023 11:12 pm
Ter Set 05, 2023 3:12 pm
Seg Set 04, 2023 11:53 pm
Seg Set 04, 2023 7:39 pm
Dom Set 03, 2023 9:47 pm
Sáb Set 02, 2023 11:53 am
Sex Set 01, 2023 2:21 pm
Qui Ago 31, 2023 8:19 pm
Qui Ago 31, 2023 6:15 pm
Qua Ago 30, 2023 11:21 am
Ter Ago 29, 2023 8:43 pm
Seg Ago 28, 2023 7:18 pm
Sáb Ago 26, 2023 4:49 pm
Sáb Ago 26, 2023 4:38 pm
Qui Ago 17, 2023 1:56 am
Qua Ago 16, 2023 10:21 pm
Seg Ago 14, 2023 12:28 pm
Dom Ago 06, 2023 5:24 pm
Dom Ago 06, 2023 10:58 am
Qui Ago 03, 2023 9:38 am
Qua Ago 02, 2023 8:20 am
Ter Ago 01, 2023 6:07 pm
Dom Jul 30, 2023 5:43 pm
Sáb Jul 29, 2023 7:24 pm
Qui Jul 27, 2023 9:27 am
Seg Jul 24, 2023 11:12 am
Seg Jul 24, 2023 12:44 am
Seg Jul 24, 2023 12:37 am
Seg Jul 24, 2023 12:17 am
Seg Jul 24, 2023 12:10 am
Qua Jul 19, 2023 11:37 am
Ter Jul 18, 2023 7:12 pm
Qua Jul 12, 2023 9:49 am
Ter Jul 11, 2023 8:58 am
Ter Jul 11, 2023 1:03 am
Seg Jul 10, 2023 9:10 pm
Sex Jul 07, 2023 4:14 pm
Ter Jul 04, 2023 12:11 am
Sex Jun 30, 2023 8:10 pm
Qui Jun 29, 2023 5:19 pm
Qui Jun 29, 2023 3:40 pm
Ter Jun 27, 2023 1:45 am
Seg Jun 19, 2023 11:03 am
Dom Jun 18, 2023 6:11 pm
Dom Jun 04, 2023 2:41 pm
Ter maio 30, 2023 7:28 pm
Ter maio 30, 2023 6:04 am
Seg maio 29, 2023 7:53 pm
Sáb maio 27, 2023 3:11 pm
Sex maio 26, 2023 4:59 pm
Sex maio 26, 2023 11:27 am
Qui maio 25, 2023 10:33 am
Sáb maio 20, 2023 12:25 pm
Ter maio 16, 2023 5:43 pm
Ter maio 16, 2023 5:42 pm
Ter maio 09, 2023 7:42 pm
Seg maio 08, 2023 7:13 am
Seg maio 08, 2023 6:38 am
Sáb maio 06, 2023 11:44 pm
Sáb maio 06, 2023 6:42 pm
Sáb maio 06, 2023 1:35 am
Qua maio 03, 2023 12:32 pm
Seg maio 01, 2023 8:51 pm
Dom Abr 30, 2023 8:49 pm
Dom Abr 30, 2023 5:06 pm
Sáb Abr 29, 2023 4:05 pm
Qui Abr 27, 2023 4:39 pm
Qui Abr 27, 2023 12:40 am
Ter Abr 25, 2023 5:33 pm
Ter Abr 25, 2023 10:23 am
Dom Abr 23, 2023 12:11 am
Sáb Abr 22, 2023 4:27 am
Sex Abr 21, 2023 11:38 pm
Sex Abr 21, 2023 10:21 pm
Qui Abr 20, 2023 4:57 pm
Qui Abr 20, 2023 12:28 pm
Qua Abr 19, 2023 3:03 pm



































































































[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 : 2968
REPUTAÇÃO : 85
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 : 4394
REPUTAÇÃO : 574
Idade : 18
Á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 : 3334
REPUTAÇÃO : 170
Idade : 23
Á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