diff options
Diffstat (limited to 'examples')
17 files changed, 1307 insertions, 0 deletions
diff --git a/examples/shaders/resources/models/old_car_new.glb b/examples/shaders/resources/models/old_car_new.glb Binary files differnew file mode 100644 index 00000000..119995ca --- /dev/null +++ b/examples/shaders/resources/models/old_car_new.glb diff --git a/examples/shaders/resources/models/plane.glb b/examples/shaders/resources/models/plane.glb Binary files differnew file mode 100644 index 00000000..452e1c5b --- /dev/null +++ b/examples/shaders/resources/models/plane.glb diff --git a/examples/shaders/resources/old_car_d.png b/examples/shaders/resources/old_car_d.png Binary files differnew file mode 100644 index 00000000..d8b3c833 --- /dev/null +++ b/examples/shaders/resources/old_car_d.png diff --git a/examples/shaders/resources/old_car_e.png b/examples/shaders/resources/old_car_e.png Binary files differnew file mode 100644 index 00000000..23f01c0f --- /dev/null +++ b/examples/shaders/resources/old_car_e.png diff --git a/examples/shaders/resources/old_car_mra.png b/examples/shaders/resources/old_car_mra.png Binary files differnew file mode 100644 index 00000000..0fb46b33 --- /dev/null +++ b/examples/shaders/resources/old_car_mra.png diff --git a/examples/shaders/resources/old_car_n.png b/examples/shaders/resources/old_car_n.png Binary files differnew file mode 100644 index 00000000..11f689fe --- /dev/null +++ b/examples/shaders/resources/old_car_n.png diff --git a/examples/shaders/resources/road_a.png b/examples/shaders/resources/road_a.png Binary files differnew file mode 100644 index 00000000..10377739 --- /dev/null +++ b/examples/shaders/resources/road_a.png diff --git a/examples/shaders/resources/road_mra.png b/examples/shaders/resources/road_mra.png Binary files differnew file mode 100644 index 00000000..988c839c --- /dev/null +++ b/examples/shaders/resources/road_mra.png diff --git a/examples/shaders/resources/road_n.png b/examples/shaders/resources/road_n.png Binary files differnew file mode 100644 index 00000000..a5f3548c --- /dev/null +++ b/examples/shaders/resources/road_n.png diff --git a/examples/shaders/resources/shaders/glsl100/pbr.fs b/examples/shaders/resources/shaders/glsl100/pbr.fs new file mode 100644 index 00000000..1ada8331 --- /dev/null +++ b/examples/shaders/resources/shaders/glsl100/pbr.fs @@ -0,0 +1,156 @@ +#version 100 + +precision mediump float; + +#define MAX_LIGHTS 4 +#define LIGHT_DIRECTIONAL 0 +#define LIGHT_POINT 1 +#define PI 3.14159265358979323846 + +struct Light { + int enabled; + int type; + vec3 position; + vec3 target; + vec4 color; + float intensity; +}; + +// Input vertex attributes (from vertex shader) +varying in vec3 fragPosition; +varying in vec2 fragTexCoord; +varying in vec4 fragColor; +varying in vec3 fragNormal; +varying in vec4 shadowPos; +varying in mat3 TBN; + + +// Input uniform values +uniform int numOfLights; +uniform sampler2D albedoMap; +uniform sampler2D mraMap; +uniform sampler2D normalMap; +uniform sampler2D emissiveMap; // r: Hight g:emissive + +uniform vec2 tiling; +uniform vec2 offset; + +uniform int useTexAlbedo; +uniform int useTexNormal; +uniform int useTexMRA; +uniform int useTexEmissive; + +uniform vec4 albedoColor; +uniform vec4 emissiveColor; +uniform float normalValue; +uniform float metallicValue; +uniform float roughnessValue; +uniform float aoValue; +uniform float emissivePower; + +// Input lighting values +uniform Light lights[MAX_LIGHTS]; +uniform vec3 viewPos; + +uniform vec3 ambientColor; +uniform float ambient; + +// refl in range 0 to 1 +// returns base reflectivity to 1 +// incrase reflectivity 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 pbr(){ + vec3 albedo = texture2D(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 = texture2D(mraMap, vec2(fragTexCoord.x * tiling.x + offset.x, fragTexCoord.y * tiling.y + offset.y)); + 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 = texture2D(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 e = vec3(0); + e = (texture2D(emissiveMap, vec2(fragTexCoord.x*tiling.x+offset.x, fragTexCoord.y*tiling.y+offset.y)).rgb).g * emissiveColor.rgb*emissivePower * float(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 Lo = vec3(0.0); // acumulate lighting lum + + for(int i=0;i<numOfLights;++i){ + + vec3 L = normalize(lights[i].position - fragPosition); // calc light vector + vec3 H = normalize(V + L); // calc halfway bisecting vector + float dist = length(lights[i].position - fragPosition); // calc distance to light + float attenuation = 1.0 / (dist * dist * 0.23); // calc attenuation + vec3 radiance = lights[i].color.rgb * lights[i].intensity * attenuation; // calc input radiance,light energy comming in + + //Cook-Torrance BRDF distribution function + float nDotV = max(dot(N,V),0.0000001); + float nDotL = max(dot(N,L),0.0000001); + float hDotV = max(dot(H,V),0.0); + float nDotH = max(dot(N,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; + Lo += ((kD * albedo.rgb / PI + spec) * radiance * nDotL)*float(lights[i].enabled); // angle of light has impact on result + } + vec3 ambient_final = (ambientColor + albedo)* ambient * 0.5; + return ambient_final+Lo*ao+e; +} + +void main() +{ + vec3 color = pbr(); + + //HDR tonemapping + color = pow(color,color + vec3(1.0)); + //gamma correction + color = pow(color,vec3(1.0/2.2)); + + gl_FragColor = vec4(color,1.0); + +}
\ No newline at end of file diff --git a/examples/shaders/resources/shaders/glsl100/pbr.vs b/examples/shaders/resources/shaders/glsl100/pbr.vs new file mode 100644 index 00000000..3fa651f7 --- /dev/null +++ b/examples/shaders/resources/shaders/glsl100/pbr.vs @@ -0,0 +1,75 @@ +#version 100 + +// Input vertex attributes +attribute vec3 vertexPosition; +attribute vec2 vertexTexCoord; +attribute vec3 vertexNormal; +attribute vec3 vertexTangent; +attribute 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) +varying vec3 fragPosition; +varying vec2 fragTexCoord; +varying vec4 fragColor; +varying vec3 fragNormal; +varying mat3 TBN; + +const float normalOffset = 0.1; + +// https://github.com/glslify/glsl-inverse +mat3 inverse(mat3 m) +{ + float a00 = m[0][0], a01 = m[0][1], a02 = m[0][2]; + float a10 = m[1][0], a11 = m[1][1], a12 = m[1][2]; + float a20 = m[2][0], a21 = m[2][1], a22 = m[2][2]; + + float b01 = a22*a11 - a12*a21; + float b11 = -a22*a10 + a12*a20; + float b21 = a21*a10 - a11*a20; + + float det = a00*b01 + a01*b11 + a02*b21; + + return mat3(b01, (-a22*a01 + a02*a21), (a12*a01 - a02*a11), + b11, (a22*a00 - a02*a20), (-a12*a00 + a02*a10), + b21, (-a21*a00 + a01*a20), (a11*a00 - a01*a10))/det; +} + +// https://github.com/glslify/glsl-transpose +mat3 transpose(mat3 m) +{ + return mat3(m[0][0], m[1][0], m[2][0], + m[0][1], m[1][1], m[2][1], + m[0][2], m[1][2], m[2][2]); +} + +void main() +{ + + // calc binormal from vertex normal and tangent + vec3 vertexBinormal = cross(vertexNormal, vertexTangent); + // calc fragment normal based on normal transformations + mat3 normalMatrix = transpose(inverse(mat3(matModel))); + // calc fragment position based on model transformations + + fragPosition = vec3(matModel*vec4(vertexPosition, 1.0)); + + fragTexCoord = vertexTexCoord*2.0; + + 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); +}
\ No newline at end of file diff --git a/examples/shaders/resources/shaders/glsl120/pbr.fs b/examples/shaders/resources/shaders/glsl120/pbr.fs new file mode 100644 index 00000000..935bced3 --- /dev/null +++ b/examples/shaders/resources/shaders/glsl120/pbr.fs @@ -0,0 +1,156 @@ +#version 120 + +precision mediump float; + +#define MAX_LIGHTS 4 +#define LIGHT_DIRECTIONAL 0 +#define LIGHT_POINT 1 +#define PI 3.14159265358979323846 + +struct Light { + int enabled; + int type; + vec3 position; + vec3 target; + vec4 color; + float intensity; +}; + +// Input vertex attributes (from vertex shader) +varying in vec3 fragPosition; +varying in vec2 fragTexCoord; +varying in vec4 fragColor; +varying in vec3 fragNormal; +varying in vec4 shadowPos; +varying in mat3 TBN; + + +// Input uniform values +uniform int numOfLights; +uniform sampler2D albedoMap; +uniform sampler2D mraMap; +uniform sampler2D normalMap; +uniform sampler2D emissiveMap; // r: Hight g:emissive + +uniform vec2 tiling; +uniform vec2 offset; + +uniform int useTexAlbedo; +uniform int useTexNormal; +uniform int useTexMRA; +uniform int useTexEmissive; + +uniform vec4 albedoColor; +uniform vec4 emissiveColor; +uniform float normalValue; +uniform float metallicValue; +uniform float roughnessValue; +uniform float aoValue; +uniform float emissivePower; + +// Input lighting values +uniform Light lights[MAX_LIGHTS]; +uniform vec3 viewPos; + +uniform vec3 ambientColor; +uniform float ambient; + +// refl in range 0 to 1 +// returns base reflectivity to 1 +// incrase reflectivity 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 pbr(){ + vec3 albedo = texture2D(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 = texture2D(mraMap, vec2(fragTexCoord.x * tiling.x + offset.x, fragTexCoord.y * tiling.y + offset.y)); + 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 = texture2D(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 e = vec3(0); + e = (texture2D(emissiveMap, vec2(fragTexCoord.x*tiling.x+offset.x, fragTexCoord.y*tiling.y+offset.y)).rgb).g * emissiveColor.rgb*emissivePower * float(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 Lo = vec3(0.0); // acumulate lighting lum + + for(int i=0;i<numOfLights;++i){ + + vec3 L = normalize(lights[i].position - fragPosition); // calc light vector + vec3 H = normalize(V + L); // calc halfway bisecting vector + float dist = length(lights[i].position - fragPosition); // calc distance to light + float attenuation = 1.0 / (dist * dist * 0.23); // calc attenuation + vec3 radiance = lights[i].color.rgb * lights[i].intensity * attenuation; // calc input radiance,light energy comming in + + //Cook-Torrance BRDF distribution function + float nDotV = max(dot(N,V),0.0000001); + float nDotL = max(dot(N,L),0.0000001); + float hDotV = max(dot(H,V),0.0); + float nDotH = max(dot(N,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; + Lo += ((kD * albedo.rgb / PI + spec) * radiance * nDotL)*float(lights[i].enabled); // angle of light has impact on result + } + vec3 ambient_final = (ambientColor + albedo)* ambient * 0.5; + return ambient_final+Lo*ao+e; +} + +void main() +{ + vec3 color = pbr(); + + //HDR tonemapping + color = pow(color,color + vec3(1.0)); + //gamma correction + color = pow(color,vec3(1.0/2.2)); + + gl_FragColor = vec4(color,1.0); + +}
\ No newline at end of file diff --git a/examples/shaders/resources/shaders/glsl120/pbr.vs b/examples/shaders/resources/shaders/glsl120/pbr.vs new file mode 100644 index 00000000..4c00261f --- /dev/null +++ b/examples/shaders/resources/shaders/glsl120/pbr.vs @@ -0,0 +1,75 @@ +#version 120 + +// Input vertex attributes +attribute vec3 vertexPosition; +attribute vec2 vertexTexCoord; +attribute vec3 vertexNormal; +attribute vec3 vertexTangent; +attribute 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) +varying vec3 fragPosition; +varying vec2 fragTexCoord; +varying vec4 fragColor; +varying vec3 fragNormal; +varying mat3 TBN; + +const float normalOffset = 0.1; + +// https://github.com/glslify/glsl-inverse +mat3 inverse(mat3 m) +{ + float a00 = m[0][0], a01 = m[0][1], a02 = m[0][2]; + float a10 = m[1][0], a11 = m[1][1], a12 = m[1][2]; + float a20 = m[2][0], a21 = m[2][1], a22 = m[2][2]; + + float b01 = a22*a11 - a12*a21; + float b11 = -a22*a10 + a12*a20; + float b21 = a21*a10 - a11*a20; + + float det = a00*b01 + a01*b11 + a02*b21; + + return mat3(b01, (-a22*a01 + a02*a21), (a12*a01 - a02*a11), + b11, (a22*a00 - a02*a20), (-a12*a00 + a02*a10), + b21, (-a21*a00 + a01*a20), (a11*a00 - a01*a10))/det; +} + +// https://github.com/glslify/glsl-transpose +mat3 transpose(mat3 m) +{ + return mat3(m[0][0], m[1][0], m[2][0], + m[0][1], m[1][1], m[2][1], + m[0][2], m[1][2], m[2][2]); +} + +void main() +{ + + // calc binormal from vertex normal and tangent + vec3 vertexBinormal = cross(vertexNormal, vertexTangent); + // calc fragment normal based on normal transformations + mat3 normalMatrix = transpose(inverse(mat3(matModel))); + // calc fragment position based on model transformations + + fragPosition = vec3(matModel*vec4(vertexPosition, 1.0)); + + fragTexCoord = vertexTexCoord*2.0; + + 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); +}
\ No newline at end of file diff --git a/examples/shaders/resources/shaders/glsl330/pbr.fs b/examples/shaders/resources/shaders/glsl330/pbr.fs new file mode 100644 index 00000000..5375d449 --- /dev/null +++ b/examples/shaders/resources/shaders/glsl330/pbr.fs @@ -0,0 +1,159 @@ +#version 330 + +#define MAX_LIGHTS 4 +#define LIGHT_DIRECTIONAL 0 +#define LIGHT_POINT 1 +#define PI 3.14159265358979323846 + +struct Light { + int enabled; + int type; + vec3 position; + vec3 target; + vec4 color; + float intensity; +}; + +// 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; +// Input uniform values + +uniform int numOfLights; +uniform sampler2D albedoMap; +uniform sampler2D mraMap; +uniform sampler2D normalMap; +uniform sampler2D emissiveMap; // r: Hight g:emissive + +uniform vec2 tiling; +uniform vec2 offset; + +uniform int useTexAlbedo; +uniform int useTexNormal; +uniform int useTexMRA; +uniform int useTexEmissive; + +uniform vec4 albedoColor; +uniform vec4 emissiveColor; +uniform float normalValue; +uniform float metallicValue; +uniform float roughnessValue; +uniform float aoValue; +uniform float emissivePower; + +// Input lighting values +uniform Light lights[MAX_LIGHTS]; +uniform vec3 viewPos; + +uniform vec3 ambientColor; +uniform float ambient; + +// refl in range 0 to 1 +// returns base reflectivity to 1 +// incrase reflectivity 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 pbr(){ + 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 e = vec3(0); + e = (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 Lo = vec3(0.0); // acumulate lighting lum + + for(int i=0;i<numOfLights;++i){ + + vec3 L = normalize(lights[i].position - fragPosition); // calc light vector + vec3 H = normalize(V + L); // calc halfway bisecting vector + float dist = length(lights[i].position - fragPosition); // calc distance to light + float attenuation = 1.0 / (dist * dist * 0.23); // calc attenuation + vec3 radiance = lights[i].color.rgb * lights[i].intensity * attenuation; // calc input radiance,light energy comming in + + //Cook-Torrance BRDF distribution function + float nDotV = max(dot(N,V),0.0000001); + float nDotL = max(dot(N,L),0.0000001); + float hDotV = max(dot(H,V),0.0); + float nDotH = max(dot(N,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; + Lo += ((kD * albedo.rgb / PI + spec) * radiance * nDotL)*lights[i].enabled; // angle of light has impact on result + } + vec3 ambient_final = (ambientColor + albedo)* ambient * 0.5; + return ambient_final+Lo*ao+e; +} + +void main() +{ + vec3 color = pbr(); + + //HDR tonemapping + color = pow(color,color + vec3(1.0)); + //gamma correction + color = pow(color,vec3(1.0/2.2)); + + finalColor = vec4(color,1.0); +}
\ No newline at end of file diff --git a/examples/shaders/resources/shaders/glsl330/pbr.vs b/examples/shaders/resources/shaders/glsl330/pbr.vs new file mode 100644 index 00000000..a03898cb --- /dev/null +++ b/examples/shaders/resources/shaders/glsl330/pbr.vs @@ -0,0 +1,49 @@ +#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 vec4 fragColor; +out vec3 fragNormal; +out mat3 TBN; + +const float normalOffset = 0.1; + +void main() +{ + + // calc binormal from vertex normal and tangent + vec3 vertexBinormal = cross(vertexNormal, vertexTangent); + // calc fragment normal based on normal transformations + mat3 normalMatrix = transpose(inverse(mat3(matModel))); + // calc fragment position based on model transformations + + fragPosition = vec3(matModel*vec4(vertexPosition, 1.0f)); + + fragTexCoord = vertexTexCoord*2.0; + + 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); +}
\ No newline at end of file diff --git a/examples/shaders/rpbr.h b/examples/shaders/rpbr.h new file mode 100644 index 00000000..a8b7e939 --- /dev/null +++ b/examples/shaders/rpbr.h @@ -0,0 +1,466 @@ +/********************************************************************************************** +* +* raylib.pbr - Some useful functions to deal with pbr materials and lights +* +* CONFIGURATION: +* +* #define RPBR_IMPLEMENTATION +* Generates the implementation of the library into the included file. +* If not defined, the library is in header only mode and can be included in other headers +* or source files without problems. But only ONE file should hold the implementation. +* +* LICENSE: zlib/libpng +* +* Copyright (c) 2023-2024 Afan OLOVCIC (@_DevDad) 2017-2020 Victor Fisac(@victorfisac),Ramon Santamaria (@raysan5) +* +* This software is provided "as-is", without any express or implied warranty. In no event +* will the authors be held liable for any damages arising from the use of this software. +* +* Permission is granted to anyone to use this software for any purpose, including commercial +* applications, and to alter it and redistribute it freely, subject to the following restrictions: +* +* 1. The origin of this software must not be misrepresented; you must not claim that you +* wrote the original software. If you use this software in a product, an acknowledgment +* in the product documentation would be appreciated but is not required. +* +* 2. Altered source versions must be plainly marked as such, and must not be misrepresented +* as being the original software. +* +* 3. This notice may not be removed or altered from any source distribution. +* +**********************************************************************************************/ + +#ifndef RPBR_H +#define RPBR_H +#include "raylib.h" + + +//---------------------------------------------------------------------------------- +// Defines and Macros +//---------------------------------------------------------------------------------- +#define MAX_LIGHTS 4 // Max dynamic lights supported by shader +#define SHADER_LOC_MAP_MRA SHADER_LOC_MAP_METALNESS //METALLIC, ROUGHNESS and AO +#define SHADER_LOC_MAP_EMISSIVE SHADER_LOC_MAP_HEIGHT //EMISSIVE +#define MATERIAL_MAP_MRA MATERIAL_MAP_METALNESS +#define MATERIAL_MAP_EMISSIVE MATERIAL_MAP_HEIGHT +#define NULL 0 +#define COLOR_TO_ARRAY(c) + +typedef struct { + int enabled; + int type; + Vector3 position; + Vector3 target; + float color[4]; + float intensity; + + int enabledLoc; + int typeLoc; + int positionLoc; + int targetLoc; + int colorLoc; + int intensityLoc; +} PBRLight; + +typedef enum { + LIGHT_DIRECTIONAL = 0, + LIGHT_POINT, + LIGHT_SPOT +} PBRLightType; + +typedef struct{ + Shader pbrShader; + Shader skyShader; + unsigned int cubemap; + unsigned int irradiance; + unsigned int prefilter; + unsigned int brdf; + int modelMatrixLoc; + int pbrViewLoc; + int skyViewLoc; + int skyResolutionLoc; +} PBREnvironment; + +typedef enum{ + PBR_COLOR_ALBEDO = 0, + PBR_COLOR_EMISSIVE +}PBRColorType; + +typedef enum{ + PBR_VEC2_TILING = 0, + PBR_VEC2_OFFSET +}PBRVec2Type; + +typedef enum{ + PBR_PARAM_NORMAL =0, + PBR_PARAM_METALLIC, + PBR_PARAM_ROUGHNESS, + PBR_PARAM_EMISSIVE, + PBR_PARAM_AO +}PBRFloatType; + +typedef enum{ + PBR_TEXTURE_ALBEDO = 0, + PBR_TEXTURE_NORMAL, + PBR_TEXTURE_MRA, + PBR_TEXTURE_EMISSIVE +}PBRTexType; + +// Textures are moved to material from params to pack better and use less textures on the end +// texture MRAE 4Channel R: Metallic G: Roughness B: A: Ambient Occlusion +// texEmissive use just one channel, so we have 3 channels still to use if we need +typedef struct { + Shader pbrShader; + float albedo[4]; + float normal; + float metallic; + float roughness; + float ao; + float emissive[4]; + float ambient[3]; + float emissivePower; + + Texture2D texAlbedo; + Texture2D texNormal; + Texture2D texMRA;//r: Metallic g: Roughness b: AO a:Empty + Texture2D texEmissive; //Emissive Texture + // Using float4 to store tilling at 1st and 2nd position and offset at 3rd and 4th + float texTiling[2]; + float texOffset[2]; + + int useTexAlbedo; + int useTexNormal; + int useTexMRA; + int useTexEmissive; + + int albedoLoc; + int normalLoc; + int metallicLoc; + int roughnessLoc; + int aoLoc; + int emissiveColorLoc; + int emissivePowerLoc; + + int texTilingLoc; + int texOffsetLoc; + + int useTexAlbedoLoc; + int useTexNormalLoc; + int useTexMRAELoc; + int useTexEmissiveLoc; +} PBRMaterial; + +typedef struct{ + Model model; + PBRMaterial pbrMat; +}PBRModel; + +#ifdef __cplusplus +extern "C" { +#endif + + +//---------------------------------------------------------------------------------- +// Module Functions Declaration +//---------------------------------------------------------------------------------- + +// Create a light and get shader locations +PBRLight PBRLightCreate(int type, Vector3 position, Vector3 target, Color color,float intensity, Shader shader); +// Send light properties to shader +void PBRLightUpdate(Shader shader, PBRLight light); + +//For now until we do real skylight +void PBRSetAmbient(Shader shader, Color color, float intensity); + +PBRModel PBRModelLoad(const char *fileName); +PBRModel PBRModelLoadFromMesh(Mesh mesh); + +void PBRLoadTextures(PBRMaterial *pbrMat,PBRTexType pbrTexType,const char *fileName); +void UnloadPBRMaterial(PBRMaterial pbrMat); +void PBRSetColor(PBRMaterial *pbrMat,PBRColorType pbrColorType,Color color); +void PBRSetVec2(PBRMaterial *pbrMat,PBRVec2Type type,Vector2 value); +void PBRSetFloat(PBRMaterial *pbrMat, PBRFloatType pbrParamType, float value); + +void PBRMaterialSetup( PBRMaterial *pbrMat,Shader pbrShader, PBREnvironment* environment); +void PBRSetMaterial(PBRModel* model,PBRMaterial* pbrMat,int matIndex); +void PBRDrawModel(PBRModel pbrModel, Vector3 position, float scale); + +#ifdef __cplusplus +} +#endif + +#endif //RPBR_H + +/*********************************************************************************** +* +* RPBR IMPLEMENTATION +* +************************************************************************************/ + +#if defined(RPBR_IMPLEMENTATION) + +//---------------------------------------------------------------------------------- +// Global Variables Definition +//---------------------------------------------------------------------------------- +static int lightsCount = 0; // Current amount of created lights + +// Create a light and get shader locations +PBRLight PBRLightCreate(int type, Vector3 position, Vector3 target, Color color,float intensity, Shader shader) +{ + PBRLight light = { 0 }; + + if (lightsCount < MAX_LIGHTS) + { + light.enabled = 1; + light.type = type; + light.position = position; + light.target = target; + light.color[0] = (float)color.r/(float)255; + light.color[1] = (float)color.g/(float)255; + light.color[2] = (float)color.b/(float)255; + light.color[3] = (float)color.a/(float)255; + light.intensity = intensity; + // NOTE: Lighting shader naming must be the provided ones + light.enabledLoc = GetShaderLocation(shader, TextFormat("lights[%i].enabled", lightsCount)); + light.typeLoc = GetShaderLocation(shader, TextFormat("lights[%i].type", lightsCount)); + light.positionLoc = GetShaderLocation(shader, TextFormat("lights[%i].position", lightsCount)); + light.targetLoc = GetShaderLocation(shader, TextFormat("lights[%i].target", lightsCount)); + light.colorLoc = GetShaderLocation(shader, TextFormat("lights[%i].color", lightsCount)); + light.intensityLoc = GetShaderLocation(shader, TextFormat("lights[%i].intensity", lightsCount)); + PBRLightUpdate(shader, light); + + lightsCount++; + } + + return light; +} + +// Send light properties to shader +// NOTE: Light shader locations should be available +void PBRLightUpdate(Shader shader, PBRLight light) +{ + SetShaderValue(shader, light.enabledLoc, &light.enabled, SHADER_UNIFORM_INT); + SetShaderValue(shader, light.typeLoc, &light.type, SHADER_UNIFORM_INT); + // Send to shader light position values + float position[3] = { light.position.x, light.position.y, light.position.z }; + SetShaderValue(shader, light.positionLoc, position, SHADER_UNIFORM_VEC3); + + // Send to shader light target position values + float target[3] = { light.target.x, light.target.y, light.target.z }; + SetShaderValue(shader, light.targetLoc, target, SHADER_UNIFORM_VEC3); + SetShaderValue(shader, light.colorLoc, light.color, SHADER_UNIFORM_VEC4); + SetShaderValue(shader, light.intensityLoc, &light.intensity, SHADER_UNIFORM_FLOAT); +} + +void PBRSetAmbient(Shader shader, Color color, float intensity){ + float col[3] = {color.r/255,color.g/255,color.b/255}; + SetShaderValue(shader, GetShaderLocation(shader, "ambientColor"), col, SHADER_UNIFORM_VEC3); + SetShaderValue(shader, GetShaderLocation(shader, "ambient"), &intensity, SHADER_UNIFORM_FLOAT); +} + +void PBRMaterialSetup(PBRMaterial *pbrMat, Shader pbrShader, PBREnvironment* environment){ + pbrMat->pbrShader = pbrShader; + + pbrMat->texAlbedo = (Texture2D){0}; + pbrMat->texNormal = (Texture2D){0}; + pbrMat->texMRA = (Texture2D){0}; + pbrMat->texEmissive = (Texture2D){0}; + + //PBRParam + pbrMat->albedo[0] = 1.0; + pbrMat->albedo[1] = 1.0; + pbrMat->albedo[2] = 1.0; + pbrMat->albedo[3] = 1.0; + pbrMat->metallic = 0; + pbrMat->roughness = 0; + pbrMat->ao = 1.0; + pbrMat->normal = 1; + pbrMat->emissive[0] = 0; + pbrMat->emissive[1] = 0; + pbrMat->emissive[2] = 0; + pbrMat->emissive[3] = 0; + + pbrMat->texTiling[0] = 1.0; + pbrMat->texTiling[1] = 1.0; + pbrMat->texOffset[0] = 0.0; + pbrMat->texOffset[1] = 0.0; + pbrMat->emissivePower = 1.0; + // Set up PBR shader material locations + + pbrMat->albedoLoc = GetShaderLocation(pbrMat->pbrShader, "albedoColor"); + pbrMat->normalLoc = GetShaderLocation(pbrMat->pbrShader, "normalValue"); + pbrMat->metallicLoc = GetShaderLocation(pbrMat->pbrShader, "metallicValue"); + pbrMat->roughnessLoc = GetShaderLocation(pbrMat->pbrShader, "roughnessValue"); + pbrMat->aoLoc = GetShaderLocation(pbrMat->pbrShader, "aoValue"); + pbrMat->emissiveColorLoc = GetShaderLocation(pbrMat->pbrShader, "emissiveColor"); + pbrMat->emissivePowerLoc = GetShaderLocation(pbrMat->pbrShader, "emissivePower"); + + pbrMat->texTilingLoc = GetShaderLocation(pbrMat->pbrShader, "tiling"); + pbrMat->texOffsetLoc = GetShaderLocation(pbrMat->pbrShader, "offset"); + + pbrMat->useTexAlbedoLoc = GetShaderLocation(pbrMat->pbrShader, "useTexAlbedo"); + pbrMat->useTexNormalLoc = GetShaderLocation(pbrMat->pbrShader, "useTexNormal"); + pbrMat->useTexMRAELoc = GetShaderLocation(pbrMat->pbrShader, "useTexMRA"); + pbrMat->useTexEmissiveLoc = GetShaderLocation(pbrMat->pbrShader, "useTexEmissive"); + + SetShaderValue(pbrMat->pbrShader,pbrMat->albedoLoc,pbrMat->albedo,SHADER_UNIFORM_VEC4); + SetShaderValue(pbrMat->pbrShader, pbrMat->emissiveColorLoc, pbrMat->emissive, SHADER_UNIFORM_VEC4); + SetShaderValue(pbrMat->pbrShader, pbrMat->emissivePowerLoc, &pbrMat->emissivePower, SHADER_UNIFORM_FLOAT); + SetShaderValue(pbrMat->pbrShader,pbrMat->metallicLoc,&pbrMat->metallic,SHADER_UNIFORM_FLOAT); + SetShaderValue(pbrMat->pbrShader,pbrMat->roughnessLoc,&pbrMat->roughness,SHADER_UNIFORM_FLOAT); + SetShaderValue(pbrMat->pbrShader,pbrMat->aoLoc,&pbrMat->ao,SHADER_UNIFORM_FLOAT); + SetShaderValue(pbrMat->pbrShader,pbrMat->normalLoc,&pbrMat->normal,SHADER_UNIFORM_FLOAT); + SetShaderValue(pbrMat->pbrShader,pbrMat->texTilingLoc,pbrMat->texTiling,SHADER_UNIFORM_VEC2); + SetShaderValue(pbrMat->pbrShader,pbrMat->texOffsetLoc,pbrMat->texOffset,SHADER_UNIFORM_VEC2); +} + +void PBRLoadTextures(PBRMaterial *pbrMat,PBRTexType pbrTexType,const char *fileName){ + if(pbrMat == NULL) return; + switch(pbrTexType){ + case PBR_TEXTURE_ALBEDO: + pbrMat->texAlbedo = LoadTexture(fileName); + pbrMat->useTexAlbedo = 1; + break; + case PBR_TEXTURE_MRA: + pbrMat->texMRA = LoadTexture(fileName); + pbrMat->useTexMRA = 1; + break; + case PBR_TEXTURE_NORMAL: + pbrMat->texNormal = LoadTexture(fileName); + pbrMat->useTexNormal = 1; + break; + case PBR_TEXTURE_EMISSIVE: + pbrMat->texEmissive = LoadTexture(fileName); + pbrMat->useTexEmissive = 1; + break; + } +} + +void UnloadPBRMaterial(PBRMaterial pbrMat){ + if(pbrMat.useTexAlbedo == 1) UnloadTexture(pbrMat.texAlbedo); + if(pbrMat.useTexNormal == 1) UnloadTexture(pbrMat.texNormal); + if(pbrMat.useTexMRA == 1) UnloadTexture(pbrMat.texMRA); + if(pbrMat.useTexEmissive == 1) UnloadTexture(pbrMat.texEmissive); +} + +void PBRSetColor(PBRMaterial *pbrMat,PBRColorType pbrColorType,Color color){ + if(pbrMat == NULL) return; + switch(pbrColorType){ + case PBR_COLOR_ALBEDO: + pbrMat->albedo[0] = (float) color.r / 255; + pbrMat->albedo[1] = (float) color.g / 255; + pbrMat->albedo[2] = (float) color.b / 255; + pbrMat->albedo[3] = (float) color.a / 255; + SetShaderValue(pbrMat->pbrShader,pbrMat->albedoLoc,pbrMat->albedo,SHADER_UNIFORM_VEC4); + break; + case PBR_COLOR_EMISSIVE: + pbrMat->emissive[0] = (float) color.r / 255; + pbrMat->emissive[1] = (float) color.g / 255; + pbrMat->emissive[2] = (float) color.b / 255; + pbrMat->emissive[3] = (float) color.a / 255; + SetShaderValue(pbrMat->pbrShader, pbrMat->emissiveColorLoc, pbrMat->emissive, SHADER_UNIFORM_VEC4); + break; + } +} + +void PBRSetFloat(PBRMaterial *pbrMat, PBRFloatType pbrParamType, float value){ + if(pbrMat == NULL) return; + switch(pbrParamType){ + case PBR_PARAM_METALLIC: + pbrMat->metallic = value; + SetShaderValue(pbrMat->pbrShader,pbrMat->metallicLoc,&pbrMat->metallic,SHADER_UNIFORM_FLOAT); + break; + case PBR_PARAM_ROUGHNESS: + pbrMat->roughness = value; + SetShaderValue(pbrMat->pbrShader,pbrMat->roughnessLoc,&pbrMat->roughness,SHADER_UNIFORM_FLOAT); + break; + case PBR_PARAM_NORMAL: + pbrMat->normal = value; + SetShaderValue(pbrMat->pbrShader,pbrMat->normalLoc,&pbrMat->normal,SHADER_UNIFORM_FLOAT); + break; + case PBR_PARAM_AO: + pbrMat->ao = value; + SetShaderValue(pbrMat->pbrShader,pbrMat->aoLoc,&pbrMat->ao,SHADER_UNIFORM_FLOAT); + break; + case PBR_PARAM_EMISSIVE: + pbrMat->emissivePower = value; + SetShaderValue(pbrMat->pbrShader,pbrMat->emissivePowerLoc,&pbrMat->emissivePower,SHADER_UNIFORM_FLOAT); + break; + } +} + + +void PBRSetVec2(PBRMaterial *pbrMat,PBRVec2Type type,Vector2 value){ + switch(type){ + case PBR_VEC2_TILING: + pbrMat->texTiling[0] = value.x; + pbrMat->texTiling[1] = value.y; + SetShaderValue(pbrMat->pbrShader,pbrMat->texTilingLoc,&pbrMat->texTiling,SHADER_UNIFORM_VEC2); + break; + case PBR_VEC2_OFFSET: + pbrMat->texOffset[0] = value.x; + pbrMat->texOffset[1] = value.y; + SetShaderValue(pbrMat->pbrShader,pbrMat->texOffsetLoc,&pbrMat->texOffset,SHADER_UNIFORM_VEC2); + break; + } +} + +void PBRSetMaterial(PBRModel* model,PBRMaterial* pbrMat,int matIndex){ + + + model->pbrMat = *pbrMat; + model->model.materials[matIndex].shader = model->pbrMat.pbrShader; + pbrMat->pbrShader.locs[SHADER_LOC_MAP_MRA] = GetShaderLocation(pbrMat->pbrShader, "mraMap"); + pbrMat->pbrShader.locs[SHADER_LOC_MAP_EMISSIVE] = GetShaderLocation(pbrMat->pbrShader, "emissiveMap"); + pbrMat->pbrShader.locs[SHADER_LOC_MAP_NORMAL] = GetShaderLocation(pbrMat->pbrShader, "normalMap"); + + if(pbrMat->useTexAlbedo) { + model->model.materials[matIndex].maps[MATERIAL_MAP_ALBEDO].texture = pbrMat->texAlbedo; + } + if(pbrMat->useTexMRA) { + model->model.materials[matIndex].maps[MATERIAL_MAP_MRA].texture = pbrMat->texMRA; + } + if(pbrMat->useTexNormal) { + model->model.materials[matIndex].maps[MATERIAL_MAP_NORMAL].texture = pbrMat->texNormal; + } + if(pbrMat->useTexEmissive) { + model->model.materials[matIndex].maps[MATERIAL_MAP_EMISSIVE].texture = pbrMat->texEmissive; + } + + SetShaderValue(pbrMat->pbrShader,pbrMat->useTexAlbedoLoc,&pbrMat->useTexAlbedo,SHADER_UNIFORM_INT); + SetShaderValue(pbrMat->pbrShader,pbrMat->useTexNormalLoc,&pbrMat->useTexNormal,SHADER_UNIFORM_INT); + SetShaderValue(pbrMat->pbrShader, pbrMat->useTexMRAELoc, &pbrMat->useTexMRA, SHADER_UNIFORM_INT); + SetShaderValue(pbrMat->pbrShader, pbrMat->useTexEmissiveLoc, &pbrMat->useTexEmissive, SHADER_UNIFORM_INT); +} + +void PBRDrawModel(PBRModel pbrModel, Vector3 position, float scale){ + PBRMaterial *pbrMat = &pbrModel.pbrMat; + SetShaderValue(pbrMat->pbrShader,pbrMat->albedoLoc,pbrMat->albedo,SHADER_UNIFORM_VEC4); + SetShaderValue(pbrMat->pbrShader, pbrMat->emissiveColorLoc, pbrMat->emissive, SHADER_UNIFORM_VEC4); + SetShaderValue(pbrMat->pbrShader,pbrMat->metallicLoc,&pbrMat->metallic,SHADER_UNIFORM_FLOAT); + SetShaderValue(pbrMat->pbrShader,pbrMat->roughnessLoc,&pbrMat->roughness,SHADER_UNIFORM_FLOAT); + SetShaderValue(pbrMat->pbrShader,pbrMat->aoLoc,&pbrMat->ao,SHADER_UNIFORM_FLOAT); + SetShaderValue(pbrMat->pbrShader,pbrMat->normalLoc,&pbrMat->normal,SHADER_UNIFORM_FLOAT); + SetShaderValue(pbrMat->pbrShader,pbrMat->texTilingLoc,pbrMat->texTiling,SHADER_UNIFORM_VEC2); + SetShaderValue(pbrMat->pbrShader,pbrMat->texOffsetLoc,pbrMat->texOffset,SHADER_UNIFORM_VEC2); + + SetShaderValue(pbrMat->pbrShader,pbrMat->useTexAlbedoLoc,&pbrMat->useTexAlbedo,SHADER_UNIFORM_INT); + SetShaderValue(pbrMat->pbrShader,pbrMat->useTexNormalLoc,&pbrMat->useTexNormal,SHADER_UNIFORM_INT); + SetShaderValue(pbrMat->pbrShader, pbrMat->useTexMRAELoc, &pbrMat->useTexMRA, SHADER_UNIFORM_INT); + SetShaderValue(pbrMat->pbrShader, pbrMat->useTexEmissiveLoc, &pbrMat->useTexEmissive, SHADER_UNIFORM_INT); + + DrawModel(pbrModel.model,position,scale,WHITE); +} + +PBRModel PBRModelLoad(const char *fileName){ + PBRModel pbrModel = (PBRModel){0}; + pbrModel.model = LoadModel(fileName); + return pbrModel; +} + +PBRModel PBRModelLoadFromMesh(Mesh mesh){ + PBRModel pbrModel = (PBRModel){0}; + pbrModel.model = LoadModelFromMesh(mesh); + return pbrModel; +} +#endif // RPBR_IMPLEMENTATION diff --git a/examples/shaders/shaders_basic_pbr.c b/examples/shaders/shaders_basic_pbr.c new file mode 100644 index 00000000..92a88881 --- /dev/null +++ b/examples/shaders/shaders_basic_pbr.c @@ -0,0 +1,171 @@ +/******************************************************************************************* +* +* raylib [core] example - Model Defuse Normal Shader (adapted for HTML5 platform) +* +* This example is prepared to compile for PLATFORM_WEB and PLATFORM_DESKTOP +* As you will notice, code structure is slightly different to the other examples... +* To compile it for PLATFORM_WEB just uncomment #define PLATFORM_WEB at beginning +* +* This example has been created using raylib 5.0 (www.raylib.com) +* raylib is licensed under an unmodified zlib/libpng license (View raylib.h for details) +* +* Copyright (c) 2023-2024 Afan OLOVCIC (@_DevDad) 2015 Ramon Santamaria (@raysan5) +* Model: "Old Rusty Car" (https://skfb.ly/LxRy) by Renafox is licensed under Creative Commons Attribution-NonCommercial (http://creativecommons.org/licenses/by-nc/4.0/). +********************************************************************************************/ + +#include "raylib.h" + +#if defined(PLATFORM_WEB) +#include <emscripten/emscripten.h> +#endif + +#define RPBR_IMPLEMENTATION +#include "rpbr.h" + +#if defined(PLATFORM_DESKTOP) +#define GLSL_VERSION 330 +#else // PLATFORM_ANDROID, PLATFORM_WEB +#define GLSL_VERSION 120 +#endif + + +//---------------------------------------------------------------------------------- +// Main Entry Point +//---------------------------------------------------------------------------------- +int main() +{ + // Initialization + //-------------------------------------------------------------------------------------- + const int screenWidth = 800; + const int screenHeight = 450; + + SetConfigFlags(FLAG_MSAA_4X_HINT); + InitWindow(screenWidth, screenHeight, "raylib [shaders] example - basic pbr"); + + // Define the camera to look into our 3d world + Camera camera = { 0 }; + camera.position = (Vector3){ 2.0f, 2.0f, 6.0f }; // Camera position + camera.target = (Vector3){ 0.0f, 0.5f, 0.0f }; // Camera looking at point + camera.up = (Vector3){ 0.0f, 1.0f, 0.0f }; // Camera up vector (rotation towards target) + camera.fovy = 45.0f; // Camera field-of-view Y + camera.projection = CAMERA_PERSPECTIVE; // Camera projection type + + + Shader shader = LoadShader(TextFormat("resources/shaders/glsl%i/pbr.vs",GLSL_VERSION), + TextFormat("resources/shaders/glsl%i/pbr.fs",GLSL_VERSION)); + + + + PBRModel model = PBRModelLoad("resources/models/old_car_new.glb"); + //if we use obj file formator if model doesn't have tangents we have to calculate MeshTangents + //by using raylib function GenMeshTangents(mesh) for example: obj file doesn't support tangents + //GenMeshTangents(&model.model.meshes[0]); + + PBRMaterial model_mat = (PBRMaterial){0}; + PBRMaterialSetup(&model_mat, shader, NULL); //environment = NULL for now + PBRLoadTextures(&model_mat, PBR_TEXTURE_ALBEDO, "resources/old_car_d.png"); + PBRLoadTextures(&model_mat, PBR_TEXTURE_MRA, "resources/old_car_mra.png"); + PBRLoadTextures(&model_mat, PBR_TEXTURE_NORMAL, "resources/old_car_n.png"); + PBRLoadTextures(&model_mat, PBR_TEXTURE_EMISSIVE, "resources/old_car_e.png"); + PBRSetColor(&model_mat,PBR_COLOR_EMISSIVE, (Color){255,162,0,255}); + PBRSetVec2(&model_mat, PBR_VEC2_TILING,(Vector2){0.5,0.5}); + PBRSetMaterial(&model,&model_mat,0); + + PBRModel floor = PBRModelLoad("resources/models/plane.glb"); + + PBRMaterial floor_mat = (PBRMaterial){0}; + PBRMaterialSetup(&floor_mat, shader, NULL); + PBRLoadTextures(&floor_mat, PBR_TEXTURE_ALBEDO, "resources/road_a.png"); + PBRLoadTextures(&floor_mat, PBR_TEXTURE_MRA, "resources/road_mra.png"); + PBRLoadTextures(&floor_mat, PBR_TEXTURE_NORMAL, "resources/road_n.png"); + PBRSetVec2(&floor_mat, PBR_VEC2_TILING,(Vector2){0.5,0.5}); + PBRSetMaterial(&floor,&floor_mat,0); + + shader.locs[SHADER_LOC_VECTOR_VIEW] = GetShaderLocation(shader, "viewPos"); + int numOfLightsLoc = GetShaderLocation(shader, "numOfLights"); + int numOfLights = 4; + SetShaderValue(shader, numOfLightsLoc, &numOfLights, SHADER_UNIFORM_INT); + + Color ambCol = (Color){26,32,135,255}; + float ambIntens = 0.02; + + int albedoLoc = GetShaderLocation(shader, "albedo"); + PBRSetAmbient(shader,ambCol,ambIntens); + + // Create lights + PBRLight lights[MAX_LIGHTS] = { 0 }; + lights[0] = PBRLightCreate(LIGHT_POINT, (Vector3){ -1, 1, -2 }, (Vector3){0,0,0}, YELLOW,4, shader); + lights[1] = PBRLightCreate(LIGHT_POINT, (Vector3){ 2, 1, 1 }, (Vector3){0,0,0}, GREEN,3.3, shader); + lights[2] = PBRLightCreate(LIGHT_POINT, (Vector3){ -2, 1, 1 }, (Vector3){0,0,0}, RED,8.3, shader); + lights[3] = PBRLightCreate(LIGHT_POINT, (Vector3){ 1, 1, -2 }, (Vector3){0,0,0}, BLUE,2, shader); + SetShaderValueV(shader, GetShaderLocation(shader, "lights"), lights, SHADER_UNIFORM_FLOAT, numOfLights); + + SetTargetFPS(60); // Set our game to run at 60 frames-per-second------------------------------------------------------------- + + int emissiveCnt = 0; + // Main game loop + while (!WindowShouldClose()) // Detect window close button or ESC key + { + // Update + //---------------------------------------------------------------------------------- + UpdateCamera(&camera, CAMERA_ORBITAL); + + // Update the shader with the camera view vector (points towards { 0.0f, 0.0f, 0.0f }) + float cameraPos[3] = {camera.position.x, camera.position.y, camera.position.z}; + SetShaderValue(shader, shader.locs[SHADER_LOC_VECTOR_VIEW], cameraPos, SHADER_UNIFORM_VEC3); + + // Check key inputs to enable/disable lights + if (IsKeyPressed(KEY_Y)) { lights[0].enabled = !lights[0].enabled; } + if (IsKeyPressed(KEY_G)) { lights[1].enabled = !lights[1].enabled; } + if (IsKeyPressed(KEY_R)) { lights[2].enabled = !lights[2].enabled; } + if (IsKeyPressed(KEY_B)) { lights[3].enabled = !lights[3].enabled; } + + // Update light values (actually, only enable/disable them) + for (int i = 0; i < MAX_LIGHTS; i++) PBRLightUpdate(shader, lights[i]); + emissiveCnt--; + if(emissiveCnt<=0){ + emissiveCnt = GetRandomValue(0,20); + PBRSetFloat(&model_mat,PBR_PARAM_EMISSIVE,(float)GetRandomValue(0,100)/100); + } + //---------------------------------------------------------------------------------- + + // Draw + //---------------------------------------------------------------------------------- + BeginDrawing(); + ClearBackground(BLACK); + BeginMode3D(camera); + + PBRDrawModel(floor, (Vector3){0,0,0}, 5.0f); + PBRDrawModel(model, (Vector3) {0, 0.0, 0}, 0.005); + + // Draw spheres to show where the lights are + for (int i = 0; i < MAX_LIGHTS; i++) { + Color col = (Color) {lights[i].color[0] * 255, lights[i].color[1] * 255, lights[i].color[2] * 255, + lights[i].color[3] * 255}; + if (lights[i].enabled) DrawSphereEx(lights[i].position, 0.2f, 8, 8, col); + else DrawSphereWires(lights[i].position, 0.2f, 8, 8, ColorAlpha(col, 0.3f)); + } + EndMode3D(); + + DrawText("(c) Old Rusty Car model by Renafox (https://skfb.ly/LxRy)", screenWidth - 320, screenHeight - 20, 10, GRAY); + DrawFPS(10, 10); + + EndDrawing(); + //---------------------------------------------------------------------------------- + } + + //-------------------------------------------------------------------------------------- + // De-Initialization + //-------------------------------------------------------------------------------------- + + UnloadModel(floor.model); // Unload model + UnloadModel(model.model); // Unload model + UnloadShader(shader); // Unload Shader + UnloadPBRMaterial(floor_mat); // Unload PBRMaterial + UnloadPBRMaterial(model_mat); // Unload PBRMaterial + + CloseWindow(); // Close window and OpenGL context + //-------------------------------------------------------------------------------------- + + return 0; + } |
