example: I can add physic base render to example
296
examples/shaders/pbr/glsl330/pbr.fs
Normal file
|
@ -0,0 +1,296 @@
|
|||
#version 330
|
||||
|
||||
#define MAX_LIGHTS 4
|
||||
#define LIGHT_DIRECTIONAL 0
|
||||
#define LIGHT_POINT 1
|
||||
#define LIGHT_SPOT 2
|
||||
#define PI 3.14159265358979323846
|
||||
|
||||
struct Light{
|
||||
int enabled;
|
||||
int type;
|
||||
float enargy;
|
||||
float cutOff ;
|
||||
float outerCutOff;
|
||||
float constant;
|
||||
float linear ;
|
||||
float quadratic ;
|
||||
float shiny ;
|
||||
float specularStr;
|
||||
vec3 position;
|
||||
vec3 direction;
|
||||
vec3 lightColor;
|
||||
};
|
||||
|
||||
// Input vertex attributes (from vertex shader)
|
||||
in vec3 fragPosition;
|
||||
in vec2 fragTexCoord;
|
||||
in vec4 fragColor;
|
||||
in vec3 fragNormal;
|
||||
in vec4 shadowPos;
|
||||
in mat3 TBN;
|
||||
|
||||
// Output fragment color
|
||||
out vec4 finalColor;
|
||||
// mask
|
||||
uniform sampler2D mask;
|
||||
uniform int frame;
|
||||
// Input uniform values
|
||||
uniform int numOfLights = 4;
|
||||
uniform sampler2D albedoMap;
|
||||
uniform sampler2D mraMap;
|
||||
uniform sampler2D normalMap;
|
||||
uniform sampler2D emissiveMap; // r: Hight g:emissive
|
||||
// Input uniform values
|
||||
uniform sampler2D texture0;
|
||||
uniform sampler2D texture1;
|
||||
uniform sampler2D flashlight;
|
||||
|
||||
uniform vec4 colDiffuse;
|
||||
|
||||
uniform vec2 tiling = vec2(0.5);
|
||||
uniform vec2 offset ;
|
||||
uniform vec2 tilingFlashlight = vec2(0.5);
|
||||
uniform vec2 offsetFlashlight ;
|
||||
|
||||
uniform int useTexAlbedo =1;
|
||||
uniform int useTexNormal = 0;
|
||||
uniform int useTexMRA =1;
|
||||
uniform int useTexEmissive =1;
|
||||
|
||||
uniform vec4 albedoColor ;
|
||||
uniform vec4 emissiveColor ;
|
||||
uniform float normalValue =0.5;
|
||||
uniform float metallicValue =0.4;
|
||||
uniform float roughnessValue =0;
|
||||
uniform float aoValue =0.8;
|
||||
uniform float emissivePower ;
|
||||
|
||||
// Input lighting values
|
||||
uniform Light lights[MAX_LIGHTS];
|
||||
uniform vec3 viewPos;
|
||||
|
||||
uniform vec3 ambientColor = vec3(1,1,1);
|
||||
uniform float ambientStrength = 0.2;
|
||||
uniform float ambient = 0.03;
|
||||
uniform float fogDensity;
|
||||
|
||||
vec3 CalcDirLight(Light light,vec3 normal,vec3 viewDir,vec3 albedo,vec3 baseRefl,float roughness,float metallic);
|
||||
vec3 CalcPointLight(Light light,vec3 normal,vec3 viewDir,vec3 albedo,vec3 baseRefl,float roughness,float metallic);
|
||||
vec3 CalcSpotLight(Light light,vec3 normal,vec3 viewDir,vec3 albedo,vec3 baseRefl,float roughness,float metallic);
|
||||
|
||||
// Reflectivity in range 0.0 to 1.0
|
||||
// NOTE: Reflectivity is increased when surface view at larger angle
|
||||
vec3 SchlickFresnel(float hDotV,vec3 refl)
|
||||
{
|
||||
return refl + (1.0 - refl)*pow(1.0 - hDotV, 5.0);
|
||||
}
|
||||
|
||||
float GgxDistribution(float nDotH,float roughness)
|
||||
{
|
||||
float a = roughness * roughness * roughness * roughness;
|
||||
float d = nDotH * nDotH * (a - 1.0) + 1.0;
|
||||
d = PI * d * d;
|
||||
return a / max(d,0.0000001);
|
||||
}
|
||||
|
||||
float GeomSmith(float nDotV,float nDotL,float roughness)
|
||||
{
|
||||
float r = roughness + 1.0;
|
||||
float k = r*r / 8.0;
|
||||
float ik = 1.0 - k;
|
||||
float ggx1 = nDotV/(nDotV*ik + k);
|
||||
float ggx2 = nDotL/(nDotL*ik + k);
|
||||
return ggx1*ggx2;
|
||||
}
|
||||
|
||||
vec3 ComputePBR()
|
||||
{
|
||||
vec3 albedo = texture(albedoMap,vec2(fragTexCoord.x*tiling.x + offset.x, fragTexCoord.y*tiling.y + offset.y)).rgb;
|
||||
albedo = vec3(albedoColor.x*albedo.x, albedoColor.y*albedo.y, albedoColor.z*albedo.z);
|
||||
|
||||
float metallic = clamp(metallicValue, 0.0, 1.0);
|
||||
float roughness = clamp(roughnessValue, 0.0, 1.0);
|
||||
float ao = clamp(aoValue, 0.0, 1.0);
|
||||
|
||||
if (useTexMRA == 1)
|
||||
{
|
||||
vec4 mra = texture(mraMap, vec2(fragTexCoord.x*tiling.x + offset.x, fragTexCoord.y*tiling.y + offset.y))*useTexMRA;
|
||||
metallic = clamp(mra.r + metallicValue, 0.04, 1.0);
|
||||
roughness = clamp(mra.g + roughnessValue, 0.04, 1.0);
|
||||
ao = (mra.b + aoValue)*0.5;
|
||||
}
|
||||
|
||||
vec3 N = normalize(fragNormal);
|
||||
if (useTexNormal == 1)
|
||||
{
|
||||
N = texture(normalMap, vec2(fragTexCoord.x*tiling.x + offset.y, fragTexCoord.y*tiling.y + offset.y)).rgb;
|
||||
N = normalize(N*2.0 - 1.0);
|
||||
N = normalize(N*TBN);
|
||||
}
|
||||
|
||||
vec3 V = normalize(viewPos - fragPosition);
|
||||
|
||||
vec3 emissive = vec3(0);
|
||||
emissive = (texture(emissiveMap, vec2(fragTexCoord.x*tiling.x+offset.x, fragTexCoord.y*tiling.y+offset.y)).rgb).g * emissiveColor.rgb*emissivePower * useTexEmissive;
|
||||
|
||||
// return N;//vec3(metallic,metallic,metallic);
|
||||
// if dia-electric use base reflectivity of 0.04 otherwise ut is a metal use albedo as base reflectivity
|
||||
vec3 baseRefl = mix(vec3(0.04), albedo.rgb, metallic);
|
||||
vec3 lightAccum = vec3(0.0); // Acumulate lighting lum
|
||||
|
||||
vec3 norm=N;
|
||||
vec3 viewDir=V;
|
||||
vec3 result = vec3(0.0);
|
||||
|
||||
for (int i = 0; i < MAX_LIGHTS; i++){
|
||||
|
||||
if(lights[i].enabled == 1){
|
||||
|
||||
if(lights[i].type == LIGHT_DIRECTIONAL){
|
||||
result += CalcDirLight(lights[i],norm,viewDir,albedo,baseRefl,roughness,metallic);
|
||||
}
|
||||
|
||||
if(lights[i].type == LIGHT_POINT){
|
||||
result += CalcPointLight(lights[i],norm,viewDir,albedo,baseRefl,roughness,metallic);
|
||||
}
|
||||
|
||||
if(lights[i].type == LIGHT_SPOT){
|
||||
result += CalcSpotLight(lights[i],norm,viewDir,albedo,baseRefl,roughness,metallic);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
vec3 ambientFinal = (ambientColor + albedo)*ambient*0.5;
|
||||
|
||||
return ambientFinal+result*ao + emissive;
|
||||
|
||||
}
|
||||
|
||||
|
||||
void main()
|
||||
{
|
||||
vec3 color = ComputePBR();
|
||||
|
||||
// HDR tonemapping
|
||||
color = pow(color, color + vec3(1.0));
|
||||
|
||||
// // Gamma correction
|
||||
// color = pow(color, vec3(1.0/2.5));
|
||||
|
||||
// Fog calculation
|
||||
float dist = length(viewPos - fragPosition);
|
||||
|
||||
// these could be parameters...
|
||||
const vec4 fogColor = vec4(0.5, 0.5, 0.5, 1.0);
|
||||
|
||||
|
||||
// Exponential fog
|
||||
float fogFactor = 1.0/exp((dist*fogDensity)*(dist*fogDensity));
|
||||
|
||||
|
||||
fogFactor = clamp(fogFactor, 0.0, 1.0);
|
||||
|
||||
finalColor = mix(fogColor,vec4(color,1.0), fogFactor);
|
||||
}
|
||||
|
||||
|
||||
|
||||
vec3 CalcDirLight(Light light,vec3 normal,vec3 viewDir,vec3 albedo,vec3 baseRefl,float roughness,float metallic)
|
||||
{
|
||||
|
||||
vec3 L = normalize(-light.direction);
|
||||
float diff=max(dot(normal,L),0.0);
|
||||
vec3 diffuse=light.lightColor*diff*vec3(texture(texture0,fragTexCoord));
|
||||
vec3 H = normalize(diffuse + L);
|
||||
|
||||
// Cook-Torrance BRDF distribution function
|
||||
float nDotV = max(dot(normal,viewDir), 0.0000001);
|
||||
float nDotL = max(dot(normal,L), 0.0000001);
|
||||
float hDotV = max(dot(H,viewDir), 0.0);
|
||||
float nDotH = max(dot(normal,H), 0.0);
|
||||
float D = GgxDistribution(nDotH, roughness); // Larger the more micro-facets aligned to H
|
||||
float G = GeomSmith(nDotV, nDotL, roughness); // Smaller the more micro-facets shadow
|
||||
vec3 F = SchlickFresnel(hDotV, baseRefl); // Fresnel proportion of specular reflectance
|
||||
|
||||
vec3 spec = (D*G*F)/(4.0*nDotV*nDotL);
|
||||
|
||||
// Difuse and spec light can't be above 1.0
|
||||
// kD = 1.0 - kS diffuse component is equal 1.0 - spec comonent
|
||||
vec3 kD = vec3(1.0) - F;
|
||||
// Mult kD by the inverse of metallnes, only non-metals should have diffuse light
|
||||
kD *= 1.0 - metallic;
|
||||
// Angle of light has impact on result
|
||||
return ((kD*albedo.rgb/PI + spec)*nDotL)*light.enabled;
|
||||
|
||||
}
|
||||
|
||||
vec3 CalcPointLight(Light light,vec3 normal,vec3 viewDir,vec3 albedo,vec3 baseRefl,float roughness,float metallic)
|
||||
{
|
||||
|
||||
vec3 L = normalize(light.position - fragPosition);
|
||||
vec3 H = normalize(viewDir + L);
|
||||
float distance=length(light.position-fragPosition);
|
||||
float attenuation=light.enargy/(light.constant+light.linear*distance+light.quadratic*(distance*distance));
|
||||
vec3 radiance = light.lightColor.rgb*light.enargy*attenuation;
|
||||
|
||||
// Cook-Torrance BRDF distribution function
|
||||
float nDotV = max(dot(normal,viewDir), 0.0000001);
|
||||
float nDotL = max(dot(normal,L), 0.0000001);
|
||||
float hDotV = max(dot(H,viewDir), 0.0);
|
||||
float nDotH = max(dot(normal,H), 0.0);
|
||||
float D = GgxDistribution(nDotH, roughness); // Larger the more micro-facets aligned to H
|
||||
float G = GeomSmith(nDotV, nDotL, roughness); // Smaller the more micro-facets shadow
|
||||
vec3 F = SchlickFresnel(hDotV, baseRefl); // Fresnel proportion of specular reflectance
|
||||
|
||||
vec3 spec = (D*G*F)/(4.0*nDotV*nDotL);
|
||||
|
||||
// Difuse and spec light can't be above 1.0
|
||||
// kD = 1.0 - kS diffuse component is equal 1.0 - spec comonent
|
||||
vec3 kD = vec3(1.0) - F;
|
||||
// Mult kD by the inverse of metallnes, only non-metals should have diffuse light
|
||||
kD *= 1.0 - metallic;
|
||||
// Angle of light has impact on result
|
||||
return ((kD*albedo.rgb/PI + spec)*radiance*nDotL)*light.enabled ;
|
||||
}
|
||||
|
||||
vec3 CalcSpotLight(Light light,vec3 normal,vec3 viewDir,vec3 albedo,vec3 baseRefl,float roughness,float metallic){
|
||||
|
||||
vec3 L = normalize(light.position - fragPosition);
|
||||
|
||||
float theta=dot(L,normalize(-light.direction));
|
||||
float epsilon=cos(radians(light.cutOff))-cos(radians(light.outerCutOff));
|
||||
float intensity=smoothstep(0.0,1.0,(theta-cos(radians(light.outerCutOff)))/epsilon);//clamp((theta-cos(radians(light.outerCutOff)))/epsilon,0.0,1.0);
|
||||
intensity*= length(vec3(texture(flashlight,vec2(fragTexCoord.x*tilingFlashlight.x + offsetFlashlight.y, fragTexCoord.y*tilingFlashlight.y + offsetFlashlight.y)).rgb));
|
||||
|
||||
float diff=max(dot(normal,L),0.0);
|
||||
vec3 H = light.lightColor*diff*vec3(texture(texture0,fragTexCoord));
|
||||
float distance=length(light.position-fragPosition);
|
||||
float attenuation=light.enargy/(light.constant+light.linear*distance+light.quadratic*(distance*distance));
|
||||
vec3 radiance = light.lightColor.rgb*light.enargy*attenuation;
|
||||
H*=intensity;
|
||||
|
||||
// Cook-Torrance BRDF distribution function
|
||||
float nDotV = max(dot(normal,viewDir), 0.0000001);
|
||||
float nDotL = max(dot(normal,L), 0.0000001);
|
||||
float hDotV = max(dot(H,viewDir), 0.0);
|
||||
float nDotH = max(dot(normal,H), 0.0);
|
||||
float D = GgxDistribution(nDotH, roughness); // Larger the more micro-facets aligned to H
|
||||
float G = GeomSmith(nDotV, nDotL, roughness); // Smaller the more micro-facets shadow
|
||||
vec3 F = SchlickFresnel(hDotV, baseRefl); // Fresnel proportion of specular reflectance
|
||||
|
||||
vec3 spec = (D*G*F)/(4.0*nDotV*nDotL);
|
||||
spec*=intensity;
|
||||
|
||||
|
||||
// Difuse and spec light can't be above 1.0
|
||||
// kD = 1.0 - kS diffuse component is equal 1.0 - spec comonent
|
||||
vec3 kD = vec3(1.0) - F;
|
||||
// Mult kD by the inverse of metallnes, only non-metals should have diffuse light
|
||||
kD *= 1.0 - metallic;
|
||||
// Angle of light has impact on result
|
||||
return ((kD*albedo.rgb/PI + spec)*radiance*nDotL)*light.enabled;
|
||||
}
|
||||
|
50
examples/shaders/pbr/glsl330/pbr.vs
Normal file
|
@ -0,0 +1,50 @@
|
|||
#version 330
|
||||
|
||||
// Input vertex attributes
|
||||
in vec3 vertexPosition;
|
||||
in vec2 vertexTexCoord;
|
||||
in vec3 vertexNormal;
|
||||
in vec3 vertexTangent;
|
||||
in vec4 vertexColor;
|
||||
|
||||
// Input uniform values
|
||||
uniform mat4 mvp;
|
||||
uniform mat4 matModel;
|
||||
uniform mat4 matNormal;
|
||||
uniform vec3 lightPos;
|
||||
uniform vec4 difColor;
|
||||
|
||||
// Output vertex attributes (to fragment shader)
|
||||
out vec3 fragPosition;
|
||||
out vec2 fragTexCoord;
|
||||
out vec2 fragTexCoord2;
|
||||
out vec4 fragColor;
|
||||
out vec3 fragNormal;
|
||||
out mat3 TBN;
|
||||
|
||||
const float normalOffset = 0.1;
|
||||
|
||||
void main()
|
||||
{
|
||||
// Compute binormal from vertex normal and tangent
|
||||
vec3 vertexBinormal = cross(vertexNormal, vertexTangent);
|
||||
|
||||
// Compute fragment normal based on normal transformations
|
||||
mat3 normalMatrix = transpose(inverse(mat3(matModel)));
|
||||
|
||||
// Compute fragment position based on model transformations
|
||||
fragPosition = vec3(matModel*vec4(vertexPosition, 1.0f));
|
||||
|
||||
fragTexCoord = vertexTexCoord;
|
||||
fragNormal = normalize(normalMatrix*vertexNormal);
|
||||
vec3 fragTangent = normalize(normalMatrix*vertexTangent);
|
||||
fragTangent = normalize(fragTangent - dot(fragTangent, fragNormal)*fragNormal);
|
||||
vec3 fragBinormal = normalize(normalMatrix*vertexBinormal);
|
||||
fragBinormal = cross(fragNormal, fragTangent);
|
||||
|
||||
TBN = transpose(mat3(fragTangent, fragBinormal, fragNormal));
|
||||
|
||||
// Calculate final vertex position
|
||||
gl_Position = mvp*vec4(vertexPosition, 1.0);
|
||||
}
|
||||
|
212
examples/shaders/pbr/light.go
Normal file
|
@ -0,0 +1,212 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
rl "github.com/gen2brain/raylib-go/raylib"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
type LightType int32
|
||||
|
||||
const (
|
||||
LightTypeDirectional LightType = iota
|
||||
LightTypePoint
|
||||
LightTypeSpot
|
||||
)
|
||||
|
||||
type Light struct {
|
||||
Shader rl.Shader
|
||||
combineStatus bool
|
||||
lightType LightType
|
||||
position rl.Vector3
|
||||
direction rl.Vector3
|
||||
lightColor rl.Color
|
||||
enabled int32
|
||||
enargy float32
|
||||
cutOff float32
|
||||
outerCutOff float32
|
||||
constant float32
|
||||
linear float32
|
||||
quadratic float32
|
||||
shiny float32
|
||||
specularStr float32
|
||||
// shader locations
|
||||
enabledLoc int32
|
||||
typeLoc int32
|
||||
posLoc int32
|
||||
dirLoc int32
|
||||
colorLoc int32
|
||||
viewPosLoc int32
|
||||
enargyLoc int32
|
||||
cutOffLoc int32
|
||||
outerCutOffLoc int32
|
||||
constantLoc int32
|
||||
linearLoc int32
|
||||
quadraticLoc int32
|
||||
shinyLoc int32
|
||||
specularStrLoc int32
|
||||
}
|
||||
|
||||
var MaxLights = 5
|
||||
var lightCount = 0
|
||||
|
||||
func (lt *Light) NewLight(
|
||||
lightType LightType,
|
||||
position, direction rl.Vector3,
|
||||
color rl.Color,
|
||||
enargy float32, shader *rl.Shader) Light {
|
||||
|
||||
light := Light{
|
||||
Shader: *shader,
|
||||
}
|
||||
|
||||
if lightCount < MaxLights {
|
||||
light.enabled = 1
|
||||
light.lightType = lightType
|
||||
light.position = position
|
||||
light.direction = direction
|
||||
light.lightColor = color
|
||||
light.enargy = enargy
|
||||
light.cutOff = 12.5
|
||||
light.outerCutOff = 17.5
|
||||
light.constant = 1.0
|
||||
light.linear = 0.09
|
||||
light.quadratic = 0.032
|
||||
light.shiny = 32.0
|
||||
light.specularStr = 0.9
|
||||
light.enabledLoc = rl.GetShaderLocation(*shader, fmt.Sprintf("lights[%d].enabled", lightCount))
|
||||
light.typeLoc = rl.GetShaderLocation(*shader, fmt.Sprintf("lights[%d].type", lightCount))
|
||||
light.posLoc = rl.GetShaderLocation(*shader, fmt.Sprintf("lights[%d].position", lightCount))
|
||||
light.dirLoc = rl.GetShaderLocation(*shader, fmt.Sprintf("lights[%d].direction", lightCount))
|
||||
light.colorLoc = rl.GetShaderLocation(*shader, fmt.Sprintf("lights[%d].lightColor", lightCount))
|
||||
light.enargyLoc = rl.GetShaderLocation(*shader, fmt.Sprintf("lights[%d].enargy", lightCount))
|
||||
light.cutOffLoc = rl.GetShaderLocation(*shader, fmt.Sprintf("lights[%d].cutOff", lightCount))
|
||||
light.outerCutOffLoc = rl.GetShaderLocation(*shader, fmt.Sprintf("lights[%d].outerCutOff", lightCount))
|
||||
light.constantLoc = rl.GetShaderLocation(*shader, fmt.Sprintf("lights[%d].constant", lightCount))
|
||||
light.linearLoc = rl.GetShaderLocation(*shader, fmt.Sprintf("lights[%d].linear", lightCount))
|
||||
light.quadraticLoc = rl.GetShaderLocation(*shader, fmt.Sprintf("lights[%d].quadratic", lightCount))
|
||||
light.shinyLoc = rl.GetShaderLocation(*shader, fmt.Sprintf("lights[%d].shiny", lightCount))
|
||||
light.specularStrLoc = rl.GetShaderLocation(*shader, fmt.Sprintf("lights[%d].specularStr", lightCount))
|
||||
|
||||
light.UpdateValues()
|
||||
lightCount++
|
||||
}
|
||||
return light
|
||||
}
|
||||
|
||||
func (lt *Light) UpdateValues() {
|
||||
// Send to shader light enabled state and type
|
||||
rl.SetShaderValue(lt.Shader, lt.enabledLoc, unsafe.Slice((*float32)(unsafe.Pointer(<.enabled)), 4), rl.ShaderUniformInt)
|
||||
rl.SetShaderValue(lt.Shader, lt.typeLoc, unsafe.Slice((*float32)(unsafe.Pointer(<.lightType)), 4), rl.ShaderUniformInt)
|
||||
|
||||
// Send to shader light position values
|
||||
rl.SetShaderValue(lt.Shader, lt.posLoc, []float32{lt.position.X, lt.position.Y, lt.position.Z}, rl.ShaderUniformVec3)
|
||||
|
||||
// Send to shader light direction values
|
||||
rl.SetShaderValue(lt.Shader, lt.dirLoc, []float32{lt.direction.X, lt.direction.Y, lt.direction.Z}, rl.ShaderUniformVec3)
|
||||
|
||||
// Send to shader light color values
|
||||
rl.SetShaderValue(lt.Shader, lt.colorLoc,
|
||||
[]float32{float32(lt.lightColor.R) / 255, float32(lt.lightColor.G) / 255, float32(lt.lightColor.B) / 255},
|
||||
rl.ShaderUniformVec3)
|
||||
|
||||
// Send to shader light enargy values
|
||||
rl.SetShaderValue(lt.Shader, lt.enargyLoc, []float32{lt.enargy}, rl.ShaderUniformFloat)
|
||||
|
||||
// Send to shader light spot values
|
||||
rl.SetShaderValue(lt.Shader, lt.cutOffLoc, []float32{lt.cutOff}, rl.ShaderUniformFloat)
|
||||
rl.SetShaderValue(lt.Shader, lt.outerCutOffLoc, []float32{lt.outerCutOff}, rl.ShaderUniformFloat)
|
||||
|
||||
// Send to shader light pointLight values
|
||||
rl.SetShaderValue(lt.Shader, lt.constantLoc, []float32{lt.constant}, rl.ShaderUniformFloat)
|
||||
rl.SetShaderValue(lt.Shader, lt.linearLoc, []float32{lt.linear}, rl.ShaderUniformFloat)
|
||||
rl.SetShaderValue(lt.Shader, lt.quadraticLoc, []float32{lt.quadratic}, rl.ShaderUniformFloat)
|
||||
|
||||
// Send to shader light shiness values
|
||||
rl.SetShaderValue(lt.Shader, lt.shinyLoc, []float32{lt.shiny}, rl.ShaderUniformFloat)
|
||||
rl.SetShaderValue(lt.Shader, lt.specularStrLoc, []float32{lt.specularStr}, rl.ShaderUniformFloat)
|
||||
|
||||
}
|
||||
|
||||
// if you want more 5 light in the light.fs change #define MAX_LIGHTS "your number"
|
||||
func (lt *Light) SetMaxLight(max int) {
|
||||
MaxLights = max
|
||||
}
|
||||
|
||||
func (lt *Light) SetConfigSpotLight(light *Light, cutOff, outerCutOff float32) {
|
||||
light.cutOff = cutOff
|
||||
light.outerCutOff = outerCutOff
|
||||
light.UpdateValues()
|
||||
}
|
||||
|
||||
func (lt *Light) SetConfigPointLight(light *Light, constant, linear, quadratic float32) {
|
||||
light.constant = constant
|
||||
light.linear = linear
|
||||
light.quadratic = quadratic
|
||||
light.UpdateValues()
|
||||
}
|
||||
|
||||
func (lt *Light) SetConfigShiness(light *Light, shiny, specularStr float32) {
|
||||
light.shiny = shiny
|
||||
light.specularStr = specularStr
|
||||
light.UpdateValues()
|
||||
}
|
||||
|
||||
func (lt *Light) SetMaterialTexture(materials []*rl.Material, texture []*rl.Texture2D) {
|
||||
for index, material := range materials {
|
||||
rl.SetMaterialTexture(material, rl.MapDiffuse, *texture[index])
|
||||
}
|
||||
}
|
||||
|
||||
func (lt *Light) SetFlashlightTexture(materials []*rl.Material, texure *rl.Texture2D) {
|
||||
|
||||
lt.Shader.UpdateLocation(rl.ShaderLocMapOcclusion, rl.GetShaderLocation(lt.Shader, "flashlight"))
|
||||
for _, material := range materials {
|
||||
rl.SetMaterialTexture(material, rl.MapOcclusion, *texure)
|
||||
}
|
||||
}
|
||||
|
||||
func (lt *Light) Init(ambientStrength float32, ambientColor rl.Vector3) {
|
||||
if !lt.combineStatus {
|
||||
lt.configShader()
|
||||
}
|
||||
lt.viewPosLoc = rl.GetShaderLocation(lt.Shader, "viewPos")
|
||||
rl.SetShaderValue(lt.Shader, rl.GetShaderLocation(lt.Shader, "ambientColor"), []float32{ambientColor.X, ambientColor.Y, ambientColor.Z}, rl.ShaderUniformVec3)
|
||||
rl.SetShaderValue(lt.Shader, rl.GetShaderLocation(lt.Shader, "ambientStrength"), []float32{ambientStrength}, rl.ShaderUniformFloat)
|
||||
}
|
||||
|
||||
func (lt *Light) DisableLight(light *Light) {
|
||||
light.enabled *= -1
|
||||
light.UpdateValues()
|
||||
}
|
||||
|
||||
func (lt *Light) EnableLight(light *Light) {
|
||||
light.enabled = 1
|
||||
light.UpdateValues()
|
||||
}
|
||||
|
||||
func (lt *Light) DrawSpherelight(light *Light) {
|
||||
if light.enabled == 1 {
|
||||
rl.DrawSphereEx(light.position, 0.2, 8, 8, light.lightColor)
|
||||
} else {
|
||||
rl.DrawSphereWires(light.position, 0.2, 8, 8, rl.Fade(light.lightColor, 0.3))
|
||||
}
|
||||
}
|
||||
|
||||
func (lt *Light) UpdateReflect(cameraPos rl.Vector3) {
|
||||
rl.SetShaderValue(lt.Shader, lt.viewPosLoc, []float32{cameraPos.X, cameraPos.Y, cameraPos.Z}, rl.ShaderUniformVec3)
|
||||
}
|
||||
|
||||
func (lt *Light) configShader() {
|
||||
lt.Shader = rl.LoadShader("pbr.vs","./pbr.fs")
|
||||
}
|
||||
|
||||
// exce before init or set manually
|
||||
func (lt *Light) SetCombineShader(CombineShader *rl.Shader) {
|
||||
lt.combineStatus = true
|
||||
lt.Shader = *CombineShader
|
||||
}
|
||||
|
||||
func (lt *Light) Unload() {
|
||||
rl.UnloadShader(lt.Shader)
|
||||
}
|
83
examples/shaders/pbr/main.go
Normal file
|
@ -0,0 +1,83 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
rl "github.com/gen2brain/raylib-go/raylib"
|
||||
)
|
||||
|
||||
func main() {
|
||||
|
||||
screenWidth := int32(900)
|
||||
screenHeight := int32(500)
|
||||
rl.SetConfigFlags(rl.FlagMsaa4xHint) //ENABLE 4X MSAA IF AVAILABLE
|
||||
|
||||
rl.InitWindow(screenWidth, screenHeight, "raylib [shaders] example - basic pbr")
|
||||
|
||||
car := rl.LoadModel("./models/old_car_new.glb")
|
||||
plane := rl.LoadModel("./models/plane.glb")
|
||||
|
||||
cam := rl.Camera3D{}
|
||||
cam.Fovy = 45
|
||||
cam.Position = rl.Vector3{2, 2, 8}
|
||||
cam.Projection = rl.CameraPerspective
|
||||
cam.Up = rl.Vector3{0, 1, 0}
|
||||
|
||||
shader := rl.LoadShader("./glsl330/pbr.vs", "./glsl330/pbr.fs")
|
||||
|
||||
l := Light{}
|
||||
l.SetCombineShader(&shader)
|
||||
l.Init(0.0, rl.Vector3{1, 1, 1})
|
||||
l1 := l.NewLight(LightTypePoint, rl.Vector3{-1, 1, -2}, rl.Vector3{}, rl.Yellow, 4, &l.Shader)
|
||||
l2 := l.NewLight(LightTypePoint, rl.Vector3{2, 1, 1}, rl.Vector3{}, rl.Green, 3.3, &l.Shader)
|
||||
l3 := l.NewLight(LightTypePoint, rl.Vector3{-2, 1, 1}, rl.Vector3{}, rl.Red, 8.3, &l.Shader)
|
||||
l4 := l.NewLight(LightTypePoint, rl.Vector3{1, 1, -2}, rl.Vector3{}, rl.Blue, 2, &l.Shader)
|
||||
|
||||
p := PhysicRender{}
|
||||
p.SetCombineShader(&shader)
|
||||
p.Init()
|
||||
|
||||
p.UseTexAlbedo()
|
||||
p.UseTexMRA()
|
||||
p.UseTexNormal()
|
||||
p.UseTexEmissive()
|
||||
|
||||
car.GetMaterials()[0].Shader = shader
|
||||
|
||||
p.AlbedoColorModel(&car, rl.White)
|
||||
p.MetallicValue(0.0)
|
||||
p.RoughnessValue(0)
|
||||
p.EmissivePower(0.0)
|
||||
p.AoValue(0.0)
|
||||
p.NormalValue(0.2)
|
||||
|
||||
p.EmissiveColor(rl.NewColor(255, 162, 0, 255))
|
||||
p.TextureMapAlbedo(&car.GetMaterials()[0], rl.LoadTexture("models/old_car_d.png"))
|
||||
p.TextureMapMetalness(&car.GetMaterials()[0], rl.LoadTexture("models/old_car_mra.png"))
|
||||
p.TextureMapNormal(&car.GetMaterials()[0], rl.LoadTexture("models/old_car_n.png"))
|
||||
rl.SetMaterialTexture(&car.GetMaterials()[0], rl.MapEmission, rl.LoadTexture("models/old_car_e.png"))
|
||||
|
||||
p.SetTiling(rl.NewVector2(1, 1))
|
||||
|
||||
plane.GetMaterials()[0].Shader = shader
|
||||
p.TextureMapAlbedo(&plane.GetMaterials()[0], rl.LoadTexture("./models/road_a.png"))
|
||||
p.TextureMapNormal(&plane.GetMaterials()[0], rl.LoadTexture("./models/road_n.png"))
|
||||
p.TextureMapMetalness(&plane.GetMaterials()[0], rl.LoadTexture("./models/road_mra.png"))
|
||||
|
||||
rl.SetTargetFPS(60)
|
||||
for !rl.WindowShouldClose() {
|
||||
rl.UpdateCamera(&cam, rl.CameraOrbital)
|
||||
p.UpadteByCamera(cam.Position)
|
||||
rl.BeginDrawing()
|
||||
rl.DrawFPS(10, 20)
|
||||
rl.ClearBackground(rl.Gray)
|
||||
rl.BeginMode3D(cam)
|
||||
rl.DrawModel(car, rl.Vector3{0, 0.01, 0}, 0.25, rl.RayWhite)
|
||||
rl.DrawModel(plane, rl.Vector3{0, 0, 0}, 5, rl.RayWhite)
|
||||
l.DrawSpherelight(&l1)
|
||||
l.DrawSpherelight(&l2)
|
||||
l.DrawSpherelight(&l3)
|
||||
l.DrawSpherelight(&l4)
|
||||
rl.EndMode3D()
|
||||
rl.EndDrawing()
|
||||
}
|
||||
rl.CloseWindow()
|
||||
}
|
BIN
examples/shaders/pbr/models/old_car_d.png
Normal file
After Width: | Height: | Size: 1.6 MiB |
BIN
examples/shaders/pbr/models/old_car_e.png
Normal file
After Width: | Height: | Size: 1.7 KiB |
BIN
examples/shaders/pbr/models/old_car_mra.png
Normal file
After Width: | Height: | Size: 1.1 MiB |
BIN
examples/shaders/pbr/models/old_car_n.png
Normal file
After Width: | Height: | Size: 1.2 MiB |
BIN
examples/shaders/pbr/models/old_car_new.glb
Normal file
BIN
examples/shaders/pbr/models/plane.glb
Normal file
BIN
examples/shaders/pbr/models/road_a.png
Normal file
After Width: | Height: | Size: 623 KiB |
BIN
examples/shaders/pbr/models/road_mra.png
Normal file
After Width: | Height: | Size: 657 KiB |
BIN
examples/shaders/pbr/models/road_n.png
Normal file
After Width: | Height: | Size: 645 KiB |
218
examples/shaders/pbr/pbr.go
Normal file
|
@ -0,0 +1,218 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
"unsafe"
|
||||
rl "github.com/gen2brain/raylib-go/raylib"
|
||||
)
|
||||
|
||||
const (
|
||||
LIGHT_DIRECTIONAL int32 = iota
|
||||
LIGHT_POINT
|
||||
LIGHT_SPOT
|
||||
)
|
||||
|
||||
type light struct {
|
||||
Enabled int32
|
||||
Type int32
|
||||
Target rl.Vector3
|
||||
Position rl.Vector3
|
||||
Color [4]float32
|
||||
Intensity float32
|
||||
// Shader light parameters locations
|
||||
enabledLoc int32
|
||||
typeLoc int32
|
||||
targetLoc int32
|
||||
positionLoc int32
|
||||
colorLoc int32
|
||||
intensityLoc int32
|
||||
}
|
||||
|
||||
type PhysicRender struct {
|
||||
Shader *rl.Shader
|
||||
combineStatus bool
|
||||
}
|
||||
|
||||
// make light and pbr Shader
|
||||
func (ph *PhysicRender) Init() {
|
||||
|
||||
if !ph.combineStatus {
|
||||
ph.configShader()
|
||||
}
|
||||
|
||||
ph.Shader.UpdateLocation(rl.ShaderLocMapAlbedo, rl.GetShaderLocation(*ph.Shader, "albedoMap"))
|
||||
ph.Shader.UpdateLocation(rl.ShaderLocMapMetalness, rl.GetShaderLocation(*ph.Shader, "mraMap"))
|
||||
ph.Shader.UpdateLocation(rl.ShaderLocMapNormal, rl.GetShaderLocation(*ph.Shader, "normalMap"))
|
||||
ph.Shader.UpdateLocation(rl.ShaderLocMapEmission, rl.GetShaderLocation(*ph.Shader, "emissiveMap"))
|
||||
ph.Shader.UpdateLocation(12, rl.GetShaderLocation(*ph.Shader, "albedoColor"))
|
||||
ph.Shader.UpdateLocation(rl.ShaderLocVectorView, rl.GetShaderLocation(*ph.Shader, "viewPos"))
|
||||
|
||||
ambientColor := rl.Color{R: 122, G: 36, B: 26, A: 100}
|
||||
ambientColorNormalized := rl.NewVector3(float32(ambientColor.R)/255.0, float32(ambientColor.G)/255.0, float32(ambientColor.B)/255.0)
|
||||
rl.SetShaderValue(*ph.Shader, rl.GetShaderLocation(*ph.Shader, "ambientColor"), []float32{ambientColorNormalized.X, ambientColorNormalized.Y, ambientColorNormalized.Z}, rl.ShaderUniformVec3)
|
||||
rl.SetShaderValue(*ph.Shader, rl.GetShaderLocation(*ph.Shader, "ambient"), []float32{float32(0.03)}, rl.ShaderUniformFloat)
|
||||
|
||||
lightCountLoc := rl.GetShaderLocation(*ph.Shader, "numOfLights")
|
||||
rl.SetShaderValue(*ph.Shader, lightCountLoc, generiteIntForGlsl(int32(MaxLights)), rl.ShaderUniformInt)
|
||||
|
||||
}
|
||||
|
||||
func (ph *PhysicRender) UpadteByCamera(pos rl.Vector3) {
|
||||
rl.SetShaderValue(*ph.Shader, rl.GetShaderLocation(*ph.Shader, "viewPos"), []float32{pos.X, pos.Y, pos.Z}, rl.ShaderUniformVec3)
|
||||
}
|
||||
|
||||
func (ph *PhysicRender) CreateLight(typeLight int32, position rl.Vector3, target rl.Vector3, color rl.Color, intensity float32) light {
|
||||
light := light{}
|
||||
if lightCount < MaxLights {
|
||||
light.Enabled = 1
|
||||
light.Position = position
|
||||
light.Type = typeLight
|
||||
light.Target = target
|
||||
light.Color[0] = float32(float32(color.R) / 255.0)
|
||||
light.Color[1] = float32(float32(color.G) / 255.0)
|
||||
light.Color[2] = float32(float32(color.B) / 255.0)
|
||||
light.Color[3] = float32(float32(color.A) / 255.0)
|
||||
light.Intensity = intensity
|
||||
// NOTE: Shader parameters names for lights must match the requested ones
|
||||
light.enabledLoc = rl.GetShaderLocation(*ph.Shader, fmt.Sprintf("lights[%d].enabled", lightCount))
|
||||
light.positionLoc = rl.GetShaderLocation(*ph.Shader, fmt.Sprintf("lights[%d].position", lightCount))
|
||||
light.colorLoc = rl.GetShaderLocation(*ph.Shader, fmt.Sprintf("lights[%d].color", lightCount))
|
||||
light.intensityLoc = rl.GetShaderLocation(*ph.Shader, fmt.Sprintf("lights[%d].intensity", lightCount))
|
||||
light.typeLoc = rl.GetShaderLocation(*ph.Shader, fmt.Sprintf("lights[%d].type", lightCount))
|
||||
//light.targetLoc = rl.GetShaderLocation(ph.Shader, fmt.Sprintf("lights[%d].target", lightCount))
|
||||
|
||||
ph.UpdateLight(*ph.Shader, light)
|
||||
|
||||
lightCount++
|
||||
|
||||
}
|
||||
|
||||
return light
|
||||
}
|
||||
|
||||
func (ph *PhysicRender) UpdateLight(Shader rl.Shader, light light) {
|
||||
rl.SetShaderValue(Shader, light.enabledLoc, generiteIntForGlsl(light.Enabled), rl.ShaderUniformInt)
|
||||
rl.SetShaderValue(Shader, light.positionLoc, []float32{light.Position.X, light.Position.Y, light.Position.Z}, rl.ShaderUniformVec3)
|
||||
rl.SetShaderValue(Shader, light.colorLoc, []float32{light.Color[0], light.Color[1], light.Color[2], light.Color[3]}, rl.ShaderUniformVec4)
|
||||
rl.SetShaderValue(Shader, light.intensityLoc, []float32{light.Intensity}, rl.ShaderUniformFloat)
|
||||
rl.SetShaderValue(Shader, light.typeLoc, generiteIntForGlsl(light.Type), rl.ShaderUniformInt)
|
||||
//rl.SetShaderValue(Shader, light.targetLoc,[]float32{light.Target.X, light.Target.Y, light.Target.Z}, rl.ShaderUniformVec3)
|
||||
}
|
||||
|
||||
func (ph *PhysicRender) MaxLights(value int) {
|
||||
MaxLights = value
|
||||
}
|
||||
|
||||
func (ph *PhysicRender) TextureMapAlbedo(modelMaterials *rl.Material, texture rl.Texture2D) {
|
||||
rl.SetMaterialTexture(modelMaterials, rl.MapAlbedo, texture)
|
||||
}
|
||||
|
||||
func (ph *PhysicRender) TextureMapMetalness(modelMaterials *rl.Material, texture rl.Texture2D) {
|
||||
rl.SetMaterialTexture(modelMaterials, rl.MapMetalness, texture)
|
||||
}
|
||||
|
||||
func (ph *PhysicRender) TextureMapRoughness(modelMaterials *rl.Material, texture rl.Texture2D) {
|
||||
rl.SetMaterialTexture(modelMaterials, rl.MapRoughness, texture)
|
||||
}
|
||||
|
||||
func (ph *PhysicRender) TextureMapNormal(modelMaterials *rl.Material, texture rl.Texture2D) {
|
||||
rl.SetMaterialTexture(modelMaterials, rl.MapNormal, texture)
|
||||
}
|
||||
|
||||
func (ph *PhysicRender) TextureMapOcclusion(modelMaterials *rl.Material, texture rl.Texture2D) {
|
||||
rl.SetMaterialTexture(modelMaterials, rl.MapOcclusion, texture)
|
||||
}
|
||||
|
||||
func (ph *PhysicRender) DrawSphereLoctionLight(li light, color rl.Color) {
|
||||
rl.DrawSphereEx(li.Position, 0.2, 8, 8, color)
|
||||
}
|
||||
|
||||
func (ph *PhysicRender) AlbedoColorModel(model *rl.Model, color rl.Color) {
|
||||
model.GetMaterials()[0].GetMap(rl.MapAlbedo).Color = color
|
||||
}
|
||||
|
||||
func (ph *PhysicRender) EmissiveColor(color rl.Color) {
|
||||
rl.SetShaderValue(*ph.Shader, rl.GetShaderLocation(*ph.Shader, "emissiveColor"), []float32{float32(color.R), float32(color.G), float32(color.B), float32(color.A)}, rl.ShaderUniformVec4)
|
||||
}
|
||||
|
||||
func (ph *PhysicRender) NormalValue(value float32) {
|
||||
rl.SetShaderValue(*ph.Shader, rl.GetShaderLocation(*ph.Shader, "emissiveColor"), []float32{value}, rl.ShaderUniformFloat)
|
||||
}
|
||||
|
||||
func (ph *PhysicRender) MetallicValue(value float32) {
|
||||
rl.SetShaderValue(*ph.Shader, rl.GetShaderLocation(*ph.Shader, "metallicValue"), []float32{value}, rl.ShaderUniformFloat)
|
||||
}
|
||||
|
||||
func (ph *PhysicRender) RoughnessValue(value float32) {
|
||||
rl.SetShaderValue(*ph.Shader, rl.GetShaderLocation(*ph.Shader, "roughnessValue"), []float32{value}, rl.ShaderUniformFloat)
|
||||
}
|
||||
|
||||
func (ph *PhysicRender) AoValue(value float32) {
|
||||
rl.SetShaderValue(*ph.Shader, rl.GetShaderLocation(*ph.Shader, "aoValue"), []float32{value}, rl.ShaderUniformFloat)
|
||||
}
|
||||
|
||||
func (ph *PhysicRender) EmissivePower(value float32) {
|
||||
rl.SetShaderValue(*ph.Shader, rl.GetShaderLocation(*ph.Shader, "emissivePower"), []float32{value}, rl.ShaderUniformFloat)
|
||||
}
|
||||
|
||||
func (ph *PhysicRender) AmbientColor(colorAmbient rl.Vector3, ambientValue float32) {
|
||||
rl.SetShaderValue(*ph.Shader, rl.GetShaderLocation(*ph.Shader, "ambientColor"), []float32{colorAmbient.X, colorAmbient.Y, colorAmbient.Z}, rl.ShaderUniformVec3)
|
||||
rl.SetShaderValue(*ph.Shader, rl.GetShaderLocation(*ph.Shader, "ambient"), []float32{ambientValue}, rl.ShaderUniformFloat)
|
||||
}
|
||||
|
||||
func (ph *PhysicRender) SetTiling(value rl.Vector2) {
|
||||
rl.SetShaderValue(*ph.Shader, rl.GetShaderLocation(*ph.Shader, "tiling"), []float32{value.X, value.Y}, rl.ShaderUniformVec2)
|
||||
}
|
||||
|
||||
func (ph *PhysicRender) SetOffset(value rl.Vector2) {
|
||||
rl.SetShaderValue(*ph.Shader, rl.GetShaderLocation(*ph.Shader, "offset"), []float32{value.X, value.Y}, rl.ShaderUniformVec2)
|
||||
}
|
||||
|
||||
func (ph *PhysicRender) SetTilingFlashlight(value rl.Vector2) {
|
||||
rl.SetShaderValue(*ph.Shader, rl.GetShaderLocation(*ph.Shader, "tilingFlashlight"), []float32{value.X, value.Y}, rl.ShaderUniformVec2)
|
||||
}
|
||||
|
||||
func (ph *PhysicRender) SetOffsetFlashlight(value rl.Vector2) {
|
||||
rl.SetShaderValue(*ph.Shader, rl.GetShaderLocation(*ph.Shader, "offsetFlashlight"), []float32{value.X, value.Y}, rl.ShaderUniformVec2)
|
||||
}
|
||||
|
||||
func (ph *PhysicRender) UseTexAlbedo() {
|
||||
rl.SetShaderValue(*ph.Shader, rl.GetShaderLocation(*ph.Shader, "useTexAlbedo"), generiteIntForGlsl(1), rl.ShaderUniformInt)
|
||||
}
|
||||
|
||||
func (ph *PhysicRender) UseTexNormal() {
|
||||
rl.SetShaderValue(*ph.Shader, rl.GetShaderLocation(*ph.Shader, "useTexNormal"), generiteIntForGlsl(1), rl.ShaderUniformInt)
|
||||
}
|
||||
|
||||
func (ph *PhysicRender) UseTexMRA() {
|
||||
rl.SetShaderValue(*ph.Shader, rl.GetShaderLocation(*ph.Shader, "useTexMRA"), generiteIntForGlsl(1), rl.ShaderUniformInt)
|
||||
}
|
||||
|
||||
func (ph *PhysicRender) UseTexEmissive() {
|
||||
rl.SetShaderValue(*ph.Shader, rl.GetShaderLocation(*ph.Shader, "useTexEmissive"), generiteIntForGlsl(1), rl.ShaderUniformInt)
|
||||
}
|
||||
|
||||
func (ph *PhysicRender) configShader() {
|
||||
sh := rl.LoadShader("./pbr.vs", "./pbr.fs")
|
||||
ph.Shader = &sh
|
||||
}
|
||||
|
||||
// exce before init or set manually
|
||||
func (ph *PhysicRender) SetCombineShader(CombineShader *rl.Shader) {
|
||||
ph.combineStatus = true
|
||||
ph.Shader = CombineShader
|
||||
}
|
||||
|
||||
func (ph *PhysicRender) Unload() {
|
||||
rl.UnloadShader(*ph.Shader)
|
||||
}
|
||||
|
||||
func generiteIntForGlsl(value int32) []float32 {
|
||||
data := &reflect.SliceHeader{
|
||||
Data: uintptr(unsafe.Pointer(&value)),
|
||||
Len: 4,
|
||||
Cap: 4,
|
||||
}
|
||||
return *(*[]float32)(unsafe.Pointer(data))
|
||||
}
|