diff --git a/examples/shaders/pbr/glsl330/pbr.fs b/examples/shaders/pbr/glsl330/pbr.fs new file mode 100644 index 0000000..0448073 --- /dev/null +++ b/examples/shaders/pbr/glsl330/pbr.fs @@ -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; +} + diff --git a/examples/shaders/pbr/glsl330/pbr.vs b/examples/shaders/pbr/glsl330/pbr.vs new file mode 100644 index 0000000..53b0d0f --- /dev/null +++ b/examples/shaders/pbr/glsl330/pbr.vs @@ -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); +} + diff --git a/examples/shaders/pbr/light.go b/examples/shaders/pbr/light.go new file mode 100644 index 0000000..9a272e5 --- /dev/null +++ b/examples/shaders/pbr/light.go @@ -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) +} diff --git a/examples/shaders/pbr/main.go b/examples/shaders/pbr/main.go new file mode 100644 index 0000000..2085b12 --- /dev/null +++ b/examples/shaders/pbr/main.go @@ -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() +} diff --git a/examples/shaders/pbr/models/old_car_d.png b/examples/shaders/pbr/models/old_car_d.png new file mode 100644 index 0000000..d8b3c83 Binary files /dev/null and b/examples/shaders/pbr/models/old_car_d.png differ diff --git a/examples/shaders/pbr/models/old_car_e.png b/examples/shaders/pbr/models/old_car_e.png new file mode 100644 index 0000000..23f01c0 Binary files /dev/null and b/examples/shaders/pbr/models/old_car_e.png differ diff --git a/examples/shaders/pbr/models/old_car_mra.png b/examples/shaders/pbr/models/old_car_mra.png new file mode 100644 index 0000000..0fb46b3 Binary files /dev/null and b/examples/shaders/pbr/models/old_car_mra.png differ diff --git a/examples/shaders/pbr/models/old_car_n.png b/examples/shaders/pbr/models/old_car_n.png new file mode 100644 index 0000000..11f689f Binary files /dev/null and b/examples/shaders/pbr/models/old_car_n.png differ diff --git a/examples/shaders/pbr/models/old_car_new.glb b/examples/shaders/pbr/models/old_car_new.glb new file mode 100644 index 0000000..119995c Binary files /dev/null and b/examples/shaders/pbr/models/old_car_new.glb differ diff --git a/examples/shaders/pbr/models/plane.glb b/examples/shaders/pbr/models/plane.glb new file mode 100644 index 0000000..452e1c5 Binary files /dev/null and b/examples/shaders/pbr/models/plane.glb differ diff --git a/examples/shaders/pbr/models/road_a.png b/examples/shaders/pbr/models/road_a.png new file mode 100644 index 0000000..1037773 Binary files /dev/null and b/examples/shaders/pbr/models/road_a.png differ diff --git a/examples/shaders/pbr/models/road_mra.png b/examples/shaders/pbr/models/road_mra.png new file mode 100644 index 0000000..988c839 Binary files /dev/null and b/examples/shaders/pbr/models/road_mra.png differ diff --git a/examples/shaders/pbr/models/road_n.png b/examples/shaders/pbr/models/road_n.png new file mode 100644 index 0000000..a5f3548 Binary files /dev/null and b/examples/shaders/pbr/models/road_n.png differ diff --git a/examples/shaders/pbr/pbr.go b/examples/shaders/pbr/pbr.go new file mode 100644 index 0000000..cdc59c1 --- /dev/null +++ b/examples/shaders/pbr/pbr.go @@ -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)) +}