Hello,
So, I am working with a smooth voxel terrain, and thought it would be kinda fun to try my hand at modifying the PBRLighting shader to use textures arrays and get PBR lighting working on my terrain.
I decided to use TexCoord8 to store the voxel IDs in for the textures. An initial test with just the BaseColorMap as a texture array worked to an extent. But now that I have converted all the textures to texture arrays, all I get is a black object. Currently I am passing in a array of BaseColorMaps and NormalMaps.
I will continue to work on it to see if I can get it to work, but for reference here is my current work on it.
ArrayPBRLighting.j3md
MaterialDef PBR Lighting {
MaterialParameters {
// Alpha threshold for fragment discarding
Float AlphaDiscardThreshold (AlphaTestFallOff)
//metalness of the material
Float Metallic : 1.0
//Roughness of the material
Float Roughness : 1.0
// Base material color
Color BaseColor : 1.0 1.0 1.0 1.0
// The emissive color of the object
Color Emissive
// the emissive power
Float EmissivePower : 3.0
// the emissive intensity
Float EmissiveIntensity : 2.0
// BaseColor map
TextureArray BaseColorMap
// Metallic map
TextureArray MetallicMap -LINEAR
// Roughness Map
TextureArray RoughnessMap -LINEAR
//Metallic and Roughness are packed respectively in the b and g channel of a single map
// r: unspecified
// g: Roughness
// b: Metallic
TextureArray MetallicRoughnessMap -LINEAR
// Texture of the emissive parts of the material
TextureArray EmissiveMap
// Normal map
TextureArray NormalMap -LINEAR
//The type of normal map: -1.0 (DirectX), 1.0 (OpenGl)
Float NormalType : -1.0
// For Spec gloss pipeline
Boolean UseSpecGloss
TextureArray SpecularMap
TextureArray GlossinessMap
TextureArray SpecularGlossinessMap
Color Specular : 1.0 1.0 1.0 1.0
Float Glossiness : 1.0
// Parallax/height map
TextureArray ParallaxMap -LINEAR
//Set to true if parallax map is stored in the alpha channel of the normal map
Boolean PackedNormalParallax
//Sets the relief height for parallax mapping
Float ParallaxHeight : 0.05
//Set to true to activate Steep Parallax mapping
Boolean SteepParallax
//Horizon fade
Boolean HorizonFade
// Set to Use Lightmap
TextureArray 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 Morph animation
FloatArray MorphWeights
Int NumberOfMorphTargets
Int NumberOfTargetsBuffers
// For instancing
Boolean UseInstancing
// For Vertex Color
Boolean UseVertexColor
Boolean BackfaceShadows : false
}
Technique {
LightMode SinglePassAndImageBased
VertexShader GLSL110 GLSL150: Common/MatDefs/Light/PBRLighting.vert
FragmentShader GLSL110 GLSL150: Common/MatDefs/Light/PBRLighting.frag
WorldParameters {
WorldViewProjectionMatrix
CameraPosition
WorldMatrix
WorldNormalMatrix
ViewProjectionMatrix
ViewMatrix
}
Defines {
HAS_COLOR_ARRAY : ColorMap
BASECOLORMAP : BaseColorMap
NORMALMAP : NormalMap
METALLICMAP : MetallicMap
ROUGHNESSMAP : RoughnessMap
EMISSIVEMAP : EmissiveMap
EMISSIVE : Emissive
SPECGLOSSPIPELINE : UseSpecGloss
PARALLAXMAP : ParallaxMap
NORMALMAP_PARALLAX : PackedNormalParallax
STEEP_PARALLAX : SteepParallax
LIGHTMAP : LightMap
SEPARATE_TEXCOORD : SeparateTexCoord
DISCARD_ALPHA : AlphaDiscardThreshold
NUM_BONES : NumberOfBones
INSTANCING : UseInstancing
USE_PACKED_MR: MetallicRoughnessMap
USE_PACKED_SG: SpecularGlossinessMap
SPECULARMAP : SpecularMap
GLOSSINESSMAP : GlossinessMap
NORMAL_TYPE: NormalType
VERTEX_COLOR : UseVertexColor
AO_MAP: LightMapAsAOMap
NUM_MORPH_TARGETS: NumberOfMorphTargets
NUM_TARGETS_BUFFERS: NumberOfTargetsBuffers
HORIZON_FADE: HorizonFade
}
}
Technique PreShadow {
VertexShader GLSL100 GLSL150 : Common/MatDefs/Shadow/PreShadow.vert
FragmentShader GLSL100 GLSL150 : Common/MatDefs/Shadow/PreShadow.frag
WorldParameters {
WorldViewProjectionMatrix
WorldViewMatrix
ViewProjectionMatrix
ViewMatrix
}
Defines {
DISCARD_ALPHA : AlphaDiscardThreshold
NUM_BONES : NumberOfBones
INSTANCING : UseInstancing
NUM_MORPH_TARGETS: NumberOfMorphTargets
NUM_TARGETS_BUFFERS: NumberOfTargetsBuffers
}
ForcedRenderState {
FaceCull Off
DepthTest On
DepthWrite On
PolyOffset 5 3
ColorWrite Off
}
}
Technique PostShadow{
VertexShader GLSL150: Common/MatDefs/Shadow/PostShadow.vert
FragmentShader GLSL150: Common/MatDefs/Shadow/PostShadow.frag
WorldParameters {
WorldViewProjectionMatrix
WorldMatrix
ViewProjectionMatrix
ViewMatrix
}
Defines {
HARDWARE_SHADOWS : HardwareShadows
FILTER_MODE : FilterMode
PCFEDGE : PCFEdge
DISCARD_ALPHA : AlphaDiscardThreshold
SHADOWMAP_SIZE : ShadowMapSize
SHADOWMAP_SIZE : ShadowMapSize
FADE : FadeInfo
PSSM : Splits
POINTLIGHT : LightViewProjectionMatrix5
NUM_BONES : NumberOfBones
INSTANCING : UseInstancing
BACKFACE_SHADOWS: BackfaceShadows
NUM_MORPH_TARGETS: NumberOfMorphTargets
NUM_TARGETS_BUFFERS: NumberOfTargetsBuffers
}
ForcedRenderState {
Blend Modulate
DepthWrite Off
PolyOffset -0.1 0
}
}
Technique PostShadow{
VertexShader GLSL100: Common/MatDefs/Shadow/PostShadow.vert
FragmentShader GLSL100: Common/MatDefs/Shadow/PostShadow.frag
WorldParameters {
WorldViewProjectionMatrix
WorldMatrix
ViewProjectionMatrix
ViewMatrix
}
Defines {
HARDWARE_SHADOWS : HardwareShadows
FILTER_MODE : FilterMode
PCFEDGE : PCFEdge
DISCARD_ALPHA : AlphaDiscardThreshold
SHADOWMAP_SIZE : ShadowMapSize
FADE : FadeInfo
PSSM : Splits
POINTLIGHT : LightViewProjectionMatrix5
NUM_BONES : NumberOfBones
INSTANCING : UseInstancing
BACKFACE_SHADOWS: BackfaceShadows
NUM_MORPH_TARGETS: NumberOfMorphTargets
NUM_TARGETS_BUFFERS: NumberOfTargetsBuffers
}
ForcedRenderState {
Blend Modulate
DepthWrite Off
PolyOffset -0.1 0
}
}
Technique PreNormalPass {
VertexShader GLSL100 : Common/MatDefs/SSAO/normal.vert
FragmentShader GLSL100 : Common/MatDefs/SSAO/normal.frag
WorldParameters {
WorldViewProjectionMatrix
WorldViewMatrix
NormalMatrix
ViewProjectionMatrix
ViewMatrix
}
Defines {
NUM_BONES : NumberOfBones
INSTANCING : UseInstancing
NUM_MORPH_TARGETS: NumberOfMorphTargets
NUM_TARGETS_BUFFERS: NumberOfTargetsBuffers
}
}
Technique Glow {
VertexShader GLSL100 GLSL150: Common/MatDefs/Misc/Unshaded.vert
FragmentShader GLSL100 GLSL150: Common/MatDefs/Light/Glow.frag
WorldParameters {
WorldViewProjectionMatrix
ViewProjectionMatrix
ViewMatrix
}
Defines {
NEED_TEXCOORD1
NUM_BONES : NumberOfBones
INSTANCING : UseInstancing
NUM_MORPH_TARGETS: NumberOfMorphTargets
NUM_TARGETS_BUFFERS: NumberOfTargetsBuffers
}
}
}
ArrayPBRLighting.vert
#import "Common/ShaderLib/GLSLCompat.glsllib"
#import "Common/ShaderLib/Instancing.glsllib"
#import "Common/ShaderLib/Skinning.glsllib"
#import "Common/ShaderLib/MorphAnim.glsllib"
uniform vec4 m_BaseColor;
uniform vec4 g_AmbientLightColor;
varying vec2 texCoord;
#if defined(HAS_COLORMAP) || (defined(HAS_LIGHTMAP) && !defined(SEPARATE_TEXCOORD))
#define NEED_TEXCOORD8
#endif
#ifdef NEED_TEXCOORD8
in vec3 inTexCoord8;
out vec3 texCoord8;
flat out float vid;
#endif
#ifdef SEPARATE_TEXCOORD
varying vec2 texCoord2;
attribute vec2 inTexCoord2;
#endif
varying vec4 Color;
attribute vec3 inPosition;
attribute vec2 inTexCoord;
attribute vec3 inNormal;
#ifdef VERTEX_COLOR
attribute vec4 inColor;
#endif
varying vec3 wNormal;
varying vec3 wPosition;
#if defined(NORMALMAP) || defined(PARALLAXMAP)
attribute vec4 inTangent;
varying vec4 wTangent;
#endif
void main(){
vec4 modelSpacePos = vec4(inPosition, 1.0);
vec3 modelSpaceNorm = inNormal;
#if ( defined(NORMALMAP) || defined(PARALLAXMAP)) && !defined(VERTEX_LIGHTING)
vec3 modelSpaceTan = inTangent.xyz;
#endif
#ifdef NEED_TEXCOORD8
texCoord8 = inTexCoord8;
vid = inTexCoord8.x;
#endif
#ifdef NUM_MORPH_TARGETS
#if defined(NORMALMAP) && !defined(VERTEX_LIGHTING)
Morph_Compute(modelSpacePos, modelSpaceNorm, modelSpaceTan);
#else
Morph_Compute(modelSpacePos, modelSpaceNorm);
#endif
#endif
#ifdef NUM_BONES
#if defined(NORMALMAP) && !defined(VERTEX_LIGHTING)
Skinning_Compute(modelSpacePos, modelSpaceNorm, modelSpaceTan);
#else
Skinning_Compute(modelSpacePos, modelSpaceNorm);
#endif
#endif
gl_Position = TransformWorldViewProjection(modelSpacePos);
texCoord = inTexCoord;
#ifdef SEPARATE_TEXCOORD
texCoord2 = inTexCoord2;
#endif
wPosition = TransformWorld(modelSpacePos).xyz;
wNormal = TransformWorldNormal(modelSpaceNorm);
#if defined(NORMALMAP) || defined(PARALLAXMAP)
wTangent = vec4(TransformWorldNormal(modelSpaceTan),inTangent.w);
#endif
Color = m_BaseColor;
#ifdef VERTEX_COLOR
Color *= inColor;
#endif
}
ArrayPBRLighting.frag
#import "Common/ShaderLib/GLSLCompat.glsllib"
#import "Common/ShaderLib/PBR.glsllib"
#import "Common/ShaderLib/Parallax.glsllib"
#import "Common/ShaderLib/Lighting.glsllib"
varying vec2 texCoord;
#ifdef SEPARATE_TEXCOORD
varying vec2 texCoord2;
#endif
#if defined(HAS_GLOWMAP) || defined(HAS_COLORMAP) || (defined(HAS_LIGHTMAP) && !defined(SEPARATE_TEXCOORD))
#define NEED_TEXCOORD8
#endif
#ifdef NEED_TEXCOORD8
in vec3 texCoord8;
flat in float vid;
#endif
varying vec4 Color;
uniform vec4 g_LightData[NB_LIGHTS];
uniform vec3 g_CameraPosition;
uniform vec4 g_AmbientLightColor;
uniform float m_Roughness;
uniform float m_Metallic;
varying vec3 wPosition;
#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 BASECOLORMAP
#if !defined(GL_EXT_texture_array)
#error Texture arrays are not supported, but required to use shader.
#endif
uniform sampler2DArray m_BaseColorMap;
#endif
#ifdef USE_PACKED_MR
uniform sampler2DArray m_MetallicRoughnessMap;
#else
#ifdef METALLICMAP
uniform sampler2DArray m_MetallicMap;
#endif
#ifdef ROUGHNESSMAP
uniform sampler2DArray m_RoughnessMap;
#endif
#endif
#ifdef EMISSIVE
uniform vec4 m_Emissive;
#endif
#ifdef EMISSIVEMAP
uniform sampler2DArray m_EmissiveMap;
#endif
#if defined(EMISSIVE) || defined(EMISSIVEMAP)
uniform float m_EmissivePower;
uniform float m_EmissiveIntensity;
#endif
#ifdef SPECGLOSSPIPELINE
uniform vec4 m_Specular;
uniform float m_Glossiness;
#ifdef USE_PACKED_SG
uniform sampler2DArray m_SpecularGlossinessMap;
#else
uniform sampler2DArray m_SpecularMap;
uniform sampler2DArray m_GlossinessMap;
#endif
#endif
#ifdef PARALLAXMAP
uniform sampler2DArray m_ParallaxMap;
#endif
#if (defined(PARALLAXMAP) || (defined(NORMALMAP_PARALLAX) && defined(NORMALMAP)))
uniform float m_ParallaxHeight;
#endif
#ifdef LIGHTMAP
uniform sampler2DArray m_LightMap;
#endif
#if defined(NORMALMAP) || defined(PARALLAXMAP)
uniform sampler2DArray m_NormalMap;
varying vec4 wTangent;
#endif
varying vec3 wNormal;
#ifdef DISCARD_ALPHA
uniform float m_AlphaDiscardThreshold;
#endif
void main(){
vec2 newTexCoord;
vec3 viewDir = normalize(g_CameraPosition - wPosition);
vec3 norm = normalize(wNormal);
#if defined(NORMALMAP) || defined(PARALLAXMAP)
vec3 tan = normalize(wTangent.xyz);
mat3 tbnMat = mat3(tan, wTangent.w * cross( (norm), (tan)), norm);
#endif
#if (defined(PARALLAXMAP) || (defined(NORMALMAP_PARALLAX) && defined(NORMALMAP)))
vec3 vViewDir = viewDir * tbnMat;
#ifdef STEEP_PARALLAX
#ifdef NORMALMAP_PARALLAX
//parallax map is stored in the alpha channel of the normal map
newTexCoord = steepParallaxOffset(texture2DArray(m_NormalMap, vid), vViewDir, texCoord, m_ParallaxHeight);
#else
//parallax map is a texture
newTexCoord = steepParallaxOffset(texture2DArray(m_ParallaxMap, vid), vViewDir, texCoord, m_ParallaxHeight);
#endif
#else
#ifdef NORMALMAP_PARALLAX
//parallax map is stored in the alpha channel of the normal map
newTexCoord = classicParallaxOffset(texture2DArray(m_NormalMap, vid), vViewDir, texCoord, m_ParallaxHeight);
#else
//parallax map is a texture
newTexCoord = classicParallaxOffset(texture2DArray(m_ParallaxMap, vid), vViewDir, texCoord, m_ParallaxHeight);
#endif
#endif
#else
newTexCoord = texCoord;
#endif
#ifdef BASECOLORMAP
vec4 albedo = texture2D(texture2DArray(m_BaseColorMap, vid), newTexCoord) * Color;
#else
vec4 albedo = Color;
#endif
#ifdef USE_PACKED_MR
vec2 rm = texture2D(texture2DArray(m_MetallicRoughnessMap, vid), newTexCoord).gb;
float Roughness = rm.x * max(m_Roughness, 1e-4);
float Metallic = rm.y * max(m_Metallic, 0.0);
#else
#ifdef ROUGHNESSMAP
float Roughness = texture2D(texture2DArray(m_RoughnessMap, vid), newTexCoord).r * max(m_Roughness, 1e-4);
#else
float Roughness = max(m_Roughness, 1e-4);
#endif
#ifdef METALLICMAP
float Metallic = texture2D(texture2DArray(m_MetallicMap, vid), newTexCoord).r * max(m_Metallic, 0.0);
#else
float Metallic = max(m_Metallic, 0.0);
#endif
#endif
float alpha = albedo.a;
#ifdef DISCARD_ALPHA
if(alpha < m_AlphaDiscardThreshold){
discard;
}
#endif
// ***********************
// Read from textures
// ***********************
#if defined(NORMALMAP)
vec4 normalHeight = texture2D(texture2DArray(m_NormalMap, vid), newTexCoord);
//Note the -2.0 and -1.0. We invert the green channel of the normal map,
//as it's complient with normal maps generated with blender.
//see http://hub.jmonkeyengine.org/forum/topic/parallax-mapping-fundamental-bug/#post-256898
//for more explanation.
vec3 normal = normalize((normalHeight.xyz * vec3(2.0, NORMAL_TYPE * 2.0, 2.0) - vec3(1.0, NORMAL_TYPE * 1.0, 1.0)));
normal = normalize(tbnMat * normal);
//normal = normalize(normal * inverse(tbnMat));
#else
vec3 normal = norm;
#endif
#ifdef SPECGLOSSPIPELINE
#ifdef USE_PACKED_SG
vec4 specularColor = texture2D(texture2DArray(m_SpecularGlossinessMap, vid), newTexCoord);
float glossiness = specularColor.a * m_Glossiness;
specularColor *= m_Specular;
#else
#ifdef SPECULARMAP
vec4 specularColor = texture2D(texture2DArray(m_SpecularMap, vid), newTexCoord);
#else
vec4 specularColor = vec4(1.0);
#endif
#ifdef GLOSSINESSMAP
float glossiness = texture2D(texture2DArray(m_GlossinessMap, vid), 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);
#ifdef LIGHTMAP
vec3 lightMapColor;
#ifdef SEPARATE_TEXCOORD
lightMapColor = texture2D(texture2DArray(m_LightMap, vid), texCoord2).rgb;
#else
lightMapColor = texture2D(texture2DArray(m_LightMap, vid), texCoord).rgb;
#endif
#ifdef AO_MAP
lightMapColor.gb = lightMapColor.rr;
ao = lightMapColor;
#else
gl_FragColor.rgb += diffuseColor.rgb * lightMapColor;
#endif
specularColor.rgb *= lightMapColor;
#endif
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
vec4 emissive = texture2D(texture2DArray(m_EmissiveMap, vid), newTexCoord);
#else
vec4 emissive = m_Emissive;
#endif
gl_FragColor += emissive * pow(emissive.a, m_EmissivePower) * m_EmissiveIntensity;
#endif
gl_FragColor.a = alpha;
}