This replaces Steep Parallax and should give better quality with fewer samples
Implementation details are here: LearnOpenGL - Parallax Mapping
This replaces Steep Parallax and should give better quality with fewer samples
Implementation details are here: LearnOpenGL - Parallax Mapping
sorry i thought there is missing import.
but i just noticed you use import in 91 line.
@RiccardoBlb any chance you can share a demo screenshot from a scene with Occlusion Parallax enabled and one with Occlusion Parallax disabled.
not good example, have wrong texture to show and sphere is not full round, but maybe some details might be visible.
will try implement this into terrain PBR now.
here for you my friend, much better preview.
its visible it really make a lot difference, its much better.
Riccardo made a great work adding this PR into JME.
edit:
and even better example:
im not sure why color dont work for me, but probably i meesed something up.
now just need wait for @yaRnMcDonuts finished JME PBR Terrain to also add this occlusion parallax for terrain textures. really Terrain PBR for jme is missing feature too.
Given enought samples, steep parallax should look the same as parallax occlusion mapping, this should only reduce the number of samples required to get the same visual effect.
@oxplay2 thanks for the examples.
i think i am successfull adapt it into PBR Terrain.
here result:
im still not sure if everything is ok, but looks fine so far. if @yaRnMcDonuts will need to know how i added it there i can tell so he could prepare JME proper version.
im not sure if @RiccardoBlb used JME terrain on his VIP video, it might be just Quad and object mountains, but anyway im glad it work on PBR Terrain. again great work Riccardo!
edit:
hehe, even water with just moving tex coords look nice, just add some noise blend for parallax texcoords and there would be nice water.
made some another experiment.
seen this parallax occlusion take down some FPS, so why not optimize it with some LOD.
so made some camera distance condition: if(camDist < 0.1){
i know conditions are slow in shaders, but seen no other way for this.
but it dont seem to save a lot fps, it save only if far away, as seen on video.
edit, updated video:
any clues what can be done to LOD-optimize it?
i haven’t looked at this project, but you use a step function to avoid an if statement. Sometimes you just can’t get away from using one.
It has to evaluate both outcomes when both near and far are in the scene, so you save nothing, it just looks worse. In fact it might even be slower now because it does 2 operations. Pretty much the same as what a step mix would do.
I don’t think you can LOD like you want it to because you can’t give the result unless you have the value, so when you call a mix, even if it’s a 1 or a zero it still has to know the result to mix.
i haven’t looked at this project, but you use a step function to avoid an if statement.
thanks, what is this “step function”?
i seen i can use ifdef (or if defined()) to not use heavy if conditions. also learned about this ##index from terrain shader. but i dont know what is this “step function”.
hmm i saved 30 fps with double distance(so better effect) and one thing: each terrain texture (3 there) if defined are causing parallax method to execute (if parallax is defined for this texture ofc)
its like:
#ifdef ALBEDOMAP_0
DEFINE_COORD(_0)
#if defined(PARALLAXMAPPING) && defined (PARALLAXMAP_0)
PARALLAX_BLEND(_0, alphaBlend.r)
#endif
#ifdef NORMALMAP_0
BLEND_NORMAL(_0, alphaBlend.r)
#else
BLEND(_0, alphaBlend.r)
#endif
#endif
so i just added if(intensity > 0.1){ so it skip heavy code from executing if not blended more than 0.1f;
it saved 30 fps like for me for this 3 textures, i think it will save a much more if there would be like 11 textures…
Those are called preprocessors. They are executed before the shader is compiled and truncate the result. If the texture is not defined, just remove all the code inside the ifdef, for example. So if no normal map is defined, don’t even bother calculating it. It’s great for things like that.
https://www.khronos.org/registry/OpenGL-Refpages/gl4/html/step.xhtml
A step function returns a 1 or 0 based on whether a < b or whatever. You can then use it for a mix for example instead of an if statement.
its a very nice function.
but i dont know how to use it to skip heavy parallax code, i would need if condition anyway.
when i would need to use it on calculated parallax value, it will anyway be already calculated by heavy code.
what i mean i can do float isInLOD = step(camDist, m_ParallaxLODDistance);
but anyway i need condition.
You could have 2 materials, one with a map and one without. Just give the materials closest to the camera the parallax and normal maps and the ones further away none of them. Its a common case. If you play ark you can even see it swapping low res textures at like 10m away. That game has some crazy lod techniques.
Only for divergent branches. It will work fine in this case.
It should also be possible to reduce the height by the distance, so that the transition is smooth and you don’t get an abrupt interruption.
You could have 2 materials, one with a map and one without. Just give the materials closest to the camera the parallax and normal maps and the ones further away none of them. Its a common case. If you play ark you can even see it swapping low res textures at like 10m away. That game has some crazy lod techniques.
would need to see code example.
Problem is that Terrain is One material (it share it for all tiles)
i can only imagine stupid code that anyway got condition like:
float isInLOD = step(camDist < m_ParallaxLODDistance);
if(isInLOD == 1) {
#import “highDetailFragmentShader”
} else {
#import “lowDetailFragmentShader”
}
but its 100% not what you mean.
rather based on my knowledge i would make it just via game “setMaterial” for entites far / close distance based.
But anyway Terrain is just one material all the time. so it dont help for this case.
Right i could switch Tile materials somehow (but they have shared material). But not sure it it would not break terrain or terrain itself will not override it later.
Anyway i feel like i dont get your idea, because i never seen solutions like this. (using this step function)
But, i think i could try override Terrain system to use different material for far tiles if possible.
Problem is, i seen Terrain anyway got 9 tiles right? so if we go from center tile to left tile and we are on seam between tiles, there would be seam because one tile use parallax and other not.
here is the Terrain PBR/parallax occlusion based on mix of @yaRnMcDonuts work and @RiccardoBlb work.
yaRnMcDonuts source:
it dont tave tri plannar, because im not sure how to manage texCoords there, but someone might add it.
!!! Please replace “MatDefs” with “Common” for imports, or use same dirs in project as me. I use MatDefs folder with cloned libs to be able to see shader in 3.2.2 IDE properly.
Also there is:
**coord_2.x += g_Time * 0.03; **
to demonstrate tex moving like water, remove it or use if need.
And also: you need ShaderLib/OcclusionParallax.glsllib from Riccardo PR
NORMALMAP_PARALLAX - this is not used, would just need to add to j3md and use
calculateParallax(coord##index, m_ParallaxHeight##index, m_NormalMap##index, ab);
instead of
calculateParallax(coord##index, m_ParallaxHeight##index, m_ParallaxMap##index, ab);
when ifdef NORMALMAP_PARALLAX is true.
frag:
#import "MatDefs/ShaderLib/GLSLCompat.glsllib"
#import "MatDefs/ShaderLib/PBR.glsllib"
#import "MatDefs/ShaderLib/Parallax.glsllib"
#import "MatDefs/ShaderLib/Lighting.glsllib"
uniform vec4 g_LightData[NB_LIGHTS];
uniform vec4 g_AmbientLightColor;
varying vec3 wPosition;
uniform float g_Time;
// Configure height channel
#ifdef NORMALMAP_PARALLAX
#define HEIGHT_MAP A_COMPONENT
#else
#define HEIGHT_MAP R_COMPONENT
#endif
#import "MatDefs/ShaderLib/OcclusionParallax.glsllib"
#if NB_PROBES >= 1
uniform samplerCube g_PrefEnvMap;
uniform vec3 g_ShCoeffs[9];
uniform mat4 g_LightProbeData;
#endif
#if NB_PROBES >= 2
uniform samplerCube g_PrefEnvMap2;
uniform vec3 g_ShCoeffs2[9];
uniform mat4 g_LightProbeData2;
#endif
#if NB_PROBES == 3
uniform samplerCube g_PrefEnvMap3;
uniform vec3 g_ShCoeffs3[9];
uniform mat4 g_LightProbeData3;
#endif
#ifdef EMISSIVE
uniform vec4 m_Emissive;
#endif
#ifdef EMISSIVEMAP
uniform sampler2D m_EmissiveMap;
#endif
#if defined(EMISSIVE) || defined(EMISSIVEMAP)
uniform float m_EmissivePower;
uniform float m_EmissiveIntensity;
#endif
#ifdef SPECGLOSSPIPELINE
uniform sampler2D m_SpecularMap;
uniform sampler2D m_GlossMap;
#endif
#ifdef LIGHTMAP
uniform sampler2D m_LightMap;
#endif
varying vec3 vNormal;
#if defined(NORMALMAP_0) || defined(NORMALMAP_1) || defined(NORMALMAP_2) || defined(NORMALMAP_3) || defined(NORMALMAP_4) || defined(NORMALMAP_5) || defined(NORMALMAP_6) || defined(NORMALMAP_7) || defined(PLAGUEDNORMALMAP)
varying vec4 wTangent;
#endif
varying vec2 texCoord;
uniform vec3 inPosition;
uniform mat4 g_WorldViewMatrix;
uniform vec3 g_CameraPosition;
varying vec3 vPosition;
varying vec3 vnPosition;
varying vec3 vViewDir;
varying vec4 vLightDir;
varying vec4 vnLightDir;
varying vec3 lightVec;
uniform float m_Roughness_0;
uniform float m_Roughness_1;
uniform float m_Roughness_2;
uniform float m_Roughness_3;
uniform float m_Roughness_4;
uniform float m_Roughness_5;
uniform float m_Roughness_6;
uniform float m_Roughness_7;
uniform float m_Roughness_8;
uniform float m_Roughness_9;
uniform float m_Roughness_10;
uniform float m_Roughness_11;
uniform float m_Metallic_0;
uniform float m_Metallic_1;
uniform float m_Metallic_2;
uniform float m_Metallic_3;
uniform float m_Metallic_4;
uniform float m_Metallic_5;
uniform float m_Metallic_6;
uniform float m_Metallic_7;
uniform float m_Metallic_8;
uniform float m_Metallic_9;
uniform float m_Metallic_10;
uniform float m_Metallic_11;
uniform float m_Parallax_0;
uniform float m_Parallax_1;
uniform float m_Parallax_2;
uniform float m_Parallax_3;
uniform float m_Parallax_4;
uniform float m_Parallax_5;
uniform float m_Parallax_6;
uniform float m_Parallax_7;
uniform float m_Parallax_8;
uniform float m_Parallax_9;
uniform float m_Parallax_10;
uniform float m_Parallax_11;
#ifdef PARALLAX_LOD_DISTANCE
uniform float m_ParallaxLODDistance;
#endif
#ifdef ALBEDOMAP_0
uniform sampler2D m_AlbedoMap_0;
#endif
#ifdef ALBEDOMAP_1
uniform sampler2D m_AlbedoMap_1;
#endif
#ifdef ALBEDOMAP_2
uniform sampler2D m_AlbedoMap_2;
#endif
#ifdef ALBEDOMAP_3
uniform sampler2D m_AlbedoMap_3;
#endif
#ifdef ALBEDOMAP_4
uniform sampler2D m_AlbedoMap_4;
#endif
#ifdef ALBEDOMAP_5
uniform sampler2D m_AlbedoMap_5;
#endif
#ifdef ALBEDOMAP_6
uniform sampler2D m_AlbedoMap_6;
#endif
#ifdef ALBEDOMAP_7
uniform sampler2D m_AlbedoMap_7;
#endif
#ifdef ALBEDOMAP_8
uniform sampler2D m_AlbedoMap_8;
#endif
#ifdef ALBEDOMAP_9
uniform sampler2D m_AlbedoMap_9;
#endif
#ifdef ALBEDOMAP_10
uniform sampler2D m_AlbedoMap_10;
#endif
#ifdef ALBEDOMAP_11
uniform sampler2D m_AlbedoMap_11;
#endif
#ifdef ALBEDOMAP_0
uniform float m_AlbedoMap_0_scale;
#endif
#ifdef ALBEDOMAP_1
uniform float m_AlbedoMap_1_scale;
#endif
#ifdef ALBEDOMAP_2
uniform float m_AlbedoMap_2_scale;
#endif
#ifdef ALBEDOMAP_3
uniform float m_AlbedoMap_3_scale;
#endif
#ifdef ALBEDOMAP_4
uniform float m_AlbedoMap_4_scale;
#endif
#ifdef ALBEDOMAP_5
uniform float m_AlbedoMap_5_scale;
#endif
#ifdef ALBEDOMAP_6
uniform float m_AlbedoMap_6_scale;
#endif
#ifdef ALBEDOMAP_7
uniform float m_AlbedoMap_7_scale;
#endif
#ifdef ALBEDOMAP_8
uniform float m_AlbedoMap_8_scale;
#endif
#ifdef ALBEDOMAP_9
uniform float m_AlbedoMap_9_scale;
#endif
#ifdef ALBEDOMAP_10
uniform float m_AlbedoMap_10_scale;
#endif
#ifdef ALBEDOMAP_11
uniform float m_AlbedoMap_11_scale;
#endif
#ifdef ALPHAMAP
uniform sampler2D m_AlphaMap;
#endif
#ifdef ALPHAMAP_1
uniform sampler2D m_AlphaMap_1;
#endif
#ifdef ALPHAMAP_2
uniform sampler2D m_AlphaMap_2;
#endif
#ifdef NORMALMAP_0
uniform sampler2D m_NormalMap_0;
#endif
#ifdef NORMALMAP_1
uniform sampler2D m_NormalMap_1;
#endif
#ifdef NORMALMAP_2
uniform sampler2D m_NormalMap_2;
#endif
#ifdef NORMALMAP_3
uniform sampler2D m_NormalMap_3;
#endif
#ifdef NORMALMAP_4
uniform sampler2D m_NormalMap_4;
#endif
#ifdef NORMALMAP_5
uniform sampler2D m_NormalMap_5;
#endif
#ifdef NORMALMAP_6
uniform sampler2D m_NormalMap_6;
#endif
#ifdef NORMALMAP_7
uniform sampler2D m_NormalMap_7;
#endif
#ifdef NORMALMAP_8
uniform sampler2D m_NormalMap_8;
#endif
#ifdef NORMALMAP_9
uniform sampler2D m_NormalMap_9;
#endif
#ifdef NORMALMAP_10
uniform sampler2D m_NormalMap_10;
#endif
#ifdef NORMALMAP_11
uniform sampler2D m_NormalMap_11;
#endif
#ifdef PARALLAXMAP_0
uniform sampler2D m_ParallaxMap_0;
uniform float m_ParallaxHeight_0;
#endif
#ifdef PARALLAXMAP_1
uniform sampler2D m_ParallaxMap_1;
uniform float m_ParallaxHeight_1;
#endif
#ifdef PARALLAXMAP_2
uniform sampler2D m_ParallaxMap_2;
uniform float m_ParallaxHeight_2;
#endif
#ifdef PARALLAXMAP_3
uniform sampler2D m_ParallaxMap_3;
uniform float m_ParallaxHeight_3;
#endif
#ifdef PARALLAXMAP_4
uniform sampler2D m_ParallaxMap_4;
uniform float m_ParallaxHeight_4;
#endif
#ifdef PARALLAXMAP_5
uniform sampler2D m_ParallaxMap_5;
uniform float m_ParallaxHeight_5;
#endif
#ifdef PARALLAXMAP_6
uniform sampler2D m_ParallaxMap_6;
uniform float m_ParallaxHeight_6;
#endif
#ifdef PARALLAXMAP_7
uniform sampler2D m_ParallaxMap_7;
uniform float m_ParallaxHeight_7;
#endif
#ifdef PARALLAXMAP_8
uniform sampler2D m_ParallaxMap_8;
uniform float m_ParallaxHeight_8;
#endif
#ifdef PARALLAXMAP_9
uniform sampler2D m_ParallaxMap_9;
uniform float m_ParallaxHeight_9;
#endif
#ifdef PARALLAXMAP_10
uniform sampler2D m_ParallaxMap_10;
uniform float m_ParallaxHeight_10;
#endif
#ifdef PARALLAXMAP_11
uniform sampler2D m_ParallaxMap_11;
uniform float m_ParallaxHeight_11;
#endif
vec4 emissive;
varying vec3 wNormal;
//ifdef TRI_PLANAR_MAPPING
varying vec4 wVertex;
//#endif
varying float camDist;
vec2 coord;
vec4 albedo;
vec4 tempAlbedo, tempNormal;
vec3 normal = vec3(0.5,0.5,1);
vec3 newNormal;
vec3 parallax;
vec2 newTexCoord;
vec3 viewDir;
mat3 tbnMat;
vec3 norm;
float Metallic;
float Roughness;
#define DEFINE_COORD(index) vec2 coord##index = newTexCoord * m_AlbedoMap##index##_scale;
#define BLEND(index, ab)\
tempAlbedo.rgb = texture2D(m_AlbedoMap##index, coord##index).rgb;\
albedo.rgb = mix( albedo.rgb, tempAlbedo.rgb ,ab );\
normal.rgb = mix(normal.xyz, wNormal.xyz, ab);\
Metallic = mix(Metallic, m_Metallic##index, ab);\
Roughness = mix(Roughness, m_Roughness##index, ab);
#define BLEND_NORMAL(index, ab)\
tempAlbedo.rgb = texture2D(m_AlbedoMap##index, coord##index).rgb;\
albedo.rgb = mix( albedo.rgb, tempAlbedo.rgb ,ab );\
Metallic = mix(Metallic, m_Metallic##index, ab);\
Roughness = mix(Roughness, m_Roughness##index, ab);\
newNormal = texture2D(m_NormalMap##index, coord##index).xyz;\
normal = mix(normal, newNormal, ab);
#define PARALLAX_BLEND(index, ab)\
calculateParallax(coord##index, m_ParallaxHeight##index, m_ParallaxMap##index, ab);
void calculateParallax(inout vec2 newTexCoord, in float parallaxHeight, in sampler2D map, in float intensity) {
#ifdef PARALLAX_LOD_DISTANCE
if(camDist < m_ParallaxLODDistance && intensity > 0.1){
vec3 vViewDir = viewDir * tbnMat;
Parallax_initFor(vViewDir,parallaxHeight);
Parallax_displaceCoords(newTexCoord,map);
}
#else
if(intensity > 0.1){
vec3 vViewDir = viewDir * tbnMat;
Parallax_initFor(vViewDir,parallaxHeight);
Parallax_displaceCoords(newTexCoord,map);
}
#endif
}
vec4 calculateAlbedoBlend(in vec2 newTexCoord) {
vec4 alphaBlend = texture2D( m_AlphaMap, newTexCoord.xy );
vec4 albedo = vec4(1.0);
Roughness = m_Roughness_0;
Metallic = m_Metallic_0 ;
vec3 blending = abs( wNormal );
blending = (blending -0.2) * 0.7;
blending = normalize(max(blending, 0.00001)); // Force weights to sum to 1.0 (very important!)
float b = (blending.x + blending.y + blending.z);
blending /= vec3(b, b, b);
vec3 wvPosition=(vec4(inPosition,1)*g_WorldViewMatrix).xyz;
#ifdef ALPHAMAP_1
vec4 alphaBlend1 = texture2D( m_AlphaMap_1, newTexCoord.xy );
#endif
#ifdef ALPHAMAP_2
vec4 alphaBlend2 = texture2D( m_AlphaMap_2, newTexCoord.xy );
#endif
#ifdef ALBEDOMAP_0
DEFINE_COORD(_0)
//NOTE! the old (phong) terrain shaders do not have an "_0" for the first diffuse map, it is just "DiffuseMap"
#if defined(PARALLAXMAPPING) && defined (PARALLAXMAP_0)
PARALLAX_BLEND(_0, alphaBlend.r)
#endif
#ifdef NORMALMAP_0
BLEND_NORMAL(_0, alphaBlend.r)
#else
BLEND(_0, alphaBlend.r)
#endif
#endif
#ifdef ALBEDOMAP_1
DEFINE_COORD(_1)
#if defined(PARALLAXMAPPING) && defined (PARALLAXMAP_1)
PARALLAX_BLEND(_1, alphaBlend.g)
#endif
#ifdef NORMALMAP_1
BLEND_NORMAL(_1, alphaBlend.g)
#else
BLEND(_1, alphaBlend.g)
#endif
#endif
#ifdef ALBEDOMAP_2
DEFINE_COORD(_2)
#if defined(PARALLAXMAPPING) && defined (PARALLAXMAP_2)
coord_2.x += g_Time * 0.03;
PARALLAX_BLEND(_2, alphaBlend.b)
#endif
#ifdef NORMALMAP_2
BLEND_NORMAL(_2, alphaBlend.b)
#else
BLEND(_2, alphaBlend.b)
#endif
#endif
#ifdef ALBEDOMAP_3
DEFINE_COORD(_3)
#if defined(PARALLAXMAPPING) && defined (PARALLAXMAP_3)
PARALLAX_BLEND(_3, alphaBlend.a)
#endif
#ifdef NORMALMAP_3
BLEND_NORMAL(_3, alphaBlend.a)
#else
BLEND(_3, alphaBlend.a)
#endif
#endif
#ifdef ALPHAMAP_1
#ifdef ALBEDOMAP_4
DEFINE_COORD(_4)
#if defined(PARALLAXMAPPING) && defined (PARALLAXMAP_4)
PARALLAX_BLEND(_4, alphaBlend1.r)
#endif
#ifdef NORMALMAP_4
BLEND_NORMAL(_4, alphaBlend1.r)
#else
BLEND(_4, alphaBlend1.r)
#endif
#endif
#ifdef ALBEDOMAP_5
DEFINE_COORD(_5)
#if defined(PARALLAXMAPPING) && defined (PARALLAXMAP_5)
PARALLAX_BLEND(_5, alphaBlend1.g)
#endif
#ifdef NORMALMAP_5
BLEND_NORMAL(_5, alphaBlend1.g)
#else
BLEND(_5, alphaBlend1.g)
#endif
#endif
#ifdef ALBEDOMAP_6
DEFINE_COORD(_6)
#if defined(PARALLAXMAPPING) && defined (PARALLAXMAP_6)
PARALLAX_BLEND(_6, alphaBlend1.b)
#endif
#ifdef NORMALMAP_6
BLEND_NORMAL(_6, alphaBlend1.b)
#else
BLEND(_6, alphaBlend1.b)
#endif
#endif
#ifdef ALBEDOMAP_7
DEFINE_COORD(_7)
#if defined(PARALLAXMAPPING) && defined (PARALLAXMAP_7)
PARALLAX_BLEND(_7, alphaBlend1.a)
#endif
#ifdef NORMALMAP_7
BLEND_NORMAL(_7, alphaBlend1.a)
#else
BLEND(_7, alphaBlend1.a)
#endif
#endif
#endif
#ifdef ALPHAMAP_2
#ifdef ALBEDOMAP_8
DEFINE_COORD(_8)
#if defined(PARALLAXMAPPING) && defined (PARALLAXMAP_8)
PARALLAX_BLEND(_8, alphaBlend2.r)
#endif
#ifdef NORMALMAP_8
BLEND_NORMAL(_8, alphaBlend2.r)
#else
BLEND(_8, alphaBlend2.r)
#endif
#endif
#ifdef ALBEDOMAP_9
DEFINE_COORD(_9)
#if defined(PARALLAXMAPPING) && defined (PARALLAXMAP_9)
PARALLAX_BLEND(_9, alphaBlend2.g)
#endif
#ifdef NORMALMAP_9
BLEND_NORMAL(_9, alphaBlend2.g)
#else
BLEND(_9, alphaBlend2.g)
#endif
#endif
#ifdef ALBEDOMAP_10
DEFINE_COORD(_10)
#if defined(PARALLAXMAPPING) && defined (PARALLAXMAP_10)
PARALLAX_BLEND(_10, alphaBlend2.b)
#endif
#ifdef NORMALMAP_10
BLEND_NORMAL(_10, alphaBlend2.b)
#else
BLEND(_10, alphaBlend2.b)
#endif
#endif
#ifdef ALBEDOMAP_11
DEFINE_COORD(_11)
#if defined(PARALLAXMAPPING) && defined (PARALLAXMAP_11)
PARALLAX_BLEND(_11, alphaBlend2.a)
#endif
#ifdef NORMALMAP_11
BLEND_NORMAL(_11, alphaBlend2.a)
#else
BLEND(_11, alphaBlend2.a)
#endif
#endif
#endif
return albedo;
}
#ifdef PROBE_COLOR
uniform vec4 m_ProbeColor;
#endif
void main(){
viewDir = normalize(g_CameraPosition - wPosition);
vec3 norm = normalize(wNormal);
normal = norm;
//norm = vec3(0.5, 0.5, 1.0);
#if defined(NORMALMAP_0) || defined(PARALLAXMAP) || defined(PLAGUEDNORMALMAP)
vec3 tan = normalize(wTangent.xyz);
//tbnMat = mat3(tan, wTangent.w * cross( (wNormal), (tan)), norm);
tbnMat = mat3(tan, wTangent.w * cross( (norm), (tan)), norm);
#endif
newTexCoord=texCoord;
//always calculated since the
vec3 blending;
#ifdef ALBEDOMAP_0
#ifdef ALPHAMAP
albedo = calculateAlbedoBlend(newTexCoord);
#else
albedo = texture2D(m_AlbedoMap_0, newTexCoord);
#endif
#endif
if(albedo.a <= 0.1){
albedo.r = 1.0;
discard;
}
#ifdef ROUGHNESSMAP
Roughness = texture2D(m_RoughnessMap, newTexCoord).r * Roughness;
#endif
Roughness = max(Roughness, 1e-4);
#ifdef METALLICMAP
Metallic = texture2D(m_MetallicMap, newTexCoord).r;
#endif
#ifdef METALLICMAP
Metallic = texture2D(m_MetallicMap, newTexCoord).r * max(Metallic, 0.0);
#else
Metallic = max(Metallic, 0.0);
#endif
//---------------------
// normal calculations
//---------------------
#if defined(NORMALMAP_0) || defined(NORMALMAP_1) || defined(NORMALMAP_2) || defined(NORMALMAP_3) || defined(NORMALMAP_4) || defined(NORMALMAP_5) || defined(NORMALMAP_6) || defined(NORMALMAP_7) || defined(NORMALMAP_8) || defined(NORMALMAP_9) || defined(NORMALMAP_10) || defined(NORMALMAP_11)
#ifdef TRI_PLANAR_MAPPING
// normal = calculateNormalTriPlanar(wNormal, wVertex, texCoord);
#else
// normal = calculateNormal(texCoord);
#endif
normal += norm * 0.9;
normal = normalize(normal * vec3(2.0) - vec3(1.0));
normal.z /= 100;
normal = normalize(normal);
#else
normal = normalize(norm * vec3(2.0) - vec3(1.0));
normal = wNormal;
#endif
// normal = normalize(normal * vec3(2.0) - vec3(1.0));
#ifdef SPECGLOSSPIPELINE
#ifdef USE_PACKED_SG
vec4 specularColor = texture2D(m_SpecularGlossinessMap, newTexCoord);
float glossiness = specularColor.a * m_Glossiness;
specularColor *= m_Specular;
#else
#ifdef SPECULARMAP
vec4 specularColor = texture2D(m_SpecularMap, newTexCoord);
#else
vec4 specularColor = vec4(1.0);
#endif
#ifdef GLOSSINESSMAP
float glossiness = texture2D(m_GlossinessMap, newTexCoord).r * m_Glossiness;
#else
float glossiness = m_Glossiness;
#endif
specularColor *= m_Specular;
#endif
vec4 diffuseColor = albedo;// * (1.0 - max(max(specularColor.r, specularColor.g), specularColor.b));
Roughness = 1.0 - glossiness;
vec3 fZero = specularColor.xyz;
#else
float specular = 0.5;
float nonMetalSpec = 0.08 * specular;
vec4 specularColor = (nonMetalSpec - nonMetalSpec * Metallic) + albedo * Metallic;
vec4 diffuseColor = albedo - albedo * Metallic;
vec3 fZero = vec3(specular);
#endif
gl_FragColor.rgb = vec3(0.0);
vec3 ao = vec3(1.0);
float ndotv = max( dot( normal, viewDir ),0.0);
for( int i = 0;i < NB_LIGHTS; i+=3){
vec4 lightColor = g_LightData[i];
vec4 lightData1 = g_LightData[i+1];
vec4 lightDir;
vec3 lightVec;
lightComputeDir(wPosition, lightColor.w, lightData1, lightDir, lightVec);
float fallOff = 1.0;
#if __VERSION__ >= 110
// allow use of control flow
if(lightColor.w > 1.0){
#endif
fallOff = computeSpotFalloff(g_LightData[i+2], lightVec);
#if __VERSION__ >= 110
}
#endif
//point light attenuation
fallOff *= lightDir.w;
lightDir.xyz = normalize(lightDir.xyz);
vec3 directDiffuse;
vec3 directSpecular;
float hdotv = PBR_ComputeDirectLight(normal, lightDir.xyz, viewDir,
lightColor.rgb, fZero, Roughness, ndotv,
directDiffuse, directSpecular);
vec3 directLighting = diffuseColor.rgb *directDiffuse + directSpecular;
gl_FragColor.rgb += directLighting * fallOff;
}
#if NB_PROBES >= 1
vec3 color1 = vec3(0.0);
vec3 color2 = vec3(0.0);
vec3 color3 = vec3(0.0);
float weight1 = 1.0;
float weight2 = 0.0;
float weight3 = 0.0;
float ndf = renderProbe(viewDir, wPosition, normal, norm, Roughness, diffuseColor, specularColor, ndotv, ao, g_LightProbeData, g_ShCoeffs, g_PrefEnvMap, color1);
#if NB_PROBES >= 2
float ndf2 = renderProbe(viewDir, wPosition, normal, norm, Roughness, diffuseColor, specularColor, ndotv, ao, g_LightProbeData2, g_ShCoeffs2, g_PrefEnvMap2, color2);
#endif
#if NB_PROBES == 3
float ndf3 = renderProbe(viewDir, wPosition, normal, norm, Roughness, diffuseColor, specularColor, ndotv, ao, g_LightProbeData3, g_ShCoeffs3, g_PrefEnvMap3, color3);
#endif
#if NB_PROBES >= 2
float invNdf = max(1.0 - ndf,0.0);
float invNdf2 = max(1.0 - ndf2,0.0);
float sumNdf = ndf + ndf2;
float sumInvNdf = invNdf + invNdf2;
#if NB_PROBES == 3
float invNdf3 = max(1.0 - ndf3,0.0);
sumNdf += ndf3;
sumInvNdf += invNdf3;
weight3 = ((1.0 - (ndf3 / sumNdf)) / (NB_PROBES - 1)) * (invNdf3 / sumInvNdf);
#endif
weight1 = ((1.0 - (ndf / sumNdf)) / (NB_PROBES - 1)) * (invNdf / sumInvNdf);
weight2 = ((1.0 - (ndf2 / sumNdf)) / (NB_PROBES - 1)) * (invNdf2 / sumInvNdf);
float weightSum = weight1 + weight2 + weight3;
weight1 /= weightSum;
weight2 /= weightSum;
weight3 /= weightSum;
#endif
#if USE_AMBIENT_LIGHT
color1.rgb *= g_AmbientLightColor.rgb;
color2.rgb *= g_AmbientLightColor.rgb;
color3.rgb *= g_AmbientLightColor.rgb;
#endif
gl_FragColor.rgb += color1 * clamp(weight1,0.0,1.0) + color2 * clamp(weight2,0.0,1.0) + color3 * clamp(weight3,0.0,1.0);
#endif
#if defined(EMISSIVE) || defined (EMISSIVEMAP)
#ifdef EMISSIVEMAP
emissive = texture2D(m_EmissiveMap, newTexCoord);
#else
emissive = m_Emissive;
#endif
gl_FragColor += emissive * pow(emissive.a, m_EmissivePower) * m_EmissiveIntensity;
#endif
gl_FragColor.a = 1.0;
}
vert:
#import "MatDefs/ShaderLib/GLSLCompat.glsllib"
#import "MatDefs/ShaderLib/Instancing.glsllib"
attribute vec3 inPosition;
attribute vec3 inNormal;
attribute vec2 inTexCoord;
uniform vec3 g_CameraPosition;
uniform vec4 g_AmbientLightColor; //passed to .frag for scaling light probe brightness in 3.3 compatible version of this shader.
varying vec2 texCoord;
varying vec3 wPosition;
varying vec3 wNormal;
#ifdef TRI_PLANAR_MAPPING
varying vec4 wVertex;
#endif
#if defined(NORMALMAP_0) || defined(NORMALMAP_1) || defined(NORMALMAP_2) || defined(NORMALMAP_3) || defined(NORMALMAP_4) || defined(PLAGUEDNORMALMAP)
attribute vec4 inTangent;
varying vec4 wTangent;
#endif
varying float camDist;
void main(){
vec4 modelSpacePos = vec4(inPosition, 1.0);
gl_Position = TransformWorldViewProjection(modelSpacePos);
texCoord = inTexCoord;
wPosition = TransformWorld(modelSpacePos).xyz;
wNormal = normalize(TransformWorldNormal(inNormal));
#if defined(NORMALMAP_0) || defined(NORMALMAP_1) || defined(NORMALMAP_2) || defined(NORMALMAP_3) || defined(NORMALMAP_4) || defined(NORMALMAP_5) || defined(NORMALMAP_6) || defined(NORMALMAP_7) || defined(PLAGUEDNORMALMAP)
wTangent = vec4(TransformWorldNormal(inTangent.xyz),inTangent.w);
#endif
#ifdef TRI_PLANAR_MAPPING
wVertex = vec4(inPosition,0.0);
wNormal = inNormal;
#endif
camDist = distance(g_CameraPosition.xyz, wPosition.xyz);
}
j3md:
// NOTE: Doesn't support OpenGL1
MaterialDef PBR Terrain {
MaterialParameters {
Float NormalType : -1.0
Vector4 ProbeColor
// Use alpha channel of normal texture for parallax mapping;
Boolean parallaxMapping
Float ParallaxLODDistance : 20
// The emissive color of the object
Color Emissive
// the emissive power
Float EmissivePower : 3.5
// the emissive intensity
Float EmissiveIntensity : 2.3
// Specular/gloss map
Texture2D MetallicMap -LINEAR
// Set to Use Lightmap
Texture2D LightMap
Float Roughness_0 : 0.0
Float Roughness_1 : 0.0
Float Roughness_2 : 0.0
Float Roughness_3 : 0.0
Float Roughness_4 : 0.0
Float Roughness_5 : 0.0
Float Roughness_6 : 0.0
Float Roughness_7 : 0.0
Float Roughness_8 : 0.0
Float Roughness_9 : 0.0
Float Roughness_10 : 0.0
Float Roughness_11 : 0.0
Float Metallic_0 : 0.0
Float Metallic_1 : 0.0
Float Metallic_2 : 0.0
Float Metallic_3 : 0.0
Float Metallic_4 : 0.0
Float Metallic_5 : 0.0
Float Metallic_6 : 0.0
Float Metallic_7 : 0.0
Float Metallic_8 : 0.0
Float Metallic_9 : 0.0
Float Metallic_10 : 0.0
Float Metallic_11 : 0.0
// use tri-planar mapping
Boolean useTriPlanarMapping
// Use ward specular instead of phong
Boolean WardIso
// Albedo color
Color Albedo
// Texture map #0
Texture2D AlbedoMap_0
Float AlbedoMap_0_scale
Texture2D NormalMap_0 -LINEAR
Texture2D ParallaxMap_0 -LINEAR
Float ParallaxHeight_0
// Texture map #1
Texture2D AlbedoMap_1
Float AlbedoMap_1_scale
Texture2D NormalMap_1 -LINEAR
Texture2D ParallaxMap_1 -LINEAR
Float ParallaxHeight_1
// Texture map #2
Texture2D AlbedoMap_2
Float AlbedoMap_2_scale
Texture2D NormalMap_2 -LINEAR
Texture2D ParallaxMap_2 -LINEAR
Float ParallaxHeight_2
// Texture map #3
Texture2D AlbedoMap_3
Float AlbedoMap_3_scale
Texture2D NormalMap_3 -LINEAR
Texture2D ParallaxMap_3 -LINEAR
Float ParallaxHeight_3
// Texture map #4
Texture2D AlbedoMap_4
Float AlbedoMap_4_scale
Texture2D NormalMap_4 -LINEAR
Texture2D ParallaxMap_4 -LINEAR
Float ParallaxHeight_4
// Texture map #5
Texture2D AlbedoMap_5
Float AlbedoMap_5_scale
Texture2D NormalMap_5 -LINEAR
Texture2D ParallaxMap_5 -LINEAR
Float ParallaxHeight_5
// Texture map #6
Texture2D AlbedoMap_6
Float AlbedoMap_6_scale
Texture2D NormalMap_6 -LINEAR
Texture2D ParallaxMap_6 -LINEAR
Float ParallaxHeight_6
// Texture map #7
Texture2D AlbedoMap_7
Float AlbedoMap_7_scale
Texture2D NormalMap_7 -LINEAR
Texture2D ParallaxMap_7 -LINEAR
Float ParallaxHeight_7
// Texture map #8
Texture2D AlbedoMap_8
Float AlbedoMap_8_scale
Texture2D NormalMap_8 -LINEAR
Texture2D ParallaxMap_8 -LINEAR
Float ParallaxHeight_8
// Texture map #9
Texture2D AlbedoMap_9
Float AlbedoMap_9_scale
Texture2D NormalMap_9 -LINEAR
Texture2D ParallaxMap_9 -LINEAR
Float ParallaxHeight_9
// Texture map #10
Texture2D AlbedoMap_10
Float AlbedoMap_10_scale
Texture2D NormalMap_10 -LINEAR
Texture2D ParallaxMap_10 -LINEAR
Float ParallaxHeight_10
// Texture map #11
Texture2D AlbedoMap_11
Float AlbedoMap_11_scale
Texture2D NormalMap_11 -LINEAR
Texture2D ParallaxMap_11 -LINEAR
Float ParallaxHeight_11
// Texture that specifies alpha values
Texture2D AlphaMap -LINEAR
Texture2D AlphaMap_1 -LINEAR
Texture2D AlphaMap_2 -LINEAR
// For Spec gloss pipeline
Boolean UseSpecGloss
Texture2D SpecularMap
Texture2D GlossinessMap
Texture2D SpecularGlossinessMap
Color Specular : 1.0 1.0 1.0 1.0
Float Glossiness : 1.0
Vector4 ProbeData
// Prefiltered Env Map for indirect specular lighting
TextureCubeMap PrefEnvMap -LINEAR
// Irradiance map for indirect diffuse lighting
TextureCubeMap IrradianceMap -LINEAR
//integrate BRDF map for indirect Lighting
Texture2D IntegrateBRDF -LINEAR
// Parallax/height map
Texture2D ParallaxMap -LINEAR
//Set to true is parallax map is stored in the alpha channel of the normal map
Boolean PackedNormalParallax
// Set to Use Lightmap
Texture2D LightMap
// Set to use TexCoord2 for the lightmap sampling
Boolean SeparateTexCoord
// the light map is a gray scale ao map, on ly the r channel will be read.
Boolean LightMapAsAOMap
//shadows
Int FilterMode
Boolean HardwareShadows
Texture2D ShadowMap0
Texture2D ShadowMap1
Texture2D ShadowMap2
Texture2D ShadowMap3
//pointLights
Texture2D ShadowMap4
Texture2D ShadowMap5
Float ShadowIntensity
Vector4 Splits
Vector2 FadeInfo
Matrix4 LightViewProjectionMatrix0
Matrix4 LightViewProjectionMatrix1
Matrix4 LightViewProjectionMatrix2
Matrix4 LightViewProjectionMatrix3
//pointLight
Matrix4 LightViewProjectionMatrix4
Matrix4 LightViewProjectionMatrix5
Vector3 LightPos
Vector3 LightDir
Float PCFEdge
Float ShadowMapSize
// For hardware skinning
Int NumberOfBones
Matrix4Array BoneMatrices
//For instancing
Boolean UseInstancing
//For Vertex Color
Boolean UseVertexColor
Boolean BackfaceShadows : false
}
Technique {
LightMode SinglePassAndImageBased
VertexShader GLSL150: MatDefs/Terrain/plagued/terrainPBR.vert
FragmentShader GLSL150: MatDefs/Terrain/plagued/terrainPBR.frag
WorldParameters {
WorldViewProjectionMatrix
CameraPosition
WorldMatrix
WorldNormalMatrix
ViewProjectionMatrix
ViewMatrix
Time
}
Defines {
PARALLAX_LOD_DISTANCE : ParallaxLODDistance
PARALLAXMAPPING : parallaxMapping
EMISSIVEMAP : EmissiveMap
SPECGLOSSPIPELINE : SpecularMap
PROBE_COLOR : ProbeColor
NORMAL_TYPE: NormalType
TRI_PLANAR_MAPPING : useTriPlanarMapping
ALBEDOMAP_0 : AlbedoMap_0
ALBEDOMAP_1 : AlbedoMap_1
ALBEDOMAP_2 : AlbedoMap_2
ALBEDOMAP_3 : AlbedoMap_3
ALBEDOMAP_4 : AlbedoMap_4
ALBEDOMAP_5 : AlbedoMap_5
ALBEDOMAP_6 : AlbedoMap_6
ALBEDOMAP_7 : AlbedoMap_7
ALBEDOMAP_8 : AlbedoMap_8
ALBEDOMAP_9 : AlbedoMap_9
ALBEDOMAP_10 : AlbedoMap_10
ALBEDOMAP_11 : AlbedoMap_11
NORMALMAP_0 : NormalMap_0
NORMALMAP_1 : NormalMap_1
NORMALMAP_2 : NormalMap_2
NORMALMAP_3 : NormalMap_3
NORMALMAP_4 : NormalMap_4
NORMALMAP_5 : NormalMap_5
NORMALMAP_6 : NormalMap_6
NORMALMAP_7 : NormalMap_7
NORMALMAP_8 : NormalMap_8
NORMALMAP_9 : NormalMap_9
NORMALMAP_10 : NormalMap_10
NORMALMAP_11 : NormalMap_11
SPECULARMAP : SpecularMap
ALPHAMAP : AlphaMap
ALPHAMAP_1 : AlphaMap_1
ALPHAMAP_2 : AlphaMap_2
PARALLAXMAP_0 : ParallaxMap_0
PARALLAXMAP_1 : ParallaxMap_1
PARALLAXMAP_2 : ParallaxMap_2
PARALLAXMAP_3 : ParallaxMap_3
PARALLAXMAP_4 : ParallaxMap_4
PARALLAXMAP_5 : ParallaxMap_5
PARALLAXMAP_6 : ParallaxMap_6
PARALLAXMAP_7 : ParallaxMap_7
PARALLAXMAP_8 : ParallaxMap_8
PARALLAXMAP_9 : ParallaxMap_9
PARALLAXMAP_10 : ParallaxMap_10
PARALLAXMAP_11 : ParallaxMap_11
}
}
}
example parallax code for material:
mat_terrain = new Material(assetManager, "MatDefs/Terrain/terrainPBR.j3md");
mat_terrain.setTexture("AlphaMap", assetManager.loadTexture("Textures/Terrain/splat/alphamap2.png"));
Texture grass = assetManager.loadTexture("Textures/materials/Ground07/Ground07_col.jpg");
grass.setWrap(Texture.WrapMode.Repeat);
mat_terrain.setTexture("AlbedoMap_0", grass);
mat_terrain.setFloat("AlbedoMap_0_scale", 128f);
mat_terrain.setFloat("Metallic_0", 0.2f);
mat_terrain.setFloat("Roughness_0", 0.9f);
Texture dirt = assetManager.loadTexture("Textures/materials/Ground01/Ground01_col_var1.jpg");
dirt.setWrap(Texture.WrapMode.Repeat);
mat_terrain.setTexture("AlbedoMap_1", dirt);
mat_terrain.setFloat("AlbedoMap_1_scale", 128f);
mat_terrain.setFloat("Metallic_1", 0.3f);
mat_terrain.setFloat("Roughness_1", 0.8f);
Texture rock = assetManager.loadTexture("Textures/materials/Ground18/Ground18_col.jpg");
rock.setWrap(Texture.WrapMode.Repeat);
mat_terrain.setTexture("AlbedoMap_2", rock);
mat_terrain.setFloat("AlbedoMap_2_scale", 128f);
mat_terrain.setFloat("Metallic_2", 1f);
mat_terrain.setFloat("Roughness_2", 0.1f);
// NORMAL MAPS
Texture tex1Normal = assetManager.loadTexture("Textures/materials/Ground07/Ground07_nrm.jpg"); //9
tex1Normal.setWrap(Texture.WrapMode.Repeat);
Texture tex2Normal = assetManager.loadTexture("Textures/materials/Ground01/Ground01_nrm.jpg");
tex2Normal.setWrap(Texture.WrapMode.Repeat);
Texture tex3Normal = assetManager.loadTexture("Textures/materials/Ground18/Ground18_nrm.jpg");
tex3Normal.setWrap(Texture.WrapMode.Repeat);
mat_terrain.setTexture("NormalMap_0", tex1Normal);
mat_terrain.setTexture("NormalMap_1", tex2Normal);
mat_terrain.setTexture("NormalMap_2", tex3Normal);
Texture texParallax = assetManager.loadTexture("Textures/materials/Ground07/Ground07_disp.jpg");
texParallax.setWrap(Texture.WrapMode.Repeat);
mat_terrain.setTexture("ParallaxMap_0", texParallax);
Texture texParallax2 = assetManager.loadTexture("Textures/materials/Ground01/Ground01_disp.jpg");
texParallax2.setWrap(Texture.WrapMode.Repeat);
mat_terrain.setTexture("ParallaxMap_1", texParallax2);
Texture texParallax3 = assetManager.loadTexture("Textures/materials/Ground18/Ground18_disp.jpg");
texParallax3.setWrap(Texture.WrapMode.Repeat);
mat_terrain.setTexture("ParallaxMap_2", texParallax3);
mat_terrain.setFloat("ParallaxHeight_0", 0.06f);
mat_terrain.setFloat("ParallaxHeight_1", 0.01f);
mat_terrain.setFloat("ParallaxHeight_2", 0.02f);
mat_terrain.setBoolean("parallaxMapping", true);
mat_terrain.setFloat("ParallaxLODDistance", 30f);
I’ll be away from home without a computer or internet for the next week, but I will work on adding the code to the PBR Terrain shader as soon as I’m back.
great wish you great holidays. one week is not long though.
i already cleaned your PBR terrain from affliction and added occlusion parallax, but there are things you know better how to do like:
TRI PLANNAR parallax.
because im not sure how to modify this for tri plannar:
#define PARALLAX_BLEND(index, ab)\
calculateParallax(coord##index, m_ParallaxHeight##index, m_ParallaxMap##index, ab);
there are also things to add like:
using NORMALMAP_PARALLAX
HorizonFade, because its not used in terrain pbr, but it is in new PBR material.
option for alternative SteepParallax - once i used occlusion parallax i dont gived possibility for steep parallax here.
make normals for tri plannar proper
because im not sure if this is totally correct:
normal += norm * 0.9;
normal = normalize(normal * vec3(2.0) - vec3(1.0));
normal.z /= 100;
normal = normalize(normal);
and maybe something more.
once all done i think it might be added into JME.