diff --git a/.nb-gradle-properties b/.nb-gradle-properties index eba3578ee..9ca0f2c0a 100644 --- a/.nb-gradle-properties +++ b/.nb-gradle-properties @@ -6,4 +6,30 @@ jMonkeyEngine + + + run + no + + run + + + + -ea + + + + run.single + no + + ${project}:run + + + -PmainClass=${selected-class} + + + -ea + + + diff --git a/gradle.properties b/gradle.properties index 00429d65a..e3651bbe4 100644 --- a/gradle.properties +++ b/gradle.properties @@ -6,7 +6,7 @@ jmeMainVersion = 3.1 jmeVersionTag = snapshot-github # specify if JavaDoc should be built -buildJavaDoc = true +buildJavaDoc = false # specify if SDK and Native libraries get built buildSdkProject = true diff --git a/jme3-core/src/main/resources/Common/MatDefs/Light/PBRLighting.frag b/jme3-core/src/main/resources/Common/MatDefs/Light/PBRLighting.frag new file mode 100644 index 000000000..d68ec28f0 --- /dev/null +++ b/jme3-core/src/main/resources/Common/MatDefs/Light/PBRLighting.frag @@ -0,0 +1,243 @@ +#import "Common/ShaderLib/Parallax.glsllib" +#import "Common/ShaderLib/PBR.glsllib" +#import "Common/ShaderLib/Lighting.glsllib" + +varying vec2 texCoord; +#ifdef SEPARATE_TEXCOORD + varying vec2 texCoord2; +#endif + +varying vec4 Color; + +uniform vec4 g_LightData[NB_LIGHTS]; + +uniform vec3 g_CameraPosition; + +uniform float m_Roughness; +uniform float m_Metallic; + +varying vec3 wPosition; + + +#ifdef INDIRECT_LIGHTING + uniform sampler2D m_IntegrateBRDF; + uniform samplerCube m_PrefEnvMap; + uniform samplerCube m_IrradianceMap; +#endif + +#ifdef BASECOLORMAP + uniform sampler2D m_BaseColorMap; +#endif +#ifdef METALLICMAP + uniform sampler2D m_MetallicMap; +#endif +#ifdef ROUGHNESSMAP + uniform sampler2D m_RoughnessMap; +#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 PARALLAXMAP + uniform sampler2D m_ParallaxMap; +#endif +#if (defined(PARALLAXMAP) || (defined(NORMALMAP_PARALLAX) && defined(NORMALMAP))) + uniform float m_ParallaxHeight; +#endif + +#ifdef LIGHTMAP + uniform sampler2D m_LightMap; +#endif + +#ifdef NORMALMAP + uniform sampler2D m_NormalMap; + varying vec3 wTangent; + varying vec3 wBinormal; +#endif +varying vec3 wNormal; + +#ifdef DISCARD_ALPHA +uniform float m_AlphaDiscardThreshold; +#endif + +void main(){ + vec2 newTexCoord; + + #if (defined(PARALLAXMAP) || (defined(NORMALMAP_PARALLAX) && defined(NORMALMAP))) + + #ifdef STEEP_PARALLAX + #ifdef NORMALMAP_PARALLAX + //parallax map is stored in the alpha channel of the normal map + newTexCoord = steepParallaxOffset(m_NormalMap, vViewDir, texCoord, m_ParallaxHeight); + #else + //parallax map is a texture + newTexCoord = steepParallaxOffset(m_ParallaxMap, vViewDir, texCoord, m_ParallaxHeight); + #endif + #else + #ifdef NORMALMAP_PARALLAX + //parallax map is stored in the alpha channel of the normal map + newTexCoord = classicParallaxOffset(m_NormalMap, vViewDir, texCoord, m_ParallaxHeight); + #else + //parallax map is a texture + newTexCoord = classicParallaxOffset(m_ParallaxMap, vViewDir, texCoord, m_ParallaxHeight); + #endif + #endif + #else + newTexCoord = texCoord; + #endif + + #ifdef BASECOLORMAP + vec4 albedo = texture2D(m_BaseColorMap, newTexCoord); + #else + vec4 albedo = Color; + #endif + #ifdef ROUGHNESSMAP + float Roughness = texture2D(m_RoughnessMap, newTexCoord).r * max(m_Roughness,1e-8); + #else + float Roughness = max(m_Roughness,1e-8); + #endif + #ifdef METALLICMAP + float Metallic = texture2D(m_MetallicMap, newTexCoord).r; + #else + float Metallic = max(m_Metallic,0.00); + #endif + + //Roughness = max(m_Roughness,1e-8); + //Metallic = max(m_Metallic,0.00); + float alpha = Color.a * albedo.a; + + #ifdef DISCARD_ALPHA + if(alpha < m_AlphaDiscardThreshold){ + discard; + } + #endif + + // *********************** + // Read from textures + // *********************** + #if defined(NORMALMAP) + vec4 normalHeight = texture2D(m_NormalMap, 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,-2.0,2.0) - vec3(1.0,-1.0,1.0))); + #else + vec3 normal = normalize(wNormal); + #endif + + + #ifdef LIGHTMAP + vec3 lightMapColor; + #ifdef SEPARATE_TEXCOORD + lightMapColor = texture2D(m_LightMap, texCoord2).rgb; + #else + lightMapColor = texture2D(m_LightMap, texCoord).rgb; + #endif + specularColor.rgb *= lightMapColor; + albedo.rgb *= lightMapColor; + #endif + + int i = 0; + + + #ifdef NORMALMAP + mat3 tbnMat = mat3(normalize(wTangent.xyz) , normalize(wBinormal.xyz) , normalize(wNormal.xyz)); + normal = normalize(tbnMat * normal); +// normal = normalize(normal * inverse(tbnMat)); + #endif + vec3 viewDir = normalize(g_CameraPosition - wPosition); + + + float specular = 0.5; + + #ifdef SPECGLOSSPIPELINE + vec4 specularColor = texture2D(m_SpecularMap, newTexCoord); + vec4 diffuseColor = albedo; + Roughness = 1.0 - texture2D(m_GlossMap, newTexCoord); + #else + float nonMetalSpec = 0.08 * specular; + vec4 specularColor = (nonMetalSpec - nonMetalSpec * Metallic) + albedo * Metallic; + vec4 diffuseColor = albedo - albedo * Metallic; + #endif + + gl_FragColor.rgb = vec3(0.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; + + PBR_ComputeDirectLight(normal, lightDir.xyz, viewDir, + lightColor.rgb,specular, Roughness, ndotv, + directDiffuse, directSpecular); + + vec3 directLighting = diffuseColor.rgb *directDiffuse + directSpecular * specularColor.rgb; + + gl_FragColor.rgb += directLighting * fallOff; + } + + #ifdef INDIRECT_LIGHTING + vec3 rv = reflect(-viewDir.xyz, normal.xyz); + + //horizon fade from http://marmosetco.tumblr.com/post/81245981087 + float horiz = dot(rv, wNormal.xyz); + float horizFadePower= 1.0 - Roughness; + horiz = clamp( 1.0 + horizFadePower * horiz, 0.0, 1.0 ); + horiz *= horiz; + + vec3 indirectDiffuse = vec3(0.0); + vec3 indirectSpecular = vec3(0.0); + indirectDiffuse = textureCube(m_IrradianceMap, rv.xyz).rgb * albedo.rgb; + + indirectSpecular = ApproximateSpecularIBL(m_PrefEnvMap,m_IntegrateBRDF, specularColor.rgb, Roughness, ndotv, rv.xyz); + indirectSpecular *= vec3(horiz); + + vec3 indirectLighting = indirectDiffuse + indirectSpecular; + + gl_FragColor.rgb = gl_FragColor.rgb + indirectLighting ; + #endif + + #if defined(EMISSIVE) || defined (EMISSIVEMAP) + #ifdef EMISSIVEMAP + vec4 emissive = texture2D(m_EmissiveMap, newTexCoord); + #else + vec4 emissive = m_Emissive; + #endif + gl_FragColor += emissive * pow(emissive.a, m_EmissivePower) * m_EmissiveIntensity; + #endif + + gl_FragColor.a = alpha; + +} diff --git a/jme3-core/src/main/resources/Common/MatDefs/Light/PBRLighting.j3md b/jme3-core/src/main/resources/Common/MatDefs/Light/PBRLighting.j3md new file mode 100644 index 000000000..f2d89cf51 --- /dev/null +++ b/jme3-core/src/main/resources/Common/MatDefs/Light/PBRLighting.j3md @@ -0,0 +1,305 @@ +MaterialDef PBR Lighting { + + MaterialParameters { + + // Alpha threshold for fragment discarding + Float AlphaDiscardThreshold (AlphaTestFallOff) + + //metalness of the material + Float Metallic : 0.0 + //Roughness of the material + Float Roughness : 1.0 + // Base material color + Color BaseColor + // The emissive color of the object + Color Emissive + // the emissive power + Float EmissivePower : 3.0 + // the emissive intensity + Float EmissiveIntensity : 1.0 + + // BaseColor map + Texture2D BaseColorMap + + // Specular/gloss map + Texture2D MetallicMap -LINEAR + + // Roughness Map + Texture2D RoughnessMap -LINEAR + + // Texture of the emissive parts of the material + Texture2D EmissiveMap + + // Normal map + Texture2D NormalMap -LINEAR + + // For Spec gloss pipeline + Texture2D SpecularMap + Texture2D GlossMap + + // 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 + + //Sets the relief height for parallax mapping + Float ParallaxHeight : 0.05 + + //Set to true to activate Steep Parallax mapping + Boolean SteepParallax + + // Set to Use Lightmap + Texture2D LightMap + + // Set to use TexCoord2 for the lightmap sampling + Boolean SeparateTexCoord + + //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 + } + + Technique { + LightMode SinglePass + + VertexShader GLSL100: Common/MatDefs/Light/PBRLighting.vert + FragmentShader GLSL100: Common/MatDefs/Light/PBRLighting.frag + + WorldParameters { + WorldViewProjectionMatrix + CameraPosition + WorldMatrix + } + + Defines { + BASECOLORMAP : BaseColorMap + NORMALMAP : NormalMap + METALLICMAP : MetallicMap + ROUGHNESSMAP : RoughnessMap + EMISSIVEMAP : EmissiveMap + EMISSIVE : Emissive + SPECGLOSSPIPELINE : SpecularMap + PARALLAXMAP : ParallaxMap + NORMALMAP_PARALLAX : PackedNormalParallax + STEEP_PARALLAX : SteepParallax + LIGHTMAP : LightMap + SEPARATE_TEXCOORD : SeparateTexCoord + DISCARD_ALPHA : AlphaDiscardThreshold + NUM_BONES : NumberOfBones + INSTANCING : UseInstancing + INDIRECT_LIGHTING : IntegrateBRDF + VERTEX_COLOR : UseVertexColor + } + } + + + + Technique PreShadow { + + VertexShader GLSL100 : Common/MatDefs/Shadow/PreShadow.vert + FragmentShader GLSL100 : Common/MatDefs/Shadow/PreShadow.frag + + WorldParameters { + WorldViewProjectionMatrix + WorldViewMatrix + ViewProjectionMatrix + ViewMatrix + } + + Defines { + COLOR_MAP : ColorMap + DISCARD_ALPHA : AlphaDiscardThreshold + NUM_BONES : NumberOfBones + INSTANCING : UseInstancing + } + + ForcedRenderState { + FaceCull Off + DepthTest On + DepthWrite On + PolyOffset 5 3 + ColorWrite Off + } + + } + + + Technique PostShadow15{ + VertexShader GLSL150: Common/MatDefs/Shadow/PostShadow15.vert + FragmentShader GLSL150: Common/MatDefs/Shadow/PostShadow15.frag + + WorldParameters { + WorldViewProjectionMatrix + WorldMatrix + ViewProjectionMatrix + ViewMatrix + } + + Defines { + HARDWARE_SHADOWS : HardwareShadows + FILTER_MODE : FilterMode + PCFEDGE : PCFEdge + DISCARD_ALPHA : AlphaDiscardThreshold + COLOR_MAP : ColorMap + SHADOWMAP_SIZE : ShadowMapSize + FADE : FadeInfo + PSSM : Splits + POINTLIGHT : LightViewProjectionMatrix5 + NUM_BONES : NumberOfBones + INSTANCING : UseInstancing + } + + 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 + COLOR_MAP : ColorMap + SHADOWMAP_SIZE : ShadowMapSize + FADE : FadeInfo + PSSM : Splits + POINTLIGHT : LightViewProjectionMatrix5 + NUM_BONES : NumberOfBones + INSTANCING : UseInstancing + } + + 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 { + DIFFUSEMAP_ALPHA : DiffuseMap + NUM_BONES : NumberOfBones + INSTANCING : UseInstancing + } + + } + + + Technique PreNormalPassDerivative { + + VertexShader GLSL100 : Common/MatDefs/MSSAO/normal.vert + FragmentShader GLSL100 : Common/MatDefs/MSSAO/normal.frag + + WorldParameters { + WorldViewProjectionMatrix + WorldViewMatrix + NormalMatrix + ViewProjectionMatrix + ViewMatrix + } + + Defines { + DIFFUSEMAP_ALPHA : DiffuseMap + NUM_BONES : NumberOfBones + INSTANCING : UseInstancing + } + + } + + Technique GBuf { + + VertexShader GLSL100: Common/MatDefs/Light/GBuf.vert + FragmentShader GLSL100: Common/MatDefs/Light/GBuf.frag + + WorldParameters { + WorldViewProjectionMatrix + NormalMatrix + WorldViewMatrix + WorldMatrix + } + + Defines { + VERTEX_COLOR : UseVertexColor + MATERIAL_COLORS : UseMaterialColors + V_TANGENT : VTangent + MINNAERT : Minnaert + WARDISO : WardIso + + DIFFUSEMAP : DiffuseMap + NORMALMAP : NormalMap + SPECULARMAP : SpecularMap + PARALLAXMAP : ParallaxMap + } + } + +} diff --git a/jme3-core/src/main/resources/Common/MatDefs/Light/PBRLighting.vert b/jme3-core/src/main/resources/Common/MatDefs/Light/PBRLighting.vert new file mode 100644 index 000000000..434d82e1d --- /dev/null +++ b/jme3-core/src/main/resources/Common/MatDefs/Light/PBRLighting.vert @@ -0,0 +1,67 @@ +#import "Common/ShaderLib/Instancing.glsllib" +#import "Common/ShaderLib/Skinning.glsllib" + +uniform vec4 m_BaseColor; + +uniform vec4 g_AmbientLightColor; +varying vec2 texCoord; + +#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; +#ifdef NORMALMAP + attribute vec4 inTangent; + varying vec3 wTangent; + varying vec3 wBinormal; +#endif + +void main(){ + vec4 modelSpacePos = vec4(inPosition, 1.0); + vec3 modelSpaceNorm = inNormal; + + #if defined(NORMALMAP) && !defined(VERTEX_LIGHTING) + vec3 modelSpaceTan = inTangent.xyz; + #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 = TransformWorld(vec4(modelSpaceNorm,0.0)).xyz; + + #if defined(NORMALMAP) + wTangent = TransformWorld(vec4(modelSpaceTan,0.0)).xyz; + wBinormal = cross(wNormal, wTangent)* inTangent.w; + #endif + + Color = m_BaseColor; + + #ifdef VERTEX_COLOR + Color *= inColor; + #endif +} \ No newline at end of file diff --git a/jme3-core/src/main/resources/Common/ShaderLib/PBR.glsllib b/jme3-core/src/main/resources/Common/ShaderLib/PBR.glsllib new file mode 100644 index 000000000..ebb11ac76 --- /dev/null +++ b/jme3-core/src/main/resources/Common/ShaderLib/PBR.glsllib @@ -0,0 +1,120 @@ + +#ifndef PI + #define PI 3.14159265358979323846264 +#endif + +//Specular fresnel computation +vec3 F_Shlick(float vh, vec3 F0){ + float fresnelFact = pow(2.0, (-5.55473*vh - 6.98316) * vh); + return mix(F0, vec3(1.0, 1.0, 1.0), fresnelFact); +} + +void PBR_ComputeDirectLightSpecWF(vec3 normal, vec3 lightDir, vec3 viewDir, + vec3 lightColor, vec3 specColor, float roughness, float ndotv, + out vec3 outDiffuse, out vec3 outSpecular){ + // Compute halfway vector. + vec3 halfVec = normalize(lightDir + viewDir); + + // Compute ndotl, ndoth, vdoth terms which are needed later. + float ndotl = max( dot(normal, lightDir), 0.0); + float ndoth = max( dot(normal, halfVec), 0.0); + float hdotv = max( dot(viewDir, halfVec), 0.0); + + // Compute diffuse using energy-conserving Lambert. + // Alternatively, use Oren-Nayar for really rough + // materials or if you have lots of processing power ... + outDiffuse = vec3(ndotl) * lightColor; + + //cook-torrence, microfacet BRDF : http://blog.selfshadow.com/publications/s2013-shading-course/karis/s2013_pbs_epic_notes_v2.pdf + + float alpha = roughness * roughness; + + //D, GGX normaal Distribution function + float alpha2 = alpha * alpha; + float sum = ((ndoth * ndoth) * (alpha2 - 1.0) + 1.0); + float denom = PI * sum * sum; + float D = alpha2 / denom; + + // Compute Fresnel function via Schlick's approximation. + vec3 fresnel = F_Shlick(hdotv, specColor); + + //G Shchlick GGX Gometry shadowing term, k = alpha/2 + float k = alpha * 0.5; + + // UE4 way to optimise shlick GGX Gometry shadowing term + //http://graphicrants.blogspot.co.uk/2013/08/specular-brdf-reference.html + float G_V = ndotv + sqrt( (ndotv - ndotv * k) * ndotv + k ); + float G_L = ndotl + sqrt( (ndotl - ndotl * k) * ndotl + k ); + // the max here is to avoid division by 0 that may cause some small glitches. + float G = 1.0/max( G_V * G_L ,0.01); + + float specular = D * G * ndotl; + + outSpecular = fresnel * vec3(specular) * lightColor; +} + +void PBR_ComputeDirectLight(vec3 normal, vec3 lightDir, vec3 viewDir, + vec3 lightColor, float fZero, float roughness, float ndotv, + out vec3 outDiffuse, out vec3 outSpecular){ + // Compute halfway vector. + vec3 halfVec = normalize(lightDir + viewDir); + + // Compute ndotl, ndoth, vdoth terms which are needed later. + float ndotl = max( dot(normal, lightDir), 0.0); + float ndoth = max( dot(normal, halfVec), 0.0); + float hdotv = max( dot(viewDir, halfVec), 0.0); + + // Compute diffuse using energy-conserving Lambert. + // Alternatively, use Oren-Nayar for really rough + // materials or if you have lots of processing power ... + outDiffuse = vec3(ndotl) * lightColor; + + //cook-torrence, microfacet BRDF : http://blog.selfshadow.com/publications/s2013-shading-course/karis/s2013_pbs_epic_notes_v2.pdf + + float alpha = roughness * roughness; + + //D, GGX normaal Distribution function + float alpha2 = alpha * alpha; + float sum = ((ndoth * ndoth) * (alpha2 - 1.0) + 1.0); + float denom = PI * sum * sum; + float D = alpha2 / denom; + + // Compute Fresnel function via Schlick's approximation. + float fresnel = fZero + ( 1.0 - fZero ) * pow( 1.0 - hdotv, 5.0 ); + + //G Shchlick GGX Gometry shadowing term, k = alpha/2 + float k = alpha * 0.5; + + /* + //classic Schlick ggx + float G_V = ndotv / (ndotv * (1.0 - k) + k); + float G_L = ndotl / (ndotl * (1.0 - k) + k); + float G = ( G_V * G_L ); + + float specular =(D* fresnel * G) /(4 * ndotv); + */ + + // UE4 way to optimise shlick GGX Gometry shadowing term + //http://graphicrants.blogspot.co.uk/2013/08/specular-brdf-reference.html + float G_V = ndotv + sqrt( (ndotv - ndotv * k) * ndotv + k ); + float G_L = ndotl + sqrt( (ndotl - ndotl * k) * ndotl + k ); + // the max here is to avoid division by 0 that may cause some small glitches. + float G = 1.0/max( G_V * G_L ,0.01); + + float specular = D * fresnel * G * ndotl; + + outSpecular = vec3(specular) * lightColor; +} + + +vec3 ApproximateSpecularIBL(samplerCube envMap,sampler2D integrateBRDF, vec3 SpecularColor , float Roughness, float ndotv, vec3 refVec){ + //TODO magic values should be replaced by defines. + float Lod = log2(Roughness) * 1.2 + 6.0 - 1.0; + vec3 PrefilteredColor = textureCube(envMap, refVec.xyz,Lod).rgb; + vec2 EnvBRDF = texture2D(integrateBRDF,vec2(Roughness, ndotv)).rg; + return PrefilteredColor * ( SpecularColor * EnvBRDF.x+ EnvBRDF.y ); +} + + + + diff --git a/jme3-core/src/main/resources/Common/Textures/integrateBRDF.ktx b/jme3-core/src/main/resources/Common/Textures/integrateBRDF.ktx new file mode 100644 index 000000000..2fc2e4690 Binary files /dev/null and b/jme3-core/src/main/resources/Common/Textures/integrateBRDF.ktx differ diff --git a/jme3-core/src/plugins/java/com/jme3/texture/plugins/DDSLoader.java b/jme3-core/src/plugins/java/com/jme3/texture/plugins/DDSLoader.java index e7ef0bcd9..245591c05 100644 --- a/jme3-core/src/plugins/java/com/jme3/texture/plugins/DDSLoader.java +++ b/jme3-core/src/plugins/java/com/jme3/texture/plugins/DDSLoader.java @@ -296,6 +296,12 @@ public class DDSLoader implements AssetLoader { // exit here, the rest of the structure is not valid // the real format will be available in the DX10 header return; + + case 113: + compressed = false; + bpp = 64; + pixelFormat = Image.Format.RGBA16F; + break; default: throw new IOException("Unknown fourcc: " + string(fourcc) + ", " + Integer.toHexString(fourcc)); } diff --git a/jme3-examples/src/main/java/jme3test/batching/TestBatchNodeCluster.java b/jme3-examples/src/main/java/jme3test/batching/TestBatchNodeCluster.java index 4559acfdc..9006f199d 100644 --- a/jme3-examples/src/main/java/jme3test/batching/TestBatchNodeCluster.java +++ b/jme3-examples/src/main/java/jme3test/batching/TestBatchNodeCluster.java @@ -60,7 +60,7 @@ public class TestBatchNodeCluster extends SimpleApplication { settingst.setVSync(false); settingst.setFullscreen(false); app.setSettings(settingst); - app.setShowSettings(false); + app.setShowSettings(false); app.start(); } private ActionListener al = new ActionListener() { diff --git a/jme3-examples/src/main/java/jme3test/light/TestShadowBug.java b/jme3-examples/src/main/java/jme3test/light/TestShadowBug.java new file mode 100644 index 000000000..cecb53224 --- /dev/null +++ b/jme3-examples/src/main/java/jme3test/light/TestShadowBug.java @@ -0,0 +1,131 @@ +/* + * Copyright (c) 2009-2015 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package jme3test.light; + + +import com.jme3.app.SimpleApplication; +import com.jme3.light.DirectionalLight; +import com.jme3.light.PointLight; +import com.jme3.light.SpotLight; +import com.jme3.material.Material; +import com.jme3.math.ColorRGBA; +import com.jme3.math.FastMath; +import com.jme3.math.Quaternion; +import com.jme3.math.Vector2f; +import com.jme3.math.Vector3f; +import com.jme3.renderer.queue.RenderQueue.ShadowMode; +import com.jme3.scene.Geometry; +import com.jme3.scene.Node; +import com.jme3.scene.Spatial; +import com.jme3.scene.shape.Box; +import com.jme3.shadow.EdgeFilteringMode; +import com.jme3.shadow.PointLightShadowRenderer; +import com.jme3.shadow.SpotLightShadowRenderer; +import com.jme3.texture.Texture; +import com.jme3.texture.Texture.WrapMode; + + +public class TestShadowBug extends SimpleApplication { + public static void main(String[] args) { + TestShadowBug app = new TestShadowBug(); + app.start(); + } + + @Override + public void simpleInitApp() { + flyCam.setMoveSpeed(100f); + rootNode.attachChild(makeFloor()); + + Node characters = new Node("Characters"); + characters.setShadowMode(ShadowMode.Cast); + rootNode.attachChild(characters); + + Spatial golem = assetManager.loadModel("Models/Oto/Oto.mesh.xml"); + golem.scale(0.5f); + golem.setLocalTranslation(200.0f, -6f, 200f); + golem.setShadowMode(ShadowMode.CastAndReceive); + characters.attachChild(golem); + + DirectionalLight sun = new DirectionalLight(); + sun.setDirection(new Vector3f(-1f, -1f, 1f)); + sun.setColor(ColorRGBA.White.mult(1.3f)); + rootNode.addLight(sun); + characters.addLight(sun); + + SpotLight spot = new SpotLight(); + spot.setSpotRange(13f); // distance + spot.setSpotInnerAngle(15f * FastMath.DEG_TO_RAD); // inner light cone (central beam) + spot.setSpotOuterAngle(20f * FastMath.DEG_TO_RAD); // outer light cone (edge of the light) + spot.setColor(ColorRGBA.White.mult(1.3f)); // light color + spot.setPosition(new Vector3f(192.0f, -1f, 192f)); + spot.setDirection(new Vector3f(1, -0.5f, 1)); + rootNode.addLight(spot); + + PointLight lamp_light = new PointLight(); + lamp_light.setColor(ColorRGBA.Yellow); + lamp_light.setRadius(20f); + lamp_light.setPosition(new Vector3f(210.0f, 0f, 210f)); + rootNode.addLight(lamp_light); + + SpotLightShadowRenderer slsr = new SpotLightShadowRenderer(assetManager, 512); + slsr.setLight(spot); + slsr.setEdgeFilteringMode(EdgeFilteringMode.Nearest); + slsr.setShadowIntensity(0.6f); + slsr.setFlushQueues(false); + viewPort.addProcessor(slsr); + + PointLightShadowRenderer plsr = new PointLightShadowRenderer(assetManager, 512); + plsr.setLight(lamp_light); + plsr.setShadowIntensity(0.6f); + plsr.setEdgeFilteringMode(EdgeFilteringMode.Nearest); + plsr.setFlushQueues(false); + viewPort.addProcessor(plsr); + + viewPort.getCamera().setLocation(new Vector3f(192.0f, 10f, 192f)); + float[] angles = new float[]{3.14f/2, 3.14f/2, 0}; + viewPort.getCamera().setRotation(new Quaternion(angles)); + } + + protected Geometry makeFloor() { + Box box = new Box(220, .2f, 220); + box.scaleTextureCoordinates(new Vector2f(10, 10)); + Geometry floor = new Geometry("the Floor", box); + floor.setLocalTranslation(200, -9, 200); + Material matGroundL = new Material(assetManager, "Common/MatDefs/Light/Lighting.j3md"); + Texture grass = assetManager.loadTexture("Textures/Terrain/splat/grass.jpg"); + grass.setWrap(WrapMode.Repeat); + matGroundL.setTexture("DiffuseMap", grass); + floor.setMaterial(matGroundL); + floor.setShadowMode(ShadowMode.CastAndReceive); + return floor; + } +} \ No newline at end of file diff --git a/jme3-examples/src/main/java/jme3test/light/pbr/TestPBRLighting.java b/jme3-examples/src/main/java/jme3test/light/pbr/TestPBRLighting.java new file mode 100644 index 000000000..4c4095f6d --- /dev/null +++ b/jme3-examples/src/main/java/jme3test/light/pbr/TestPBRLighting.java @@ -0,0 +1,172 @@ +package jme3test.light.pbr; + +import com.jme3.app.SimpleApplication; +import com.jme3.input.ChaseCamera; +import com.jme3.input.KeyInput; +import com.jme3.input.controls.ActionListener; +import com.jme3.input.controls.KeyTrigger; +import com.jme3.light.DirectionalLight; +import com.jme3.material.Material; +import com.jme3.math.ColorRGBA; +import com.jme3.math.FastMath; +import com.jme3.math.Vector3f; +import com.jme3.post.FilterPostProcessor; +import com.jme3.post.filters.FXAAFilter; +import com.jme3.post.filters.ToneMapFilter; +import com.jme3.scene.Geometry; +import com.jme3.scene.Node; +import com.jme3.scene.Spatial; +import com.jme3.texture.pbr.EnvironmentCamera; +import com.jme3.texture.plugins.ktx.KTXLoader; +import com.jme3.util.SkyFactory; + +/** + * A test case for PBR lighting. + * Still experimental. + * + * @author nehon + */ +public class TestPBRLighting extends SimpleApplication { + + public static void main(String[] args) { + TestPBRLighting app = new TestPBRLighting(); + app.start(); + } + private Geometry model; + private DirectionalLight dl; + private Node modelNode; + private int frame = 0; + private boolean indirectLighting = true; + private Material pbrMat; + private Material adHocMat; + + @Override + public void simpleInitApp() { + assetManager.registerLoader(KTXLoader.class, "ktx"); + + viewPort.setBackgroundColor(ColorRGBA.White); + modelNode = (Node) new Node("modelNode"); + model = (Geometry) assetManager.loadModel("Models/Tank/tank.j3o"); + modelNode.attachChild(model); + + dl = new DirectionalLight(); + dl.setDirection(new Vector3f(-1, -1, -1).normalizeLocal()); + rootNode.addLight(dl); + dl.setColor(ColorRGBA.White); + rootNode.attachChild(modelNode); + + final EnvironmentCamera envCam = new EnvironmentCamera(128, new Vector3f(0, 3f, 0)); + stateManager.attach(envCam); + FilterPostProcessor fpp = new FilterPostProcessor(assetManager); + fpp.addFilter(new FXAAFilter()); + fpp.addFilter(new ToneMapFilter(Vector3f.UNIT_XYZ.mult(2.0f))); + viewPort.addProcessor(fpp); + + //Spatial sky = SkyFactory.createSky(assetManager, "Textures/Sky/Sky_Cloudy.hdr", SkyFactory.EnvMapType.EquirectMap); + Spatial sky = SkyFactory.createSky(assetManager, "Textures/Sky/Path.hdr", SkyFactory.EnvMapType.EquirectMap); + //Spatial sky = SkyFactory.createSky(assetManager, "Textures/Sky/Stonewall.hdr", SkyFactory.EnvMapType.EquirectMap); + //Spatial sky = SkyFactory.createSky(assetManager, "Textures/Sky/road.hdr", SkyFactory.EnvMapType.EquirectMap); + rootNode.attachChild(sky); + + pbrMat = assetManager.loadMaterial("Models/Tank/tank.j3m"); + model.setMaterial(pbrMat); + + ChaseCamera chaser = new ChaseCamera(cam, modelNode, inputManager); + chaser.setDragToRotate(true); + chaser.setMinVerticalRotation(-FastMath.HALF_PI); + chaser.setMaxDistance(1000); + chaser.setSmoothMotion(true); + chaser.setRotationSensitivity(10); + chaser.setZoomSensitivity(5); + flyCam.setEnabled(false); + //flyCam.setMoveSpeed(100); + + inputManager.addListener(new ActionListener() { + @Override + public void onAction(String name, boolean isPressed, float tpf) { + if (name.equals("toggle") && isPressed) { + if (!indirectLighting) { + toggleIBL(); + + } else { + pbrMat.clearParam("IntegrateBRDF"); + indirectLighting = false; + } + } + + if (name.equals("switchMats") && isPressed) { + if (model.getMaterial() == pbrMat) { + model.setMaterial(adHocMat); + } else { + model.setMaterial(pbrMat); + } + } + + if (name.equals("debug") && isPressed) { + envCam.toggleDebug(); + } + + if (name.equals("up") && isPressed) { + model.move(0, tpf * 100f, 0); + } + + if (name.equals("down") && isPressed) { + model.move(0, -tpf * 100f, 0); + } + if (name.equals("left") && isPressed) { + model.move(0, 0, tpf * 100f); + } + if (name.equals("right") && isPressed) { + model.move(0, 0, -tpf * 100f); + } + if (name.equals("light") && isPressed) { + dl.setDirection(cam.getDirection().normalize()); + } + } + }, "toggle", "light", "up", "down", "left", "right", "debug"); + + inputManager.addMapping("toggle", new KeyTrigger(KeyInput.KEY_RETURN)); + inputManager.addMapping("light", new KeyTrigger(KeyInput.KEY_F)); + inputManager.addMapping("up", new KeyTrigger(KeyInput.KEY_UP)); + inputManager.addMapping("down", new KeyTrigger(KeyInput.KEY_DOWN)); + inputManager.addMapping("left", new KeyTrigger(KeyInput.KEY_LEFT)); + inputManager.addMapping("right", new KeyTrigger(KeyInput.KEY_RIGHT)); + inputManager.addMapping("debug", new KeyTrigger(KeyInput.KEY_D)); + + } + + private void toggleIBL() { + ensurePbrMat(); + pbrMat.setTexture("IrradianceMap", stateManager.getState(EnvironmentCamera.class).getIrradianceMap()); + pbrMat.setTexture("PrefEnvMap", stateManager.getState(EnvironmentCamera.class).getPrefilteredEnvMap()); + pbrMat.setTexture("IntegrateBRDF", assetManager.loadTexture("Common/Textures/integrateBRDF.ktx")); + indirectLighting = true; + } + + private void ensurePbrMat() { + if (model.getMaterial() != pbrMat && model.getMaterial() != adHocMat) { + pbrMat = model.getMaterial(); + } + } + + @Override + public void simpleUpdate(float tpf) { + frame++; + + if (frame == 2) { + modelNode.removeFromParent(); + stateManager.getState(EnvironmentCamera.class).snapshot(rootNode, new Runnable() { + + //this code is ensured to be called in the update loop, the run method is called by the EnvCamera app state in it's update cycle + @Override + public void run() { + toggleIBL(); + } + }); + } + if (frame > 2 && modelNode.getParent() == null) { + rootNode.attachChild(modelNode); + } + } + +} diff --git a/jme3-testdata/src/main/resources/Models/Tank/Tank_Base_Color.png b/jme3-testdata/src/main/resources/Models/Tank/Tank_Base_Color.png new file mode 100644 index 000000000..c021d42f2 Binary files /dev/null and b/jme3-testdata/src/main/resources/Models/Tank/Tank_Base_Color.png differ diff --git a/jme3-testdata/src/main/resources/Models/Tank/Tank_Emissive.png b/jme3-testdata/src/main/resources/Models/Tank/Tank_Emissive.png new file mode 100644 index 000000000..7d7c3e45b Binary files /dev/null and b/jme3-testdata/src/main/resources/Models/Tank/Tank_Emissive.png differ diff --git a/jme3-testdata/src/main/resources/Models/Tank/Tank_Metallic.png b/jme3-testdata/src/main/resources/Models/Tank/Tank_Metallic.png new file mode 100644 index 000000000..de7da8ba2 Binary files /dev/null and b/jme3-testdata/src/main/resources/Models/Tank/Tank_Metallic.png differ diff --git a/jme3-testdata/src/main/resources/Models/Tank/Tank_Normal.png b/jme3-testdata/src/main/resources/Models/Tank/Tank_Normal.png new file mode 100644 index 000000000..3bb1a2620 Binary files /dev/null and b/jme3-testdata/src/main/resources/Models/Tank/Tank_Normal.png differ diff --git a/jme3-testdata/src/main/resources/Models/Tank/Tank_Roughness.png b/jme3-testdata/src/main/resources/Models/Tank/Tank_Roughness.png new file mode 100644 index 000000000..2717275c3 Binary files /dev/null and b/jme3-testdata/src/main/resources/Models/Tank/Tank_Roughness.png differ diff --git a/jme3-testdata/src/main/resources/Models/Tank/tank.j3m b/jme3-testdata/src/main/resources/Models/Tank/tank.j3m new file mode 100644 index 000000000..0bd16814e --- /dev/null +++ b/jme3-testdata/src/main/resources/Models/Tank/tank.j3m @@ -0,0 +1,14 @@ +Material Tank : Common/MatDefs/Light/PBRLighting.j3md { + MaterialParameters { + + MetallicMap : Flip Models/Tank/Tank_Metallic.png + RoughnessMap : Flip Models/Tank/Tank_Roughness.png + NormalMap : Flip Models/Tank/Tank_Normal.png + BaseColorMap : Flip Models/Tank/Tank_Base_Color.png + EmissiveMap : Flip Models/Tank/Tank_Emissive.png + EmissiveIntensity : 2.0 + + } + AdditionalRenderState { + } +} diff --git a/jme3-testdata/src/main/resources/Models/Tank/tank.j3o b/jme3-testdata/src/main/resources/Models/Tank/tank.j3o new file mode 100644 index 000000000..a0d007426 Binary files /dev/null and b/jme3-testdata/src/main/resources/Models/Tank/tank.j3o differ diff --git a/jme3-testdata/src/main/resources/Models/Tank/tank.j3odata b/jme3-testdata/src/main/resources/Models/Tank/tank.j3odata new file mode 100644 index 000000000..9e0f13099 --- /dev/null +++ b/jme3-testdata/src/main/resources/Models/Tank/tank.j3odata @@ -0,0 +1,3 @@ +# +#Sat Apr 11 15:27:27 CEST 2015 +ORIGINAL_PATH=Models/Tank/tank.obj diff --git a/jme3-testdata/src/main/resources/Textures/Sky/Path.hdr b/jme3-testdata/src/main/resources/Textures/Sky/Path.hdr new file mode 100644 index 000000000..69b878681 Binary files /dev/null and b/jme3-testdata/src/main/resources/Textures/Sky/Path.hdr differ