Merge pull request #486 from mohsengreen1388/pbr-example

example: I can add physic base render to example
This commit is contained in:
Milan Nikolic 2025-05-04 04:25:48 +02:00 committed by GitHub
commit 5ca0e770e3
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
14 changed files with 859 additions and 0 deletions

View 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;
}

View 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);
}

View 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(&lt.enabled)), 4), rl.ShaderUniformInt)
rl.SetShaderValue(lt.Shader, lt.typeLoc, unsafe.Slice((*float32)(unsafe.Pointer(&lt.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)
}

View 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()
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 MiB

Binary file not shown.

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 623 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 657 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 645 KiB

218
examples/shaders/pbr/pbr.go Normal file
View 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))
}