Am Lightning System gearbeitet
This commit is contained in:
336
Common/MatDefs/Light/PBRLighting.j3md
Normal file
336
Common/MatDefs/Light/PBRLighting.j3md
Normal file
@@ -0,0 +1,336 @@
|
|||||||
|
MaterialDef PBR Lighting {
|
||||||
|
|
||||||
|
MaterialParameters {
|
||||||
|
Int BoundDrawBuffer
|
||||||
|
|
||||||
|
// Alpha threshold for fragment discarding
|
||||||
|
Float AlphaDiscardThreshold (AlphaTestFallOff)
|
||||||
|
|
||||||
|
//metallicity 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
|
||||||
|
Texture2D BaseColorMap
|
||||||
|
|
||||||
|
// Metallic map
|
||||||
|
Texture2D MetallicMap -LINEAR
|
||||||
|
|
||||||
|
// Roughness Map
|
||||||
|
Texture2D RoughnessMap -LINEAR
|
||||||
|
|
||||||
|
//Metallic and Roughness are packed respectively in the b and g channel of a single map
|
||||||
|
// r: AO (if AoPackedInMRMap is true)
|
||||||
|
// g: Roughness
|
||||||
|
// b: Metallic
|
||||||
|
Texture2D MetallicRoughnessMap -LINEAR
|
||||||
|
|
||||||
|
// Texture of the emissive parts of the material
|
||||||
|
Texture2D EmissiveMap
|
||||||
|
|
||||||
|
// Normal map
|
||||||
|
Texture2D NormalMap -LINEAR
|
||||||
|
// The scalar parameter applied to each normal vector of the normal map
|
||||||
|
Float NormalScale
|
||||||
|
|
||||||
|
//The type of normal map: -1.0 (DirectX), 1.0 (OpenGl)
|
||||||
|
Float NormalType : -1.0
|
||||||
|
|
||||||
|
// 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
|
||||||
|
|
||||||
|
// Parallax/height map
|
||||||
|
Texture2D ParallaxMap -LINEAR
|
||||||
|
|
||||||
|
// Specular-AA
|
||||||
|
Boolean UseSpecularAA : true
|
||||||
|
// screen space variance,Use the slider to set the strength of the geometric specular anti-aliasing effect between 0 and 1. Higher values produce a blurrier result with less aliasing.
|
||||||
|
Float SpecularAASigma
|
||||||
|
// clamping threshold,Use the slider to set a maximum value for the offset that HDRP subtracts from the smoothness value to reduce artifacts.
|
||||||
|
Float SpecularAAKappa
|
||||||
|
|
||||||
|
//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
|
||||||
|
Texture2D LightMap
|
||||||
|
|
||||||
|
// A scalar multiplier controlling the amount of occlusion applied.
|
||||||
|
// A value of `0.0` means no occlusion. A value of `1.0` means full occlusion.
|
||||||
|
Float AoStrength
|
||||||
|
|
||||||
|
// Set to use TexCoord2 for the lightmap sampling
|
||||||
|
Boolean SeparateTexCoord
|
||||||
|
// the light map is a grayscale ao map, only the r channel will be read.
|
||||||
|
Boolean LightMapAsAOMap
|
||||||
|
Boolean AoPackedInMRMap
|
||||||
|
//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
|
||||||
|
|
||||||
|
Boolean UseFog
|
||||||
|
Color FogColor
|
||||||
|
Vector2 LinearFog
|
||||||
|
Float ExpFog
|
||||||
|
Float ExpSqFog
|
||||||
|
|
||||||
|
Texture2D SunLightExposureMap
|
||||||
|
Boolean UseVertexColorsAsSunIntensity
|
||||||
|
Float StaticSunIntensity
|
||||||
|
Boolean BrightenIndoorShadows //should be set true when shadows are enabled, in order to prevent areas with low SunExposure from being way too dark when shadows are cast
|
||||||
|
|
||||||
|
// debug the final value of the selected layer as a color output
|
||||||
|
Int DebugValuesMode
|
||||||
|
// Layers:
|
||||||
|
// 0 - albedo (unshaded)
|
||||||
|
// 1 - normals
|
||||||
|
// 2 - roughness
|
||||||
|
// 3 - metallic
|
||||||
|
// 4 - ao
|
||||||
|
// 5 - emissive
|
||||||
|
// 6 - exposure
|
||||||
|
// 7 - alpha
|
||||||
|
// 8 - geometryNormals
|
||||||
|
}
|
||||||
|
|
||||||
|
Technique {
|
||||||
|
LightMode SinglePassAndImageBased
|
||||||
|
|
||||||
|
VertexShader GLSL300 GLSL150 GLSL110: Common/MatDefs/Light/PBRLighting.vert
|
||||||
|
FragmentShader GLSL300 GLSL150 GLSL110: Common/MatDefs/Light/PBRLighting.frag
|
||||||
|
|
||||||
|
WorldParameters {
|
||||||
|
WorldViewProjectionMatrix
|
||||||
|
CameraPosition
|
||||||
|
WorldMatrix
|
||||||
|
WorldNormalMatrix
|
||||||
|
ViewProjectionMatrix
|
||||||
|
ViewMatrix
|
||||||
|
}
|
||||||
|
|
||||||
|
Defines {
|
||||||
|
BOUND_DRAW_BUFFER: BoundDrawBuffer
|
||||||
|
BASECOLORMAP : BaseColorMap
|
||||||
|
NORMALMAP : NormalMap
|
||||||
|
NORMALSCALE : NormalScale
|
||||||
|
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
|
||||||
|
SPECULAR_AA : UseSpecularAA
|
||||||
|
SPECULAR_AA_SCREEN_SPACE_VARIANCE : SpecularAASigma
|
||||||
|
SPECULAR_AA_THRESHOLD : SpecularAAKappa
|
||||||
|
GLOSSINESSMAP : GlossinessMap
|
||||||
|
NORMAL_TYPE: NormalType
|
||||||
|
VERTEX_COLOR : UseVertexColor
|
||||||
|
AO_MAP: LightMapAsAOMap
|
||||||
|
AO_PACKED_IN_MR_MAP : AoPackedInMRMap
|
||||||
|
AO_STRENGTH : AoStrength
|
||||||
|
NUM_MORPH_TARGETS: NumberOfMorphTargets
|
||||||
|
NUM_TARGETS_BUFFERS: NumberOfTargetsBuffers
|
||||||
|
HORIZON_FADE: HorizonFade
|
||||||
|
EXPOSUREMAP : SunLightExposureMap
|
||||||
|
USE_VERTEX_COLORS_AS_SUN_INTENSITY : UseVertexColorsAsSunIntensity
|
||||||
|
STATIC_SUN_INTENSITY : StaticSunIntensity
|
||||||
|
BRIGHTEN_INDOOR_SHADOWS : BrightenIndoorShadows
|
||||||
|
DEBUG_VALUES_MODE : DebugValuesMode
|
||||||
|
USE_FOG : UseFog
|
||||||
|
FOG_LINEAR : LinearFog
|
||||||
|
FOG_EXP : ExpFog
|
||||||
|
FOG_EXPSQ : ExpSqFog
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Technique PreShadow {
|
||||||
|
|
||||||
|
VertexShader GLSL300 GLSL150 GLSL100: Common/MatDefs/Shadow/PreShadow.vert
|
||||||
|
FragmentShader GLSL300 GLSL150 GLSL100: Common/MatDefs/Shadow/PreShadowPBR.frag
|
||||||
|
|
||||||
|
WorldParameters {
|
||||||
|
WorldViewProjectionMatrix
|
||||||
|
WorldViewMatrix
|
||||||
|
ViewProjectionMatrix
|
||||||
|
ViewMatrix
|
||||||
|
}
|
||||||
|
|
||||||
|
Defines {
|
||||||
|
BOUND_DRAW_BUFFER: BoundDrawBuffer
|
||||||
|
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 GLSL310 GLSL300 GLSL150 GLSL100: Common/MatDefs/Shadow/PostShadow.vert
|
||||||
|
FragmentShader GLSL310 GLSL300 GLSL150 GLSL100: Common/MatDefs/Shadow/PostShadowPBR.frag
|
||||||
|
|
||||||
|
WorldParameters {
|
||||||
|
WorldViewProjectionMatrix
|
||||||
|
WorldMatrix
|
||||||
|
ViewProjectionMatrix
|
||||||
|
ViewMatrix
|
||||||
|
}
|
||||||
|
|
||||||
|
Defines {
|
||||||
|
BOUND_DRAW_BUFFER: BoundDrawBuffer
|
||||||
|
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 GLSL300 GLSL150 GLSL100 : Common/MatDefs/SSAO/normal.vert
|
||||||
|
FragmentShader GLSL300 GLSL150 GLSL100 : Common/MatDefs/SSAO/normal.frag
|
||||||
|
|
||||||
|
WorldParameters {
|
||||||
|
WorldViewProjectionMatrix
|
||||||
|
WorldViewMatrix
|
||||||
|
NormalMatrix
|
||||||
|
ViewProjectionMatrix
|
||||||
|
ViewMatrix
|
||||||
|
}
|
||||||
|
|
||||||
|
Defines {
|
||||||
|
BOUND_DRAW_BUFFER: BoundDrawBuffer
|
||||||
|
BASECOLORMAP_ALPHA : BaseColorMap
|
||||||
|
NUM_BONES : NumberOfBones
|
||||||
|
INSTANCING : UseInstancing
|
||||||
|
NUM_MORPH_TARGETS: NumberOfMorphTargets
|
||||||
|
NUM_TARGETS_BUFFERS: NumberOfTargetsBuffers
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
Technique Glow {
|
||||||
|
|
||||||
|
VertexShader GLSL300 GLSL150 GLSL100: Common/MatDefs/Misc/Unshaded.vert
|
||||||
|
FragmentShader GLSL300 GLSL150 GLSL100: Common/MatDefs/Light/PBRGlow.frag
|
||||||
|
|
||||||
|
WorldParameters {
|
||||||
|
WorldViewProjectionMatrix
|
||||||
|
ViewProjectionMatrix
|
||||||
|
ViewMatrix
|
||||||
|
}
|
||||||
|
|
||||||
|
Defines {
|
||||||
|
HAS_EMISSIVEMAP : EmissiveMap
|
||||||
|
HAS_EMISSIVECOLOR : Emissive
|
||||||
|
BOUND_DRAW_BUFFER: BoundDrawBuffer
|
||||||
|
NEED_TEXCOORD1
|
||||||
|
NUM_BONES : NumberOfBones
|
||||||
|
INSTANCING : UseInstancing
|
||||||
|
NUM_MORPH_TARGETS: NumberOfMorphTargets
|
||||||
|
NUM_TARGETS_BUFFERS: NumberOfTargetsBuffers
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -5,9 +5,9 @@ MaterialDef TerrainArray {
|
|||||||
FloatArray DiffuseScales
|
FloatArray DiffuseScales
|
||||||
TextureArray NormalArray
|
TextureArray NormalArray
|
||||||
Float Shininess : 32.0
|
Float Shininess : 32.0
|
||||||
Vector3 LightDir
|
Vector3 LightDir : 0.6 -0.8 0.4
|
||||||
Vector3 SunColor
|
Vector3 SunColor : 0.68 0.65 0.60
|
||||||
Vector3 AmbientColor
|
Vector3 AmbientColor : 0.08 0.10 0.16
|
||||||
Boolean DebugNoLight
|
Boolean DebugNoLight
|
||||||
Boolean DebugSlot0Only
|
Boolean DebugSlot0Only
|
||||||
Texture2D DebugDirectTex
|
Texture2D DebugDirectTex
|
||||||
@@ -30,8 +30,6 @@ MaterialDef TerrainArray {
|
|||||||
HAS_NORMAL_ARRAY : NormalArray
|
HAS_NORMAL_ARRAY : NormalArray
|
||||||
HAS_ALPHA_1 : AlphaMap_1
|
HAS_ALPHA_1 : AlphaMap_1
|
||||||
HAS_ALPHA_2 : AlphaMap_2
|
HAS_ALPHA_2 : AlphaMap_2
|
||||||
HAS_LIGHTDIR : LightDir
|
|
||||||
HAS_SCENE_LIGHT : SunColor
|
|
||||||
DEBUG_NO_LIGHT : DebugNoLight
|
DEBUG_NO_LIGHT : DebugNoLight
|
||||||
DEBUG_SLOT0_ONLY : DebugSlot0Only
|
DEBUG_SLOT0_ONLY : DebugSlot0Only
|
||||||
DEBUG_DIRECT_TEX : DebugDirectTex
|
DEBUG_DIRECT_TEX : DebugDirectTex
|
||||||
|
|||||||
@@ -7,9 +7,9 @@ MaterialDef Tree {
|
|||||||
Vector2 WindDir : 0.0 1.0
|
Vector2 WindDir : 0.0 1.0
|
||||||
Texture2D BarkMap
|
Texture2D BarkMap
|
||||||
Boolean HasBarkMap : false
|
Boolean HasBarkMap : false
|
||||||
Vector3 LightDir
|
Vector3 LightDir : 0.6 -0.8 0.4
|
||||||
Vector3 SunColor
|
Vector3 SunColor : 0.68 0.65 0.60
|
||||||
Vector3 AmbientColor
|
Vector3 AmbientColor : 0.08 0.10 0.16
|
||||||
}
|
}
|
||||||
|
|
||||||
Technique {
|
Technique {
|
||||||
@@ -23,7 +23,6 @@ MaterialDef Tree {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Defines {
|
Defines {
|
||||||
HAS_SCENE_LIGHT : SunColor
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -28,9 +28,9 @@ MaterialDef TreeLeaf {
|
|||||||
Matrix4 LightViewProjectionMatrix4
|
Matrix4 LightViewProjectionMatrix4
|
||||||
Matrix4 LightViewProjectionMatrix5
|
Matrix4 LightViewProjectionMatrix5
|
||||||
Vector3 LightPos
|
Vector3 LightPos
|
||||||
Vector3 LightDir
|
Vector3 LightDir : 0.6 -0.8 0.4
|
||||||
Vector3 SunColor
|
Vector3 SunColor : 0.68 0.65 0.60
|
||||||
Vector3 AmbientColor
|
Vector3 AmbientColor : 0.08 0.10 0.16
|
||||||
Float PCFEdge
|
Float PCFEdge
|
||||||
Float ShadowMapSize
|
Float ShadowMapSize
|
||||||
Boolean BackfaceShadows : false
|
Boolean BackfaceShadows : false
|
||||||
@@ -51,7 +51,6 @@ MaterialDef TreeLeaf {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Defines {
|
Defines {
|
||||||
HAS_SCENE_LIGHT : SunColor
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -16,14 +16,9 @@ uniform sampler2D m_AlphaMap_2;
|
|||||||
uniform sampler2DArray m_NormalArray;
|
uniform sampler2DArray m_NormalArray;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef HAS_LIGHTDIR
|
|
||||||
uniform vec3 m_LightDir;
|
uniform vec3 m_LightDir;
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef HAS_SCENE_LIGHT
|
|
||||||
uniform vec3 m_SunColor;
|
uniform vec3 m_SunColor;
|
||||||
uniform vec3 m_AmbientColor;
|
uniform vec3 m_AmbientColor;
|
||||||
#endif
|
|
||||||
|
|
||||||
in vec2 vSplatUV;
|
in vec2 vSplatUV;
|
||||||
in vec3 vWorldPos;
|
in vec3 vWorldPos;
|
||||||
@@ -111,18 +106,9 @@ void main() {
|
|||||||
N = normalize(pertN);
|
N = normalize(pertN);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef HAS_LIGHTDIR
|
|
||||||
vec3 lightDir = normalize(m_LightDir);
|
vec3 lightDir = normalize(m_LightDir);
|
||||||
#else
|
|
||||||
vec3 lightDir = normalize(vec3(0.6, 1.0, 0.4));
|
|
||||||
#endif
|
|
||||||
float diff = max(dot(N, lightDir), 0.0);
|
float diff = max(dot(N, lightDir), 0.0);
|
||||||
|
|
||||||
#ifdef HAS_SCENE_LIGHT
|
|
||||||
vec3 light = m_AmbientColor + m_SunColor * diff;
|
vec3 light = m_AmbientColor + m_SunColor * diff;
|
||||||
#else
|
|
||||||
vec3 light = vec3(diff * 0.65 + 0.35);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
const float BRIGHTNESS = 0.80;
|
const float BRIGHTNESS = 0.80;
|
||||||
#ifdef DEBUG_NO_LIGHT
|
#ifdef DEBUG_NO_LIGHT
|
||||||
|
|||||||
@@ -3,12 +3,9 @@
|
|||||||
uniform vec4 m_Diffuse;
|
uniform vec4 m_Diffuse;
|
||||||
uniform sampler2D m_BarkMap;
|
uniform sampler2D m_BarkMap;
|
||||||
uniform bool m_HasBarkMap;
|
uniform bool m_HasBarkMap;
|
||||||
|
uniform vec3 m_LightDir;
|
||||||
#ifdef HAS_SCENE_LIGHT
|
uniform vec3 m_SunColor;
|
||||||
uniform vec3 m_LightDir;
|
uniform vec3 m_AmbientColor;
|
||||||
uniform vec3 m_SunColor;
|
|
||||||
uniform vec3 m_AmbientColor;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
in vec2 texCoord;
|
in vec2 texCoord;
|
||||||
in vec3 worldNormal;
|
in vec3 worldNormal;
|
||||||
@@ -20,19 +17,8 @@ void main() {
|
|||||||
? texture2D(m_BarkMap, texCoord).rgb * m_Diffuse.rgb
|
? texture2D(m_BarkMap, texCoord).rgb * m_Diffuse.rgb
|
||||||
: m_Diffuse.rgb;
|
: m_Diffuse.rgb;
|
||||||
|
|
||||||
#ifdef HAS_SCENE_LIGHT
|
|
||||||
float diff = max(dot(n, normalize(m_LightDir)), 0.0);
|
float diff = max(dot(n, normalize(m_LightDir)), 0.0);
|
||||||
vec3 light = clamp(m_AmbientColor + m_SunColor * diff, 0.0, 1.0);
|
vec3 light = clamp(m_AmbientColor + m_SunColor * diff, 0.0, 1.0);
|
||||||
#else
|
|
||||||
vec3 sunDir = normalize(vec3(0.6, 0.7, 0.4));
|
|
||||||
vec3 fillDir = normalize(vec3(-0.5, 0.3, -0.4));
|
|
||||||
vec3 rimDir = normalize(vec3(-0.3, 0.5, 0.7));
|
|
||||||
float sun = max(dot(n, sunDir), 0.0);
|
|
||||||
float fill = max(dot(n, fillDir), 0.0) * 0.22;
|
|
||||||
float rim = max(dot(n, rimDir), 0.0) * 0.14;
|
|
||||||
float sky = dot(n, vec3(0.0, 1.0, 0.0)) * 0.4 + 0.4;
|
|
||||||
vec3 light = vec3(clamp(sun * 0.75 + fill + rim + sky * 0.09 + 0.05, 0.0, 1.0));
|
|
||||||
#endif
|
|
||||||
|
|
||||||
gl_FragColor = vec4(baseColor * light, m_Diffuse.a);
|
gl_FragColor = vec4(baseColor * light, m_Diffuse.a);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,12 +3,9 @@
|
|||||||
uniform vec4 m_Diffuse;
|
uniform vec4 m_Diffuse;
|
||||||
uniform sampler2D m_LeafMap;
|
uniform sampler2D m_LeafMap;
|
||||||
uniform bool m_HasLeafMap;
|
uniform bool m_HasLeafMap;
|
||||||
|
uniform vec3 m_LightDir;
|
||||||
#ifdef HAS_SCENE_LIGHT
|
uniform vec3 m_SunColor;
|
||||||
uniform vec3 m_LightDir;
|
uniform vec3 m_AmbientColor;
|
||||||
uniform vec3 m_SunColor;
|
|
||||||
uniform vec3 m_AmbientColor;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
in vec2 texCoord;
|
in vec2 texCoord;
|
||||||
in vec3 worldNormal;
|
in vec3 worldNormal;
|
||||||
@@ -27,12 +24,8 @@ void main() {
|
|||||||
baseColor = m_Diffuse.rgb * (0.7 + 0.3 * edge);
|
baseColor = m_Diffuse.rgb * (0.7 + 0.3 * edge);
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef HAS_SCENE_LIGHT
|
|
||||||
// Blätter transmittieren Licht — abs() für doppelseitige Beleuchtung
|
// Blätter transmittieren Licht — abs() für doppelseitige Beleuchtung
|
||||||
float diff = abs(dot(normalize(worldNormal), normalize(m_LightDir)));
|
float diff = abs(dot(normalize(worldNormal), normalize(m_LightDir)));
|
||||||
vec3 light = clamp(m_AmbientColor + m_SunColor * diff * 0.6, 0.0, 1.0);
|
vec3 light = clamp(m_AmbientColor + m_SunColor * diff * 0.6, 0.0, 1.0);
|
||||||
gl_FragColor = vec4(baseColor * light, 1.0);
|
gl_FragColor = vec4(baseColor * light, 1.0);
|
||||||
#else
|
|
||||||
gl_FragColor = vec4(baseColor * 0.8, 1.0);
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -37,7 +37,10 @@ public class DayTime {
|
|||||||
/** Tageszeit 0.0–1.0. */
|
/** Tageszeit 0.0–1.0. */
|
||||||
public float getTimeOfDay() { return timeOfDay; }
|
public float getTimeOfDay() { return timeOfDay; }
|
||||||
|
|
||||||
public void setTimeOfDay(float t) { timeOfDay = ((t % 1f) + 1f) % 1f; }
|
public void setTimeOfDay(float t) {
|
||||||
|
timeOfDay = ((t % 1f) + 1f) % 1f;
|
||||||
|
for (TimeListener l : listeners) l.onTimeChanged(timeOfDay);
|
||||||
|
}
|
||||||
|
|
||||||
/** @param seconds Echtzeit-Sekunden pro Spieltag */
|
/** @param seconds Echtzeit-Sekunden pro Spieltag */
|
||||||
public void setDayDuration(float seconds) { timeScale = 1f / seconds; }
|
public void setDayDuration(float seconds) { timeScale = 1f / seconds; }
|
||||||
|
|||||||
@@ -1137,7 +1137,18 @@ public class EditorApp extends Application {
|
|||||||
viewMenu.getItems().addAll(resetCam, new SeparatorMenuItem(), viewTexture, viewWireframe,
|
viewMenu.getItems().addAll(resetCam, new SeparatorMenuItem(), viewTexture, viewWireframe,
|
||||||
new SeparatorMenuItem(), viewTopology);
|
new SeparatorMenuItem(), viewTopology);
|
||||||
|
|
||||||
menuBar.getMenus().addAll(fileMenu, toolsMenu, viewMenu);
|
Menu zeitMenu = new Menu("Zeit");
|
||||||
|
ToggleGroup zeitGroup = new ToggleGroup();
|
||||||
|
int[] hours = {0, 3, 6, 9, 12, 15, 18, 21};
|
||||||
|
for (int h : hours) {
|
||||||
|
RadioMenuItem item = new RadioMenuItem(String.format("%02d:00", h));
|
||||||
|
item.setToggleGroup(zeitGroup);
|
||||||
|
if (h == 12) { item.setSelected(true); }
|
||||||
|
final float t = h / 24f;
|
||||||
|
item.setOnAction(e -> input.pendingTimeOfDay = t);
|
||||||
|
zeitMenu.getItems().add(item);
|
||||||
|
}
|
||||||
|
menuBar.getMenus().addAll(fileMenu, toolsMenu, viewMenu, zeitMenu);
|
||||||
|
|
||||||
ToolBar toolBar = new ToolBar();
|
ToolBar toolBar = new ToolBar();
|
||||||
baseBtn = new ToggleButton("▲▼ Basis-Terrain");
|
baseBtn = new ToggleButton("▲▼ Basis-Terrain");
|
||||||
|
|||||||
@@ -309,6 +309,17 @@ public class JmeEditorApp extends SimpleApplication {
|
|||||||
input.camPitch = (float) Math.toDegrees(
|
input.camPitch = (float) Math.toDegrees(
|
||||||
Math.asin(Math.max(-1f, Math.min(1f, dir.y))));
|
Math.asin(Math.max(-1f, Math.min(1f, dir.y))));
|
||||||
|
|
||||||
|
// Zeit-Menü: Tageszeit setzen
|
||||||
|
float pendingTime = input.pendingTimeOfDay;
|
||||||
|
if (!Float.isNaN(pendingTime)) {
|
||||||
|
input.pendingTimeOfDay = Float.NaN;
|
||||||
|
DayNightState dns = stateManager.getState(DayNightState.class);
|
||||||
|
if (dns != null) {
|
||||||
|
dns.getDayTime().setTimeOfDay(pendingTime);
|
||||||
|
dns.getDayTime().setPaused(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (jmeConsole == null) return;
|
if (jmeConsole == null) return;
|
||||||
|
|
||||||
// Toggle-Signal von JavaFX
|
// Toggle-Signal von JavaFX
|
||||||
|
|||||||
@@ -359,6 +359,9 @@ public class SharedInput {
|
|||||||
/** JME setzt diesen Wert; JavaFX liest ihn (z. B. für Eingabesperre). */
|
/** JME setzt diesen Wert; JavaFX liest ihn (z. B. für Eingabesperre). */
|
||||||
public volatile boolean consoleIsOpen = false;
|
public volatile boolean consoleIsOpen = false;
|
||||||
|
|
||||||
|
/** JavaFX → JME3: Tageszeit setzen (0.0 = Mitternacht, 0.5 = Mittag, 1.0 = Mitternacht). NaN = kein Auftrag. */
|
||||||
|
public volatile float pendingTimeOfDay = Float.NaN;
|
||||||
|
|
||||||
/** @deprecated Nur noch für Rückwärtskompatibilität – nicht mehr verwenden. */
|
/** @deprecated Nur noch für Rückwärtskompatibilität – nicht mehr verwenden. */
|
||||||
@Deprecated public volatile String pendingCommand = null;
|
@Deprecated public volatile String pendingCommand = null;
|
||||||
/** Status-/Fehlermeldungen von JME an JavaFX-Statusleiste. */
|
/** Status-/Fehlermeldungen von JME an JavaFX-Statusleiste. */
|
||||||
|
|||||||
@@ -113,6 +113,11 @@ public class SceneObjectState extends BaseAppState {
|
|||||||
/** Kleiner Cache: modelPath → ModelMeta, damit nicht pro Frame geladen werden muss. */
|
/** Kleiner Cache: modelPath → ModelMeta, damit nicht pro Frame geladen werden muss. */
|
||||||
private final java.util.Map<String, de.blight.common.ModelMeta> metaCache = new java.util.HashMap<>();
|
private final java.util.Map<String, de.blight.common.ModelMeta> metaCache = new java.util.HashMap<>();
|
||||||
|
|
||||||
|
// ── Beleuchtungs-Materialien (Tree/TreeLeaf/Fern) ────────────────────────
|
||||||
|
private final List<Material> sceneLitMaterials = new ArrayList<>();
|
||||||
|
private final List<Material> windMaterials = new ArrayList<>();
|
||||||
|
private final List<Material> pbrMaterials = new ArrayList<>();
|
||||||
|
|
||||||
// ── Bett-Liegefläche ─────────────────────────────────────────────────────
|
// ── Bett-Liegefläche ─────────────────────────────────────────────────────
|
||||||
/** Visualisierungspfeil für die Liegefläche (1,8 m); wird nur gezeigt wenn Bett-Objekt gewählt. */
|
/** Visualisierungspfeil für die Liegefläche (1,8 m); wird nur gezeigt wenn Bett-Objekt gewählt. */
|
||||||
private Node bedArrowNode = null;
|
private Node bedArrowNode = null;
|
||||||
@@ -183,6 +188,9 @@ public class SceneObjectState extends BaseAppState {
|
|||||||
objects.clear();
|
objects.clear();
|
||||||
objNodes.clear();
|
objNodes.clear();
|
||||||
animClips.clear();
|
animClips.clear();
|
||||||
|
sceneLitMaterials.clear();
|
||||||
|
windMaterials.clear();
|
||||||
|
pbrMaterials.clear();
|
||||||
selectedIndices.clear();
|
selectedIndices.clear();
|
||||||
activeGizmo = -1;
|
activeGizmo = -1;
|
||||||
if (gizmoNode != null)
|
if (gizmoNode != null)
|
||||||
@@ -222,6 +230,7 @@ public class SceneObjectState extends BaseAppState {
|
|||||||
|
|
||||||
objNodes.add(node);
|
objNodes.add(node);
|
||||||
objectRoot.attachChild(node);
|
objectRoot.attachChild(node);
|
||||||
|
collectLitMaterials(node);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -310,6 +319,32 @@ public class SceneObjectState extends BaseAppState {
|
|||||||
updateGizmoVisibility();
|
updateGizmoVisibility();
|
||||||
updateGizmoOrientation();
|
updateGizmoOrientation();
|
||||||
|
|
||||||
|
// Baum- und Farn-Shader mit Sonnen- und Windwerten versorgen; PBR-Emissive setzen
|
||||||
|
if (!sceneLitMaterials.isEmpty() || !windMaterials.isEmpty() || !pbrMaterials.isEmpty()) {
|
||||||
|
de.blight.game.state.DayNightState dns =
|
||||||
|
getApplication().getStateManager().getState(de.blight.game.state.DayNightState.class);
|
||||||
|
if (dns != null && dns.getSunLight() != null) {
|
||||||
|
Vector3f lightDir = dns.getSunDirection().negate();
|
||||||
|
com.jme3.math.ColorRGBA sc = dns.getSunLight().getColor();
|
||||||
|
com.jme3.math.ColorRGBA ac = dns.getCustomAmbient();
|
||||||
|
Vector3f sunVec = new Vector3f(sc.r, sc.g, sc.b);
|
||||||
|
Vector3f ambVec = new Vector3f(ac.r, ac.g, ac.b);
|
||||||
|
for (Material mat : sceneLitMaterials) {
|
||||||
|
mat.setVector3("LightDir", lightDir);
|
||||||
|
mat.setVector3("SunColor", sunVec);
|
||||||
|
mat.setVector3("AmbientColor", ambVec);
|
||||||
|
}
|
||||||
|
for (Material mat : windMaterials) {
|
||||||
|
mat.setVector3("LightDir", lightDir);
|
||||||
|
mat.setVector3("SunColor", sunVec);
|
||||||
|
mat.setVector3("AmbientColor", ambVec);
|
||||||
|
}
|
||||||
|
for (Material mat : pbrMaterials) {
|
||||||
|
mat.setColor("Emissive", new com.jme3.math.ColorRGBA(ac.r, ac.g, ac.b, 1f));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Baum-Ordner-Platzierungsmodus
|
// Baum-Ordner-Platzierungsmodus
|
||||||
String treeFolder = input.treeFolderPath;
|
String treeFolder = input.treeFolderPath;
|
||||||
if (treeFolder != null && !treeFolder.equals(activeFolderPath)) {
|
if (treeFolder != null && !treeFolder.equals(activeFolderPath)) {
|
||||||
@@ -687,6 +722,7 @@ public class SceneObjectState extends BaseAppState {
|
|||||||
}
|
}
|
||||||
objNodes.add(node);
|
objNodes.add(node);
|
||||||
objectRoot.attachChild(node);
|
objectRoot.attachChild(node);
|
||||||
|
collectLitMaterials(node);
|
||||||
|
|
||||||
selectObject(objects.size() - 1, false);
|
selectObject(objects.size() - 1, false);
|
||||||
input.objectJustPlaced = true;
|
input.objectJustPlaced = true;
|
||||||
@@ -741,13 +777,73 @@ public class SceneObjectState extends BaseAppState {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void convertUnshadedToPbr(Spatial spatial) {
|
||||||
|
if (spatial instanceof Geometry geo) {
|
||||||
|
Material mat = geo.getMaterial();
|
||||||
|
if (mat == null) return;
|
||||||
|
if (!"Unshaded".equals(mat.getMaterialDef().getName())) return;
|
||||||
|
|
||||||
|
com.jme3.material.MatParam colorMap = mat.getParam("ColorMap");
|
||||||
|
com.jme3.material.MatParam color = mat.getParam("Color");
|
||||||
|
com.jme3.material.RenderState origRS = mat.getAdditionalRenderState();
|
||||||
|
|
||||||
|
Material pbrMat = new Material(assets, "Common/MatDefs/Light/PBRLighting.j3md");
|
||||||
|
pbrMat.setFloat("Metallic", 0.0f);
|
||||||
|
pbrMat.setFloat("Roughness", 0.85f);
|
||||||
|
|
||||||
|
if (colorMap != null && colorMap.getValue() instanceof Texture t) {
|
||||||
|
pbrMat.setTexture("BaseColorMap", t);
|
||||||
|
} else if (color != null && color.getValue() instanceof ColorRGBA c) {
|
||||||
|
pbrMat.setColor("BaseColor", new ColorRGBA(c.r, c.g, c.b, 1f));
|
||||||
|
}
|
||||||
|
|
||||||
|
com.jme3.material.RenderState rs = pbrMat.getAdditionalRenderState();
|
||||||
|
rs.setBlendMode(origRS.getBlendMode());
|
||||||
|
rs.setFaceCullMode(origRS.getFaceCullMode());
|
||||||
|
|
||||||
|
geo.setMaterial(pbrMat);
|
||||||
|
} else if (spatial instanceof Node node) {
|
||||||
|
for (Spatial child : new java.util.ArrayList<>(node.getChildren())) {
|
||||||
|
convertUnshadedToPbr(child);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void collectLitMaterials(Spatial spatial) {
|
||||||
|
if (spatial instanceof Geometry geo) {
|
||||||
|
Material mat = geo.getMaterial();
|
||||||
|
if (mat == null) return;
|
||||||
|
String name = mat.getMaterialDef().getName();
|
||||||
|
if ("Tree".equals(name) || "TreeLeaf".equals(name)) {
|
||||||
|
mat.setVector3("SunColor", new com.jme3.math.Vector3f(0.68f, 0.65f, 0.60f));
|
||||||
|
mat.setVector3("AmbientColor", new com.jme3.math.Vector3f(0.08f, 0.10f, 0.16f));
|
||||||
|
mat.setVector3("LightDir", new com.jme3.math.Vector3f(0f, -1f, 0f));
|
||||||
|
sceneLitMaterials.add(mat);
|
||||||
|
} else if ("Fern".equals(name)) {
|
||||||
|
windMaterials.add(mat);
|
||||||
|
} else if ("PBRLighting".equals(name)) {
|
||||||
|
mat.setFloat("EmissivePower", 1f);
|
||||||
|
mat.setFloat("EmissiveIntensity", 1f);
|
||||||
|
mat.setColor("Emissive", new com.jme3.math.ColorRGBA(0.08f, 0.10f, 0.16f, 1f));
|
||||||
|
pbrMaterials.add(mat);
|
||||||
|
}
|
||||||
|
} else if (spatial instanceof Node node) {
|
||||||
|
for (Spatial child : node.getChildren()) {
|
||||||
|
collectLitMaterials(child);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private Node loadModelNode(String modelPath, float wx, float wy, float wz) {
|
private Node loadModelNode(String modelPath, float wx, float wy, float wz) {
|
||||||
Node node = new Node("obj_" + objects.size());
|
Node node = new Node("obj_" + objects.size());
|
||||||
try {
|
try {
|
||||||
Spatial model = modelPath.startsWith("@")
|
Spatial model = modelPath.startsWith("@")
|
||||||
? createPrimitiveSpatial(modelPath.substring(1))
|
? createPrimitiveSpatial(modelPath.substring(1))
|
||||||
: assets.loadModel(modelPath);
|
: assets.loadModel(modelPath);
|
||||||
if (!modelPath.startsWith("@")) stripControlsRecursive(model);
|
if (!modelPath.startsWith("@")) {
|
||||||
|
stripControlsRecursive(model);
|
||||||
|
convertUnshadedToPbr(model);
|
||||||
|
}
|
||||||
if (modelPath.startsWith("@")) {
|
if (modelPath.startsWith("@")) {
|
||||||
Material mat = buildPrimitiveMaterial();
|
Material mat = buildPrimitiveMaterial();
|
||||||
if (model instanceof Geometry g) g.setMaterial(mat);
|
if (model instanceof Geometry g) g.setMaterial(mat);
|
||||||
@@ -785,12 +881,13 @@ public class SceneObjectState extends BaseAppState {
|
|||||||
boolean hasNmap = nmap != null && !nmap.isEmpty();
|
boolean hasNmap = nmap != null && !nmap.isEmpty();
|
||||||
if (hasTex || hasNmap) {
|
if (hasTex || hasNmap) {
|
||||||
try {
|
try {
|
||||||
Material mat = new Material(assets, "Common/MatDefs/Light/Lighting.j3md");
|
Material mat = new Material(assets, "Common/MatDefs/Light/PBRLighting.j3md");
|
||||||
mat.setBoolean("UseMaterialColors", false);
|
mat.setFloat("Metallic", 0.0f);
|
||||||
|
mat.setFloat("Roughness", 0.85f);
|
||||||
if (hasTex) {
|
if (hasTex) {
|
||||||
Texture t = assets.loadTexture(tex);
|
Texture t = assets.loadTexture(tex);
|
||||||
t.setWrap(Texture.WrapMode.Repeat);
|
t.setWrap(Texture.WrapMode.Repeat);
|
||||||
mat.setTexture("DiffuseMap", t);
|
mat.setTexture("BaseColorMap", t);
|
||||||
}
|
}
|
||||||
if (hasNmap) {
|
if (hasNmap) {
|
||||||
Texture n = assets.loadTexture(nmap);
|
Texture n = assets.loadTexture(nmap);
|
||||||
@@ -800,8 +897,10 @@ public class SceneObjectState extends BaseAppState {
|
|||||||
return mat;
|
return mat;
|
||||||
} catch (Exception ignored) {}
|
} catch (Exception ignored) {}
|
||||||
}
|
}
|
||||||
Material mat = new Material(assets, "Common/MatDefs/Misc/Unshaded.j3md");
|
Material mat = new Material(assets, "Common/MatDefs/Light/PBRLighting.j3md");
|
||||||
mat.setColor("Color", new com.jme3.math.ColorRGBA(0.75f, 0.75f, 0.75f, 1f));
|
mat.setFloat("Metallic", 0.0f);
|
||||||
|
mat.setFloat("Roughness", 0.85f);
|
||||||
|
mat.setColor("BaseColor", new com.jme3.math.ColorRGBA(0.75f, 0.75f, 0.75f, 1f));
|
||||||
return mat;
|
return mat;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1461,7 +1560,9 @@ public class SceneObjectState extends BaseAppState {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
} else if (hasTex) {
|
} else if (hasTex) {
|
||||||
mat = new Material(assets, "Common/MatDefs/Light/Lighting.j3md");
|
mat = new Material(assets, "Common/MatDefs/Light/PBRLighting.j3md");
|
||||||
|
mat.setFloat("Metallic", 0.0f);
|
||||||
|
mat.setFloat("Roughness", 0.85f);
|
||||||
} else {
|
} else {
|
||||||
mat = new Material(assets, "Common/MatDefs/Misc/Unshaded.j3md");
|
mat = new Material(assets, "Common/MatDefs/Misc/Unshaded.j3md");
|
||||||
mat.setColor("Color", new ColorRGBA(0.75f, 0.75f, 0.75f, 1f));
|
mat.setColor("Color", new ColorRGBA(0.75f, 0.75f, 0.75f, 1f));
|
||||||
|
|||||||
@@ -96,6 +96,7 @@ public class TerrainEditorState extends BaseAppState {
|
|||||||
private final SharedInput input;
|
private final SharedInput input;
|
||||||
|
|
||||||
private TerrainQuad terrain;
|
private TerrainQuad terrain;
|
||||||
|
private com.jme3.material.Material terrainMat;
|
||||||
private float[] cachedHeightMap; // Einmal geladen, danach manuell synchron gehalten
|
private float[] cachedHeightMap; // Einmal geladen, danach manuell synchron gehalten
|
||||||
private Geometry brushIndicator;
|
private Geometry brushIndicator;
|
||||||
private PlacedObjectState placedObjectState;
|
private PlacedObjectState placedObjectState;
|
||||||
@@ -157,6 +158,9 @@ public class TerrainEditorState extends BaseAppState {
|
|||||||
// ── Lifecycle ─────────────────────────────────────────────────────────────
|
// ── Lifecycle ─────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
private de.blight.game.state.DayNightState dayNightState;
|
private de.blight.game.state.DayNightState dayNightState;
|
||||||
|
private com.jme3.light.LightProbe probe;
|
||||||
|
private com.jme3.environment.EnvironmentCamera envCam;
|
||||||
|
private int envCamFrames = 0;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void initialize(Application app) {
|
protected void initialize(Application app) {
|
||||||
@@ -182,6 +186,16 @@ public class TerrainEditorState extends BaseAppState {
|
|||||||
dayNightState.getDayTime().setTimeOfDay(0.5f);
|
dayNightState.getDayTime().setTimeOfDay(0.5f);
|
||||||
dayNightState.setPaused(true);
|
dayNightState.setPaused(true);
|
||||||
app.getStateManager().attach(dayNightState);
|
app.getStateManager().attach(dayNightState);
|
||||||
|
|
||||||
|
// LightProbe für PBR-IBL – ohne Probe ist envLightContribution immer 0 in JME3 3.9.0.
|
||||||
|
// Probe backen wenn SkyControl den Himmel gerendert hat (ab Frame 30).
|
||||||
|
probe = new com.jme3.light.LightProbe();
|
||||||
|
probe.getArea().setRadius(8000f);
|
||||||
|
rootNode.addLight(probe);
|
||||||
|
envCam = new com.jme3.environment.EnvironmentCamera(256, new com.jme3.math.Vector3f(0f, 5f, 0f));
|
||||||
|
app.getStateManager().attach(envCam);
|
||||||
|
envCamFrames = 0;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void loadCameraPrefs() {
|
private void loadCameraPrefs() {
|
||||||
@@ -391,7 +405,7 @@ public class TerrainEditorState extends BaseAppState {
|
|||||||
tq.addControl(lod);
|
tq.addControl(lod);
|
||||||
|
|
||||||
initSplatmap();
|
initSplatmap();
|
||||||
tq.setMaterial(buildTerrainMaterial());
|
tq.setMaterial(terrainMat = buildTerrainMaterial());
|
||||||
return tq;
|
return tq;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -594,7 +608,7 @@ public class TerrainEditorState extends BaseAppState {
|
|||||||
if (dayNightState != null && dayNightState.getSunLight() != null) {
|
if (dayNightState != null && dayNightState.getSunLight() != null) {
|
||||||
mat.setVector3("LightDir", dayNightState.getSunDirection().negate());
|
mat.setVector3("LightDir", dayNightState.getSunDirection().negate());
|
||||||
com.jme3.math.ColorRGBA sc = dayNightState.getSunLight().getColor();
|
com.jme3.math.ColorRGBA sc = dayNightState.getSunLight().getColor();
|
||||||
com.jme3.math.ColorRGBA ac = dayNightState.getAmbientLight().getColor();
|
com.jme3.math.ColorRGBA ac = dayNightState.getCustomAmbient();
|
||||||
mat.setVector3("SunColor", new com.jme3.math.Vector3f(sc.r, sc.g, sc.b));
|
mat.setVector3("SunColor", new com.jme3.math.Vector3f(sc.r, sc.g, sc.b));
|
||||||
mat.setVector3("AmbientColor", new com.jme3.math.Vector3f(ac.r, ac.g, ac.b));
|
mat.setVector3("AmbientColor", new com.jme3.math.Vector3f(ac.r, ac.g, ac.b));
|
||||||
}
|
}
|
||||||
@@ -925,6 +939,30 @@ public class TerrainEditorState extends BaseAppState {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void update(float tpf) {
|
public void update(float tpf) {
|
||||||
|
// LightProbe backen: nach 30 Frames hat SkyControl den Himmel vollständig gerendert.
|
||||||
|
if (envCam != null) {
|
||||||
|
envCamFrames++;
|
||||||
|
if (envCamFrames == 30) {
|
||||||
|
com.jme3.environment.LightProbeFactory.updateProbe(probe, envCam, rootNode,
|
||||||
|
new com.jme3.environment.generation.JobProgressAdapter<com.jme3.light.LightProbe>() {
|
||||||
|
@Override public void done(com.jme3.light.LightProbe result) {
|
||||||
|
app.getStateManager().detach(envCam);
|
||||||
|
envCam = null;
|
||||||
|
log.info("[TerrainEditor] LightProbe fertig.");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Terrain-Shader mit DayNightState synchronisieren (reagiert auf Zeit-Menü-Änderungen)
|
||||||
|
if (terrainMat != null && dayNightState != null && dayNightState.getSunLight() != null) {
|
||||||
|
terrainMat.setVector3("LightDir", dayNightState.getSunDirection().negate());
|
||||||
|
com.jme3.math.ColorRGBA sc = dayNightState.getSunLight().getColor();
|
||||||
|
com.jme3.math.ColorRGBA ac = dayNightState.getCustomAmbient();
|
||||||
|
terrainMat.setVector3("SunColor", new com.jme3.math.Vector3f(sc.r, sc.g, sc.b));
|
||||||
|
terrainMat.setVector3("AmbientColor", new com.jme3.math.Vector3f(ac.r, ac.g, ac.b));
|
||||||
|
}
|
||||||
|
|
||||||
float pgx = input.pendingGotoX;
|
float pgx = input.pendingGotoX;
|
||||||
if (!Float.isNaN(pgx)) {
|
if (!Float.isNaN(pgx)) {
|
||||||
input.pendingGotoX = Float.NaN;
|
input.pendingGotoX = Float.NaN;
|
||||||
@@ -987,7 +1025,7 @@ public class TerrainEditorState extends BaseAppState {
|
|||||||
input.thirdNormalMapsChanged = false;
|
input.thirdNormalMapsChanged = false;
|
||||||
input.normalMapOrderChanged = false;
|
input.normalMapOrderChanged = false;
|
||||||
input.diffuseScalesChanged = false;
|
input.diffuseScalesChanged = false;
|
||||||
terrain.setMaterial(buildTerrainMaterial());
|
terrain.setMaterial(terrainMat = buildTerrainMaterial());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (input.reloadPlacedOther) {
|
if (input.reloadPlacedOther) {
|
||||||
|
|||||||
@@ -219,6 +219,19 @@ public class VoxelEditorState extends BaseAppState {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void update(float tpf) {
|
public void update(float tpf) {
|
||||||
|
// Voxel-Shader mit DayNightState synchronisieren
|
||||||
|
if (voxelMaterial != null) {
|
||||||
|
de.blight.game.state.DayNightState dns =
|
||||||
|
getApplication().getStateManager().getState(de.blight.game.state.DayNightState.class);
|
||||||
|
if (dns != null && dns.getSunLight() != null) {
|
||||||
|
voxelMaterial.setVector3("LightDir", dns.getSunDirection().negate());
|
||||||
|
com.jme3.math.ColorRGBA sc = dns.getSunLight().getColor();
|
||||||
|
com.jme3.math.ColorRGBA ac = dns.getCustomAmbient();
|
||||||
|
voxelMaterial.setVector3("SunColor", new com.jme3.math.Vector3f(sc.r, sc.g, sc.b));
|
||||||
|
voxelMaterial.setVector3("AmbientColor", new com.jme3.math.Vector3f(ac.r, ac.g, ac.b));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// LOD-Ergebnisse aus dem Hintergrund-Thread übernehmen
|
// LOD-Ergebnisse aus dem Hintergrund-Thread übernehmen
|
||||||
Runnable r;
|
Runnable r;
|
||||||
while ((r = lodResultQueue.poll()) != null) r.run();
|
while ((r = lodResultQueue.poll()) != null) r.run();
|
||||||
|
|||||||
@@ -9,6 +9,9 @@ import com.jme3.bullet.collision.shapes.CapsuleCollisionShape;
|
|||||||
import com.jme3.bullet.control.CharacterControl;
|
import com.jme3.bullet.control.CharacterControl;
|
||||||
import com.jme3.bullet.control.RigidBodyControl;
|
import com.jme3.bullet.control.RigidBodyControl;
|
||||||
import com.jme3.bullet.util.CollisionShapeFactory;
|
import com.jme3.bullet.util.CollisionShapeFactory;
|
||||||
|
import com.jme3.environment.EnvironmentCamera;
|
||||||
|
import com.jme3.environment.LightProbeFactory;
|
||||||
|
import com.jme3.environment.generation.JobProgressAdapter;
|
||||||
import com.jme3.light.*;
|
import com.jme3.light.*;
|
||||||
import com.jme3.material.Material;
|
import com.jme3.material.Material;
|
||||||
import com.jme3.material.RenderState;
|
import com.jme3.material.RenderState;
|
||||||
@@ -338,12 +341,35 @@ public class WorldScene extends BaseAppState {
|
|||||||
drownState = new de.blight.game.state.DrownState(terrainChunkState, physicsChar, playerInput, drownMc);
|
drownState = new de.blight.game.state.DrownState(terrainChunkState, physicsChar, playerInput, drownMc);
|
||||||
app.getStateManager().attach(drownState);
|
app.getStateManager().attach(drownState);
|
||||||
|
|
||||||
|
|
||||||
// Maus einfangen – keine Klick-Pflicht für Kamerasteuerung
|
// Maus einfangen – keine Klick-Pflicht für Kamerasteuerung
|
||||||
app.getInputManager().setCursorVisible(false);
|
app.getInputManager().setCursorVisible(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void update(float tpf) {
|
public void update(float tpf) {
|
||||||
|
// LightProbe backen: nach 30 Frames auf Mittag stellen (SkyControl braucht mehrere
|
||||||
|
// Frames um die Himmels-Geometrie zu aktualisieren). Nach dem Backen Uhrzeit zurück.
|
||||||
|
if (envCam != null) {
|
||||||
|
envCamFrames++;
|
||||||
|
if (envCamFrames == 2) {
|
||||||
|
// Himmel schon jetzt auf Mittag damit SkyControl bis Frame 30 rendern kann
|
||||||
|
dayNight.getDayTime().setTimeOfDay(0.5f);
|
||||||
|
} else if (envCamFrames == 30) {
|
||||||
|
log.info("[WorldScene] Starte LightProbe-Backen bei Mittag (Frame {})...", envCamFrames);
|
||||||
|
final float restoreTime = 0.25f;
|
||||||
|
LightProbeFactory.updateProbe(probe, envCam, rootNode,
|
||||||
|
new JobProgressAdapter<LightProbe>() {
|
||||||
|
@Override public void done(LightProbe result) {
|
||||||
|
dayNight.getDayTime().setTimeOfDay(restoreTime);
|
||||||
|
app.getStateManager().detach(envCam);
|
||||||
|
envCam = null;
|
||||||
|
log.info("[WorldScene] LightProbe fertig, Uhrzeit zurück auf {}.", restoreTime);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Physik-Charakter erst aktivieren wenn BulletAppState bereit ist UND
|
// Physik-Charakter erst aktivieren wenn BulletAppState bereit ist UND
|
||||||
// TerrainChunkState bereits einen Physik-Collider für den Spawn-Chunk hat.
|
// TerrainChunkState bereits einen Physik-Collider für den Spawn-Chunk hat.
|
||||||
if (physicsCharPending) {
|
if (physicsCharPending) {
|
||||||
@@ -380,17 +406,16 @@ public class WorldScene extends BaseAppState {
|
|||||||
if (ambientSounds != null) ambientSounds.setPlayerPosition(pos);
|
if (ambientSounds != null) ambientSounds.setPlayerPosition(pos);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Terrain-Shader mit DayNightState-Licht synchronisieren (Richtung + Farben)
|
if (terrainMaterial != null && dayNight != null && dayNight.getSunLight() != null) {
|
||||||
if (terrainMaterial != null && dayNight != null
|
terrainMaterial.setVector3("LightDir", dayNight.getSunDirection().negate());
|
||||||
&& dayNight.getSunLight() != null) {
|
|
||||||
terrainMaterial.setVector3("LightDir",
|
|
||||||
dayNight.getSunDirection().negate());
|
|
||||||
ColorRGBA sc = dayNight.getSunLight().getColor();
|
ColorRGBA sc = dayNight.getSunLight().getColor();
|
||||||
ColorRGBA ac = dayNight.getAmbientLight().getColor();
|
ColorRGBA ac = dayNight.getCustomAmbient();
|
||||||
terrainMaterial.setVector3("SunColor",
|
terrainMaterial.setVector3("SunColor", new Vector3f(sc.r, sc.g, sc.b));
|
||||||
new Vector3f(sc.r, sc.g, sc.b));
|
terrainMaterial.setVector3("AmbientColor", new Vector3f(ac.r, ac.g, ac.b));
|
||||||
terrainMaterial.setVector3("AmbientColor",
|
// Charakter-PBR: Emissive = customAmbient (IBL-Fallback ohne fertige LightProbe)
|
||||||
new Vector3f(ac.r, ac.g, ac.b));
|
for (Material mat : characterPbrMaterials) {
|
||||||
|
mat.setColor("Emissive", new ColorRGBA(ac.r, ac.g, ac.b, 1f));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -507,6 +532,26 @@ public class WorldScene extends BaseAppState {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sammelt alle PBRLighting-Materialien und setzt EmissivePower=1 (Standardwert 3.0
|
||||||
|
* würde 0.08 → 0.08³=0.0005 zusammenbrechen lassen). Initial mit Tag-Ambient initialisiert.
|
||||||
|
*/
|
||||||
|
public static void collectPbrMaterials(Spatial s, List<com.jme3.material.Material> out) {
|
||||||
|
if (s instanceof Geometry g) {
|
||||||
|
com.jme3.material.Material m = g.getMaterial();
|
||||||
|
if (m != null && "PBRLighting".equals(m.getMaterialDef().getName())) {
|
||||||
|
m.setFloat("EmissivePower", 1f);
|
||||||
|
m.setFloat("EmissiveIntensity", 1f);
|
||||||
|
m.setColor("Emissive", new ColorRGBA(0.08f, 0.10f, 0.16f, 1f));
|
||||||
|
out.add(m);
|
||||||
|
}
|
||||||
|
} else if (s instanceof Node n) {
|
||||||
|
for (Spatial child : n.getChildren()) {
|
||||||
|
collectPbrMaterials(child, out);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/** Lädt das Hauptcharakter-Modell, falls im character/-Verzeichnis definiert; sonst Platzhalter. */
|
/** Lädt das Hauptcharakter-Modell, falls im character/-Verzeichnis definiert; sonst Platzhalter. */
|
||||||
private Node loadOrBuildCharacter() {
|
private Node loadOrBuildCharacter() {
|
||||||
MainCharacter mc = findMainCharacter();
|
MainCharacter mc = findMainCharacter();
|
||||||
@@ -516,6 +561,8 @@ public class WorldScene extends BaseAppState {
|
|||||||
stripEmbeddedClips(loaded, mc.getModelPath());
|
stripEmbeddedClips(loaded, mc.getModelPath());
|
||||||
loaded.setShadowMode(RenderQueue.ShadowMode.CastAndReceive);
|
loaded.setShadowMode(RenderQueue.ShadowMode.CastAndReceive);
|
||||||
applyFullAmbient(loaded);
|
applyFullAmbient(loaded);
|
||||||
|
collectPbrMaterials(loaded, characterPbrMaterials);
|
||||||
|
log.info("[WorldScene] {} PBR-Materialien im Charakter-Modell gefunden.", characterPbrMaterials.size());
|
||||||
|
|
||||||
// Auf 1.8 m skalieren – Höhe aus Vertex-Daten (zuverlässiger als BoundingBox
|
// Auf 1.8 m skalieren – Höhe aus Vertex-Daten (zuverlässiger als BoundingBox
|
||||||
// bei Skinned-Meshes, die vor der ersten SkinningControl-Runde falsche Bounds liefern)
|
// bei Skinned-Meshes, die vor der ersten SkinningControl-Runde falsche Bounds liefern)
|
||||||
@@ -628,6 +675,15 @@ public class WorldScene extends BaseAppState {
|
|||||||
shadowFilter.setEnabled(true);
|
shadowFilter.setEnabled(true);
|
||||||
dayNight.setShadowFilter(shadowFilter); // bindet sun + übernimmt Intensitäts-Updates
|
dayNight.setShadowFilter(shadowFilter); // bindet sun + übernimmt Intensitäts-Updates
|
||||||
|
|
||||||
|
// LightProbe für PBR-IBL: ohne Probe ignoriert JME3-PBR den g_AmbientLightColor.
|
||||||
|
// EnvironmentCamera backt in den ersten Frames, AmbientLight skaliert dann dynamisch.
|
||||||
|
probe = new LightProbe();
|
||||||
|
probe.getArea().setRadius(4000f);
|
||||||
|
rootNode.addLight(probe);
|
||||||
|
envCam = new EnvironmentCamera(256, new Vector3f(0f, 5f, 0f));
|
||||||
|
app.getStateManager().attach(envCam);
|
||||||
|
envCamFrames = 0;
|
||||||
|
|
||||||
setupPostProcessing(dayNight.getSunDirection(), shadowFilter);
|
setupPostProcessing(dayNight.getSunDirection(), shadowFilter);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -763,19 +819,17 @@ public class WorldScene extends BaseAppState {
|
|||||||
|
|
||||||
Node node = new Node("gebirge");
|
Node node = new Node("gebirge");
|
||||||
|
|
||||||
Material mat = new Material(assetManager, "Common/MatDefs/Light/Lighting.j3md");
|
Material mat = new Material(assetManager, "Common/MatDefs/Light/PBRLighting.j3md");
|
||||||
|
mat.setFloat("Metallic", 0.0f);
|
||||||
|
mat.setFloat("Roughness", 0.9f);
|
||||||
try {
|
try {
|
||||||
Texture rock = assetManager.loadTexture("Textures/Terrain/Rock2/rock.jpg");
|
Texture rock = assetManager.loadTexture("Textures/Terrain/Rock2/rock.jpg");
|
||||||
rock.setWrap(Texture.WrapMode.Repeat);
|
rock.setWrap(Texture.WrapMode.Repeat);
|
||||||
mat.setTexture("DiffuseMap", rock);
|
mat.setTexture("BaseColorMap", rock);
|
||||||
mat.setColor("Diffuse", new ColorRGBA(0.45f, 0.32f, 0.25f, 1f));
|
mat.setColor("BaseColor", new ColorRGBA(0.45f, 0.32f, 0.25f, 1f));
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
mat.setBoolean("UseMaterialColors", true);
|
mat.setColor("BaseColor", new ColorRGBA(0.18f, 0.12f, 0.08f, 1f));
|
||||||
mat.setColor("Diffuse", new ColorRGBA(0.18f, 0.12f, 0.08f, 1f));
|
|
||||||
}
|
}
|
||||||
mat.setColor("Ambient", new ColorRGBA(0.10f, 0.07f, 0.05f, 1f));
|
|
||||||
mat.setColor("Specular", new ColorRGBA(0.06f, 0.05f, 0.04f, 1f));
|
|
||||||
mat.setFloat("Shininess", 6f);
|
|
||||||
mat.getAdditionalRenderState().setFaceCullMode(RenderState.FaceCullMode.Off);
|
mat.getAdditionalRenderState().setFaceCullMode(RenderState.FaceCullMode.Off);
|
||||||
mat.getAdditionalRenderState().setPolyOffset(2f, 2f);
|
mat.getAdditionalRenderState().setPolyOffset(2f, 2f);
|
||||||
|
|
||||||
@@ -904,6 +958,10 @@ public class WorldScene extends BaseAppState {
|
|||||||
|
|
||||||
private static final int TERRAIN_ARRAY_SIZE = 1024;
|
private static final int TERRAIN_ARRAY_SIZE = 1024;
|
||||||
private DayNightState dayNight;
|
private DayNightState dayNight;
|
||||||
|
private LightProbe probe;
|
||||||
|
private EnvironmentCamera envCam;
|
||||||
|
private int envCamFrames = 0;
|
||||||
|
private final List<Material> characterPbrMaterials = new ArrayList<>();
|
||||||
private int debugMode = 0; // 0=normal, 1=kein Licht, 2=nur Slot0, 3=direkte Tex2D
|
private int debugMode = 0; // 0=normal, 1=kein Licht, 2=nur Slot0, 3=direkte Tex2D
|
||||||
private String debugSlot0Path = "";
|
private String debugSlot0Path = "";
|
||||||
|
|
||||||
@@ -1118,10 +1176,10 @@ public class WorldScene extends BaseAppState {
|
|||||||
mat.setBoolean("useTriPlanarMapping", false);
|
mat.setBoolean("useTriPlanarMapping", false);
|
||||||
return mat;
|
return mat;
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
Material mat = new Material(assetManager, "Common/MatDefs/Light/Lighting.j3md");
|
Material mat = new Material(assetManager, "Common/MatDefs/Light/PBRLighting.j3md");
|
||||||
mat.setBoolean("UseMaterialColors", true);
|
mat.setFloat("Metallic", 0.0f);
|
||||||
mat.setColor("Diffuse", new ColorRGBA(0.28f, 0.58f, 0.18f, 1f));
|
mat.setFloat("Roughness", 0.9f);
|
||||||
mat.setColor("Ambient", new ColorRGBA(0.15f, 0.30f, 0.09f, 1f));
|
mat.setColor("BaseColor", new ColorRGBA(0.28f, 0.58f, 0.18f, 1f));
|
||||||
return mat;
|
return mat;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1143,24 +1201,20 @@ public class WorldScene extends BaseAppState {
|
|||||||
// -----------------------------------------------------------------------
|
// -----------------------------------------------------------------------
|
||||||
|
|
||||||
private void buildDecorations(TerrainQuad terrain) {
|
private void buildDecorations(TerrainQuad terrain) {
|
||||||
Material stoneMat = new Material(assetManager, "Common/MatDefs/Light/Lighting.j3md");
|
Material stoneMat = new Material(assetManager, "Common/MatDefs/Light/PBRLighting.j3md");
|
||||||
stoneMat.setBoolean("UseMaterialColors", true);
|
stoneMat.setFloat("Metallic", 0.0f);
|
||||||
stoneMat.setColor("Diffuse", new ColorRGBA(0.55f, 0.55f, 0.55f, 1f));
|
stoneMat.setFloat("Roughness", 0.8f);
|
||||||
stoneMat.setColor("Ambient", new ColorRGBA(0.3f, 0.3f, 0.3f, 1f));
|
stoneMat.setColor("BaseColor", new ColorRGBA(0.55f, 0.55f, 0.55f, 1f));
|
||||||
stoneMat.setColor("Specular", ColorRGBA.White);
|
|
||||||
stoneMat.setFloat("Shininess", 32f);
|
|
||||||
|
|
||||||
Material treeTrunkMat = new Material(assetManager, "Common/MatDefs/Light/Lighting.j3md");
|
Material treeTrunkMat = new Material(assetManager, "Common/MatDefs/Light/PBRLighting.j3md");
|
||||||
treeTrunkMat.setBoolean("UseMaterialColors", true);
|
treeTrunkMat.setFloat("Metallic", 0.0f);
|
||||||
treeTrunkMat.setColor("Diffuse", new ColorRGBA(0.45f, 0.28f, 0.1f, 1f));
|
treeTrunkMat.setFloat("Roughness", 0.95f);
|
||||||
treeTrunkMat.setColor("Ambient", new ColorRGBA(0.2f, 0.12f, 0.04f, 1f));
|
treeTrunkMat.setColor("BaseColor", new ColorRGBA(0.45f, 0.28f, 0.1f, 1f));
|
||||||
treeTrunkMat.setColor("Specular", ColorRGBA.Black);
|
|
||||||
|
|
||||||
Material treeTopMat = new Material(assetManager, "Common/MatDefs/Light/Lighting.j3md");
|
Material treeTopMat = new Material(assetManager, "Common/MatDefs/Light/PBRLighting.j3md");
|
||||||
treeTopMat.setBoolean("UseMaterialColors", true);
|
treeTopMat.setFloat("Metallic", 0.0f);
|
||||||
treeTopMat.setColor("Diffuse", new ColorRGBA(0.1f, 0.55f, 0.15f, 1f));
|
treeTopMat.setFloat("Roughness", 0.95f);
|
||||||
treeTopMat.setColor("Ambient", new ColorRGBA(0.05f, 0.25f, 0.07f, 1f));
|
treeTopMat.setColor("BaseColor", new ColorRGBA(0.1f, 0.55f, 0.15f, 1f));
|
||||||
treeTopMat.setColor("Specular", ColorRGBA.Black);
|
|
||||||
|
|
||||||
float[][] treeXZ = {
|
float[][] treeXZ = {
|
||||||
{12, 8}, {-15, 5}, {20, -10}, {-8, -18},
|
{12, 8}, {-15, 5}, {20, -10}, {-8, -18},
|
||||||
@@ -1216,19 +1270,15 @@ public class WorldScene extends BaseAppState {
|
|||||||
private Node buildCharacter() {
|
private Node buildCharacter() {
|
||||||
Node character = new Node("character");
|
Node character = new Node("character");
|
||||||
|
|
||||||
Material bodyMat = new Material(assetManager, "Common/MatDefs/Light/Lighting.j3md");
|
Material bodyMat = new Material(assetManager, "Common/MatDefs/Light/PBRLighting.j3md");
|
||||||
bodyMat.setBoolean("UseMaterialColors", true);
|
bodyMat.setFloat("Metallic", 0.0f);
|
||||||
bodyMat.setColor("Diffuse", new ColorRGBA(0.2f, 0.4f, 0.8f, 1f));
|
bodyMat.setFloat("Roughness", 0.7f);
|
||||||
bodyMat.setColor("Ambient", new ColorRGBA(0.1f, 0.2f, 0.4f, 1f));
|
bodyMat.setColor("BaseColor", new ColorRGBA(0.2f, 0.4f, 0.8f, 1f));
|
||||||
bodyMat.setColor("Specular", ColorRGBA.White);
|
|
||||||
bodyMat.setFloat("Shininess", 64f);
|
|
||||||
|
|
||||||
Material headMat = new Material(assetManager, "Common/MatDefs/Light/Lighting.j3md");
|
Material headMat = new Material(assetManager, "Common/MatDefs/Light/PBRLighting.j3md");
|
||||||
headMat.setBoolean("UseMaterialColors", true);
|
headMat.setFloat("Metallic", 0.0f);
|
||||||
headMat.setColor("Diffuse", new ColorRGBA(0.9f, 0.75f, 0.6f, 1f));
|
headMat.setFloat("Roughness", 0.8f);
|
||||||
headMat.setColor("Ambient", new ColorRGBA(0.45f, 0.37f, 0.3f, 1f));
|
headMat.setColor("BaseColor", new ColorRGBA(0.9f, 0.75f, 0.6f, 1f));
|
||||||
headMat.setColor("Specular", new ColorRGBA(0.2f, 0.2f, 0.2f, 1f));
|
|
||||||
headMat.setFloat("Shininess", 16f);
|
|
||||||
|
|
||||||
Geometry body = new Geometry("body", new Cylinder(8, 16, 0.35f, 1.1f, true));
|
Geometry body = new Geometry("body", new Cylinder(8, 16, 0.35f, 1.1f, true));
|
||||||
body.setMaterial(bodyMat);
|
body.setMaterial(bodyMat);
|
||||||
|
|||||||
@@ -26,12 +26,7 @@ public class DayNightState extends BaseAppState implements TimeListener {
|
|||||||
|
|
||||||
private static final Logger log = LoggerFactory.getLogger(DayNightState.class);
|
private static final Logger log = LoggerFactory.getLogger(DayNightState.class);
|
||||||
|
|
||||||
// ── Farb-Konstanten ───────────────────────────────────────────────────────
|
// Alle Beleuchtungsparameter zentral in LightingConfig.
|
||||||
|
|
||||||
private static final ColorRGBA SUN_DAY = new ColorRGBA(1.00f, 0.95f, 0.88f, 1f);
|
|
||||||
private static final ColorRGBA SUN_DAWN = new ColorRGBA(1.00f, 0.55f, 0.20f, 1f);
|
|
||||||
private static final ColorRGBA AMB_DAY = new ColorRGBA(0.08f, 0.10f, 0.16f, 1f);
|
|
||||||
private static final ColorRGBA AMB_NIGHT = new ColorRGBA(0.04f, 0.04f, 0.12f, 1f);
|
|
||||||
|
|
||||||
// ── Konfiguration ─────────────────────────────────────────────────────────
|
// ── Konfiguration ─────────────────────────────────────────────────────────
|
||||||
|
|
||||||
@@ -61,6 +56,7 @@ public class DayNightState extends BaseAppState implements TimeListener {
|
|||||||
private float caveCheckTimer = 0f;
|
private float caveCheckTimer = 0f;
|
||||||
private ColorRGBA sunBaseColor = new ColorRGBA(1, 1, 1, 1);
|
private ColorRGBA sunBaseColor = new ColorRGBA(1, 1, 1, 1);
|
||||||
private float shadowBaseIntensity = 0f;
|
private float shadowBaseIntensity = 0f;
|
||||||
|
private ColorRGBA customAmbient = new ColorRGBA();
|
||||||
|
|
||||||
private static final float CAVE_RAY_HEIGHT = 12f;
|
private static final float CAVE_RAY_HEIGHT = 12f;
|
||||||
private static final float CAVE_CHECK_INTERVAL = 0.2f;
|
private static final float CAVE_CHECK_INTERVAL = 0.2f;
|
||||||
@@ -161,6 +157,9 @@ public class DayNightState extends BaseAppState implements TimeListener {
|
|||||||
/** Gibt den Shadow-Filter zurück, damit WorldScene ihn in den FPP einhängen kann. */
|
/** Gibt den Shadow-Filter zurück, damit WorldScene ihn in den FPP einhängen kann. */
|
||||||
public DirectionalLightShadowFilter getShadowFilter() { return shadowFilter; }
|
public DirectionalLightShadowFilter getShadowFilter() { return shadowFilter; }
|
||||||
|
|
||||||
|
/** Ambient-Farbe für eigene Shader-Uniforms (AmbientColor). Kleiner als AmbientLight. */
|
||||||
|
public ColorRGBA getCustomAmbient() { return customAmbient; }
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void cleanup(Application app) {
|
protected void cleanup(Application app) {
|
||||||
dayTime.removeListener(this);
|
dayTime.removeListener(this);
|
||||||
@@ -234,17 +233,28 @@ public class DayNightState extends BaseAppState implements TimeListener {
|
|||||||
float elevation = toSun.y; // +1 = Zenit, 0 = Horizont, -1 = Nadir
|
float elevation = toSun.y; // +1 = Zenit, 0 = Horizont, -1 = Nadir
|
||||||
float elevC = FastMath.clamp(elevation, 0f, 1f);
|
float elevC = FastMath.clamp(elevation, 0f, 1f);
|
||||||
|
|
||||||
|
// Spiel vs. Editor: unterschiedliche Helligkeitswerte aus LightingConfig
|
||||||
|
ColorRGBA ambDay = withShadows ? LightingConfig.AMB_DAY : LightingConfig.EDITOR_AMB_DAY;
|
||||||
|
ColorRGBA ambNight = withShadows ? LightingConfig.AMB_NIGHT : LightingConfig.EDITOR_AMB_NIGHT;
|
||||||
|
ColorRGBA custDay = withShadows ? LightingConfig.CUSTOM_AMB_DAY : LightingConfig.EDITOR_CUSTOM_AMB_DAY;
|
||||||
|
ColorRGBA custNight = withShadows ? LightingConfig.CUSTOM_AMB_NIGHT : LightingConfig.EDITOR_CUSTOM_AMB_NIGHT;
|
||||||
|
float sunIntensity = withShadows ? LightingConfig.SUN_INTENSITY : LightingConfig.EDITOR_SUN_INTENSITY;
|
||||||
|
|
||||||
// ── Sonnenfarbe: Dämmerung (orange) → Tag (warm-weiß) — jedes Frame ──
|
// ── Sonnenfarbe: Dämmerung (orange) → Tag (warm-weiß) — jedes Frame ──
|
||||||
float dawnFactor = 1f - FastMath.clamp(elevation * 5f, 0f, 1f);
|
float dawnFactor = 1f - FastMath.clamp(elevation * LightingConfig.SUN_DAWN_SLOPE, 0f, 1f);
|
||||||
ColorRGBA sunColor = SUN_DAWN.clone().interpolateLocal(SUN_DAY, 1f - dawnFactor);
|
ColorRGBA sunColor = LightingConfig.SUN_COLOR_DAWN.clone()
|
||||||
sunBaseColor = sunColor.mult(elevC * 0.68f);
|
.interpolateLocal(LightingConfig.SUN_COLOR_DAY, 1f - dawnFactor);
|
||||||
|
sunBaseColor = sunColor.mult(elevC * sunIntensity);
|
||||||
sun.setColor(sunBaseColor.mult(1f - caveFactor));
|
sun.setColor(sunBaseColor.mult(1f - caveFactor));
|
||||||
|
|
||||||
// ── Ambient: Nacht → Tag — jedes Frame ─────────────────────────────
|
// ── Ambient: Nacht → Tag — jedes Frame ─────────────────────────────
|
||||||
float ambFactor = FastMath.clamp((elevation + 0.2f) / 0.6f, 0f, 1f);
|
float ambFactor = FastMath.clamp(
|
||||||
ambient.setColor(AMB_NIGHT.clone().interpolateLocal(AMB_DAY, ambFactor));
|
(elevation - LightingConfig.AMB_ELEV_LOW) / LightingConfig.AMB_ELEV_RANGE, 0f, 1f);
|
||||||
|
ambient.setColor(ambNight.clone().interpolateLocal(ambDay, ambFactor));
|
||||||
|
customAmbient.set(custNight.clone().interpolateLocal(custDay, ambFactor));
|
||||||
|
|
||||||
shadowBaseIntensity = FastMath.clamp(elevation * 0.8f, 0f, 0.5f);
|
shadowBaseIntensity = FastMath.clamp(
|
||||||
|
elevation * LightingConfig.SHADOW_SLOPE, 0f, LightingConfig.SHADOW_MAX);
|
||||||
|
|
||||||
// Lichtrichtung und Schatten nur 4×/Sek aktualisieren → kein Shadow-Map-Flackern
|
// Lichtrichtung und Schatten nur 4×/Sek aktualisieren → kein Shadow-Map-Flackern
|
||||||
if (sunDirTimer >= SUN_DIR_INTERVAL) {
|
if (sunDirTimer >= SUN_DIR_INTERVAL) {
|
||||||
|
|||||||
@@ -0,0 +1,176 @@
|
|||||||
|
package de.blight.game.state;
|
||||||
|
|
||||||
|
import com.jme3.math.ColorRGBA;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Zentrale Beleuchtungsparameter für den Tag/Nacht-Zyklus.
|
||||||
|
*
|
||||||
|
* Alle Farbwerte sind im linearen Farbraum (JME3-Standard).
|
||||||
|
* Werte 0–1 entsprechen dem sRGB-Bereich; Werte > 1 sind ohne
|
||||||
|
* Tone-Mapping nicht sinnvoll.
|
||||||
|
*
|
||||||
|
* Geändert werden muss nur diese Datei – alle States lesen von hier.
|
||||||
|
*/
|
||||||
|
public final class LightingConfig {
|
||||||
|
|
||||||
|
// ╔══════════════════════════════════════════════════════════════════════════╗
|
||||||
|
// ║ SONNE ║
|
||||||
|
// ╚══════════════════════════════════════════════════════════════════════════╝
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sonnenfarbe bei klarem Mittag.
|
||||||
|
* Warm-weiß (leichter Gelbstich).
|
||||||
|
* ↑ R/G/B: Sonne wird weißer / heller; ↓: kühler / trüber.
|
||||||
|
*/
|
||||||
|
public static final ColorRGBA SUN_COLOR_DAY = new ColorRGBA(1.00f, 0.95f, 0.88f, 1f);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sonnenfarbe bei Sonnenauf- und -untergang.
|
||||||
|
* Orange-rot, gesättigt. Interpoliert mit SUN_COLOR_DAY
|
||||||
|
* über die Dämmerungs-Kurve (→ SUN_DAWN_SLOPE).
|
||||||
|
*/
|
||||||
|
public static final ColorRGBA SUN_COLOR_DAWN = new ColorRGBA(1.00f, 0.55f, 0.20f, 1f);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gesamtintensität der Sonne am Mittag.
|
||||||
|
* sun.color = sunColor × elevation × SUN_INTENSITY
|
||||||
|
* ↑ heller (> 0.68 → Überbelichtung möglich); ↓ weicher.
|
||||||
|
*/
|
||||||
|
public static final float SUN_INTENSITY = 0.68f;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Steuert wie schnell die Dämmerungsfarbe (DAWN) in die Tagesfarbe (DAY)
|
||||||
|
* übergeht. elevation × SUN_DAWN_SLOPE ≥ 1 → voller Tag.
|
||||||
|
* 5 bedeutet: Übergang endet bei elevation ≈ 0.2 (ca. 12° Sonnenhöhe).
|
||||||
|
* ↑ Wert → kürzere, schärfere Dämmerung; ↓ → längere, sanftere.
|
||||||
|
*/
|
||||||
|
public static final float SUN_DAWN_SLOPE = 5f;
|
||||||
|
|
||||||
|
|
||||||
|
// ╔══════════════════════════════════════════════════════════════════════════╗
|
||||||
|
// ║ SCHATTEN ║
|
||||||
|
// ╚══════════════════════════════════════════════════════════════════════════╝
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Maximale Schattenintensität (bei Sonnenhöhe = 1.0, kein Höhlen-Faktor).
|
||||||
|
* 0 = kein Schatten; 1 = Schatten vollständig schwarz.
|
||||||
|
* Typisch: 0.4–0.6. Zu hoch → abrupte, harte Übergänge.
|
||||||
|
*/
|
||||||
|
public static final float SHADOW_MAX = 0.5f;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Steigung der Schattenintensitäts-Kurve (abhängig von Sonnenhöhe).
|
||||||
|
* shadowIntensity = clamp(elevation × SHADOW_SLOPE, 0, SHADOW_MAX)
|
||||||
|
* ↑ Schatten werden schneller dunkler wenn Sonne aufgeht;
|
||||||
|
* ↓ Schatten bleiben länger schwach (z. B. morgens flacher).
|
||||||
|
*/
|
||||||
|
public static final float SHADOW_SLOPE = 0.8f;
|
||||||
|
|
||||||
|
|
||||||
|
// ╔══════════════════════════════════════════════════════════════════════════╗
|
||||||
|
// ║ AMBIENT-LICHT – LightProbe-Multiplikator (PBR-IBL) ║
|
||||||
|
// ╠══════════════════════════════════════════════════════════════════════════╣
|
||||||
|
// ║ Wirkt NUR auf JME3-PBR-Materialien MIT fertigem LightProbe. ║
|
||||||
|
// ║ Terrain-, Baum- und Voxel-Shader sind UNBERÜHRT (→ CUSTOM_AMB_*). ║
|
||||||
|
// ╚══════════════════════════════════════════════════════════════════════════╝
|
||||||
|
|
||||||
|
/**
|
||||||
|
* AmbientLight-Farbe am Mittag.
|
||||||
|
* Skaliert den LightProbe-IBL: envLight = probeIBL × AMB_DAY.
|
||||||
|
* Hoch halten (≥ 0.7) damit PBR-Reflexionen sichtbar bleiben.
|
||||||
|
* Hat keinen Effekt solange kein LightProbe in der Szene ist.
|
||||||
|
*/
|
||||||
|
public static final ColorRGBA AMB_DAY = new ColorRGBA(0.90f, 0.90f, 0.90f, 1f);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* AmbientLight-Farbe in der Nacht (LightProbe-Multiplikator).
|
||||||
|
* Leichter Blaustich simuliert Mondlicht-Reflexionen auf PBR-Flächen.
|
||||||
|
*/
|
||||||
|
public static final ColorRGBA AMB_NIGHT = new ColorRGBA(0.10f, 0.10f, 0.25f, 1f);
|
||||||
|
|
||||||
|
|
||||||
|
// ╔══════════════════════════════════════════════════════════════════════════╗
|
||||||
|
// ║ CUSTOM-AMBIENT – Terrain / Bäume / Voxel / PBR-Emissive ║
|
||||||
|
// ╠══════════════════════════════════════════════════════════════════════════╣
|
||||||
|
// ║ Direkt-additiv → NIEDRIG halten. ║
|
||||||
|
// ║ Betrifft: TerrainArray.frag, Tree.frag, Voxel.frag via AmbientColor- ║
|
||||||
|
// ║ Uniform; Tripo/PBR-Objekte via Emissive-Parameter (EmissivePower=1). ║
|
||||||
|
// ╚══════════════════════════════════════════════════════════════════════════╝
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Ambient-Farbe am Mittag für Schatten-Bereiche.
|
||||||
|
* ↑ erhöhen: Schatten heller (lesbarer), beleuchtete Flächen leicht ausgewaschen.
|
||||||
|
* ↓ senken: mehr Kontrast, tiefere Schatten (wirkt moodiger/dramatischer).
|
||||||
|
* Empfehlung: 0.03–0.10 pro Kanal.
|
||||||
|
*/
|
||||||
|
public static final ColorRGBA CUSTOM_AMB_DAY = new ColorRGBA(0.04f, 0.05f, 0.08f, 1f);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Ambient-Farbe in der Nacht.
|
||||||
|
* Blaustich = dezentes Mondlicht / Sternenlicht auf Oberflächen.
|
||||||
|
* Zu hoch → Nacht wirkt grau statt dunkel.
|
||||||
|
* Empfehlung: 0.01–0.04 pro Kanal, Blau-Kanal darf höher sein.
|
||||||
|
*/
|
||||||
|
public static final ColorRGBA CUSTOM_AMB_NIGHT = new ColorRGBA(0.025f, 0.025f, 0.06f, 1f);
|
||||||
|
|
||||||
|
|
||||||
|
// ╔══════════════════════════════════════════════════════════════════════════╗
|
||||||
|
// ║ ÜBERGANGS-KURVEN ║
|
||||||
|
// ╚══════════════════════════════════════════════════════════════════════════╝
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Untere Sonnenhöhe für den Tag/Nacht-Übergang der Ambient-Werte.
|
||||||
|
* Bei elevation ≤ AMB_ELEV_LOW → 100 % Nacht-Ambient.
|
||||||
|
* Werte: -1 (Mitternacht) … 0 (Horizont) … +1 (Zenit).
|
||||||
|
*/
|
||||||
|
public static final float AMB_ELEV_LOW = -0.2f;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Breite des Übergangs-Bands (Elevation-Einheiten).
|
||||||
|
* Bei elevation ≥ AMB_ELEV_LOW + AMB_ELEV_RANGE → 100 % Tag-Ambient.
|
||||||
|
* Aktuell: voller Tag ab elevation = -0.2 + 0.6 = 0.4 (≈ 24° Sonnenhöhe).
|
||||||
|
* ↑ verbreitern → längere Dämmerungsphase; ↓ verkürzen → abrupter Übergang.
|
||||||
|
*/
|
||||||
|
public static final float AMB_ELEV_RANGE = 0.6f;
|
||||||
|
|
||||||
|
// ╔══════════════════════════════════════════════════════════════════════════╗
|
||||||
|
// ║ EDITOR – deutlich heller als Spiel für gute Arbeits-Sichtbarkeit ║
|
||||||
|
// ╠══════════════════════════════════════════════════════════════════════════╣
|
||||||
|
// ║ Aktiv wenn DayNightState mit withShadows=false erzeugt wird ║
|
||||||
|
// ║ (Editor-Modus). Spiel-Werte bleiben unverändert. ║
|
||||||
|
// ╚══════════════════════════════════════════════════════════════════════════╝
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sonnen-Intensität im Editor.
|
||||||
|
* Höher als im Spiel damit Geometrien auch bei tiefer Sonne gut erkennbar sind.
|
||||||
|
*/
|
||||||
|
public static final float EDITOR_SUN_INTENSITY = 0.90f;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* LightProbe-Multiplikator am Mittag im Editor (AmbientLight).
|
||||||
|
* Gleich wie im Spiel – der LightProbe liefert ohnehin die meiste IBL-Helligkeit.
|
||||||
|
*/
|
||||||
|
public static final ColorRGBA EDITOR_AMB_DAY = new ColorRGBA(0.90f, 0.90f, 0.90f, 1f);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* LightProbe-Multiplikator in der Nacht im Editor.
|
||||||
|
* Deutlich heller als im Spiel damit PBR-Objekte auch bei Nachteinstellung sichtbar bleiben.
|
||||||
|
*/
|
||||||
|
public static final ColorRGBA EDITOR_AMB_NIGHT = new ColorRGBA(0.40f, 0.40f, 0.55f, 1f);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Custom-Ambient am Mittag im Editor (Terrain, Bäume, Voxel, PBR-Emissive).
|
||||||
|
* Ca. 6× heller als im Spiel: Schatten-Bereiche klar erkennbar beim Modellieren.
|
||||||
|
* ↑ erhöhen → noch heller / flacher; ↓ senken → mehr Kontrast.
|
||||||
|
*/
|
||||||
|
public static final ColorRGBA EDITOR_CUSTOM_AMB_DAY = new ColorRGBA(0.25f, 0.25f, 0.28f, 1f);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Custom-Ambient in der Nacht im Editor.
|
||||||
|
* Auch bei Nacht-Einstellung (0:00 Uhr) bleibt die Szene gut arbeitbar.
|
||||||
|
* Zu hoch → kein spürbarer Tag/Nacht-Unterschied mehr im Editor.
|
||||||
|
*/
|
||||||
|
public static final ColorRGBA EDITOR_CUSTOM_AMB_NIGHT = new ColorRGBA(0.18f, 0.18f, 0.25f, 1f);
|
||||||
|
|
||||||
|
private LightingConfig() {}
|
||||||
|
}
|
||||||
@@ -72,7 +72,7 @@ public class SculptedMeshState extends BaseAppState {
|
|||||||
if (dns == null || dns.getSunLight() == null) return;
|
if (dns == null || dns.getSunLight() == null) return;
|
||||||
material.setVector3("LightDir", dns.getSunDirection().negate());
|
material.setVector3("LightDir", dns.getSunDirection().negate());
|
||||||
ColorRGBA sc = dns.getSunLight().getColor();
|
ColorRGBA sc = dns.getSunLight().getColor();
|
||||||
ColorRGBA ac = dns.getAmbientLight().getColor();
|
ColorRGBA ac = dns.getCustomAmbient();
|
||||||
material.setVector3("SunColor", new Vector3f(sc.r, sc.g, sc.b));
|
material.setVector3("SunColor", new Vector3f(sc.r, sc.g, sc.b));
|
||||||
material.setVector3("AmbientColor", new Vector3f(ac.r, ac.g, ac.b));
|
material.setVector3("AmbientColor", new Vector3f(ac.r, ac.g, ac.b));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -102,11 +102,10 @@ public class StoneWorldState extends BaseAppState {
|
|||||||
// ── Materialien ───────────────────────────────────────────────────────────
|
// ── Materialien ───────────────────────────────────────────────────────────
|
||||||
|
|
||||||
private Material buildDefaultMat() {
|
private Material buildDefaultMat() {
|
||||||
Material m = new Material(assets, "Common/MatDefs/Light/Lighting.j3md");
|
Material m = new Material(assets, "Common/MatDefs/Light/PBRLighting.j3md");
|
||||||
m.setBoolean("UseMaterialColors", true);
|
m.setFloat("Metallic", 0.0f);
|
||||||
m.setColor("Diffuse", new ColorRGBA(0.55f, 0.52f, 0.48f, 1f));
|
m.setFloat("Roughness", 0.85f);
|
||||||
m.setColor("Ambient", new ColorRGBA(0.15f, 0.14f, 0.13f, 1f));
|
m.setColor("BaseColor", new ColorRGBA(0.55f, 0.52f, 0.48f, 1f));
|
||||||
m.setColor("Specular", ColorRGBA.Black);
|
|
||||||
return m;
|
return m;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -116,12 +115,10 @@ public class StoneWorldState extends BaseAppState {
|
|||||||
String p = (paths != null && i < paths.length && paths[i] != null) ? paths[i] : "";
|
String p = (paths != null && i < paths.length && paths[i] != null) ? paths[i] : "";
|
||||||
if (!p.isEmpty()) {
|
if (!p.isEmpty()) {
|
||||||
try {
|
try {
|
||||||
Material m = new Material(assets, "Common/MatDefs/Light/Lighting.j3md");
|
Material m = new Material(assets, "Common/MatDefs/Light/PBRLighting.j3md");
|
||||||
m.setTexture("DiffuseMap", assets.loadTexture(p));
|
m.setFloat("Metallic", 0.0f);
|
||||||
m.setColor("Diffuse", ColorRGBA.White);
|
m.setFloat("Roughness", 0.85f);
|
||||||
m.setColor("Ambient", new ColorRGBA(0.2f, 0.2f, 0.2f, 1f));
|
m.setTexture("BaseColorMap", assets.loadTexture(p));
|
||||||
m.setColor("Specular", ColorRGBA.Black);
|
|
||||||
m.setBoolean("UseMaterialColors", true);
|
|
||||||
mats[i] = m;
|
mats[i] = m;
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
log.warn("[StoneWorld] Textur nicht ladbar: {}", p);
|
log.warn("[StoneWorld] Textur nicht ladbar: {}", p);
|
||||||
|
|||||||
@@ -89,8 +89,9 @@ public class WorldNpcsState extends BaseAppState {
|
|||||||
private final List<SpawnedNpc> spawned = new ArrayList<>();
|
private final List<SpawnedNpc> spawned = new ArrayList<>();
|
||||||
|
|
||||||
private static class SpawnedNpc {
|
private static class SpawnedNpc {
|
||||||
final NPC npc;
|
final NPC npc;
|
||||||
final Spatial visual;
|
final Spatial visual;
|
||||||
|
final List<Material> pbrMaterials = new ArrayList<>();
|
||||||
float worldX, worldZ;
|
float worldX, worldZ;
|
||||||
AnimationAction currentAction = null;
|
AnimationAction currentAction = null;
|
||||||
|
|
||||||
@@ -260,6 +261,16 @@ public class WorldNpcsState extends BaseAppState {
|
|||||||
}
|
}
|
||||||
spawned.removeAll(toRemove);
|
spawned.removeAll(toRemove);
|
||||||
|
|
||||||
|
// PBR-Emissive der verbleibenden NPCs mit aktuellem Ambient aktualisieren
|
||||||
|
if (dayNight != null) {
|
||||||
|
com.jme3.math.ColorRGBA ac = dayNight.getCustomAmbient();
|
||||||
|
for (SpawnedNpc s : spawned) {
|
||||||
|
for (Material mat : s.pbrMaterials) {
|
||||||
|
mat.setColor("Emissive", new com.jme3.math.ColorRGBA(ac.r, ac.g, ac.b, 1f));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// IDs der bereits gespawnten NPCs für schnelle Prüfung
|
// IDs der bereits gespawnten NPCs für schnelle Prüfung
|
||||||
Set<String> spawnedIds = new HashSet<>();
|
Set<String> spawnedIds = new HashSet<>();
|
||||||
for (SpawnedNpc s : spawned) {
|
for (SpawnedNpc s : spawned) {
|
||||||
@@ -277,6 +288,13 @@ public class WorldNpcsState extends BaseAppState {
|
|||||||
vis.setLocalTranslation(pos);
|
vis.setLocalTranslation(pos);
|
||||||
npcsRoot.attachChild(vis);
|
npcsRoot.attachChild(vis);
|
||||||
SpawnedNpc s = new SpawnedNpc(npc, vis, pos.x, pos.z);
|
SpawnedNpc s = new SpawnedNpc(npc, vis, pos.x, pos.z);
|
||||||
|
de.blight.game.scene.WorldScene.collectPbrMaterials(vis, s.pbrMaterials);
|
||||||
|
if (dayNight != null && !s.pbrMaterials.isEmpty()) {
|
||||||
|
com.jme3.math.ColorRGBA ac = dayNight.getCustomAmbient();
|
||||||
|
for (Material mat : s.pbrMaterials) {
|
||||||
|
mat.setColor("Emissive", new com.jme3.math.ColorRGBA(ac.r, ac.g, ac.b, 1f));
|
||||||
|
}
|
||||||
|
}
|
||||||
spawned.add(s);
|
spawned.add(s);
|
||||||
playNpcAction(s, activityActionFor(npc, currentHour));
|
playNpcAction(s, activityActionFor(npc, currentHour));
|
||||||
log.debug("[WorldNpcs] NPC '{}' gespawnt bei ({}, {})", npc.getCharacterId(), pos.x, pos.z);
|
log.debug("[WorldNpcs] NPC '{}' gespawnt bei ({}, {})", npc.getCharacterId(), pos.x, pos.z);
|
||||||
|
|||||||
@@ -36,6 +36,8 @@ public class WorldObjectsState extends BaseAppState {
|
|||||||
private BulletAppState bulletAppState;
|
private BulletAppState bulletAppState;
|
||||||
private final List<Material> sceneLitMaterials = new ArrayList<>();
|
private final List<Material> sceneLitMaterials = new ArrayList<>();
|
||||||
private final List<Material> windMaterials = new ArrayList<>();
|
private final List<Material> windMaterials = new ArrayList<>();
|
||||||
|
private final List<Material> pbrMaterials = new ArrayList<>();
|
||||||
|
private float debugTimer = 0f;
|
||||||
|
|
||||||
/** RigidBodyControl pro Interactable-ID, damit Kollision während Animationen deaktiviert werden kann. */
|
/** RigidBodyControl pro Interactable-ID, damit Kollision während Animationen deaktiviert werden kann. */
|
||||||
private final Map<String, RigidBodyControl> interactableRbcs = new HashMap<>();
|
private final Map<String, RigidBodyControl> interactableRbcs = new HashMap<>();
|
||||||
@@ -110,7 +112,8 @@ public class WorldObjectsState extends BaseAppState {
|
|||||||
failed++;
|
failed++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
log.info("[WorldObjects] {} geladen, {} fehlgeschlagen.", loaded, failed);
|
log.info("[WorldObjects] {} geladen, {} fehlgeschlagen. sceneLitMaterials={}, windMaterials={}, pbrMaterials={}",
|
||||||
|
loaded, failed, sceneLitMaterials.size(), windMaterials.size(), pbrMaterials.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override protected void cleanup(Application app) {}
|
@Override protected void cleanup(Application app) {}
|
||||||
@@ -118,12 +121,12 @@ public class WorldObjectsState extends BaseAppState {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void update(float tpf) {
|
public void update(float tpf) {
|
||||||
if (!sceneLitMaterials.isEmpty()) {
|
if (!sceneLitMaterials.isEmpty() || !pbrMaterials.isEmpty()) {
|
||||||
DayNightState dns = getApplication().getStateManager().getState(DayNightState.class);
|
DayNightState dns = getApplication().getStateManager().getState(DayNightState.class);
|
||||||
if (dns != null && dns.getSunLight() != null) {
|
if (dns != null && dns.getSunLight() != null) {
|
||||||
Vector3f lightDir = dns.getSunDirection().negate();
|
Vector3f lightDir = dns.getSunDirection().negate();
|
||||||
ColorRGBA sc = dns.getSunLight().getColor();
|
ColorRGBA sc = dns.getSunLight().getColor();
|
||||||
ColorRGBA ac = dns.getAmbientLight().getColor();
|
ColorRGBA ac = dns.getCustomAmbient();
|
||||||
Vector3f sunVec = new Vector3f(sc.r, sc.g, sc.b);
|
Vector3f sunVec = new Vector3f(sc.r, sc.g, sc.b);
|
||||||
Vector3f ambVec = new Vector3f(ac.r, ac.g, ac.b);
|
Vector3f ambVec = new Vector3f(ac.r, ac.g, ac.b);
|
||||||
for (Material mat : sceneLitMaterials) {
|
for (Material mat : sceneLitMaterials) {
|
||||||
@@ -131,6 +134,24 @@ public class WorldObjectsState extends BaseAppState {
|
|||||||
mat.setVector3("SunColor", sunVec);
|
mat.setVector3("SunColor", sunVec);
|
||||||
mat.setVector3("AmbientColor", ambVec);
|
mat.setVector3("AmbientColor", ambVec);
|
||||||
}
|
}
|
||||||
|
// PBR-Ambient via Emissive: ohne LightProbe liefert JME3-PBR kein IBL.
|
||||||
|
// EmissivePower=1 verhindert, dass 0.08 zu 0.08³=0.0005 zusammenbricht.
|
||||||
|
for (Material mat : pbrMaterials) {
|
||||||
|
mat.setColor("Emissive", new ColorRGBA(ac.r, ac.g, ac.b, 1f));
|
||||||
|
}
|
||||||
|
debugTimer += tpf;
|
||||||
|
if (debugTimer >= 5f) {
|
||||||
|
debugTimer = 0f;
|
||||||
|
log.info("[WorldObjects] SunColor=({}) AmbColor=({})",
|
||||||
|
String.format("%.3f,%.3f,%.3f", sunVec.x, sunVec.y, sunVec.z),
|
||||||
|
String.format("%.3f,%.3f,%.3f", ambVec.x, ambVec.y, ambVec.z));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
debugTimer += tpf;
|
||||||
|
if (debugTimer >= 5f) {
|
||||||
|
debugTimer = 0f;
|
||||||
|
log.warn("[WorldObjects] DayNightState nicht gefunden oder sun==null! dns={}", dns);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -164,7 +185,7 @@ public class WorldObjectsState extends BaseAppState {
|
|||||||
applyMaterial(spatial, m);
|
applyMaterial(spatial, m);
|
||||||
} else {
|
} else {
|
||||||
spatial = assets.loadModel(path);
|
spatial = assets.loadModel(path);
|
||||||
convertUnshadedToLighting(spatial);
|
convertUnshadedToPbr(spatial);
|
||||||
collectSceneLitMaterials(spatial);
|
collectSceneLitMaterials(spatial);
|
||||||
}
|
}
|
||||||
spatial.setName("obj_" + path);
|
spatial.setName("obj_" + path);
|
||||||
@@ -197,7 +218,7 @@ public class WorldObjectsState extends BaseAppState {
|
|||||||
m.lod1Path(), m.lod2Path(),
|
m.lod1Path(), m.lod2Path(),
|
||||||
m.lod1Distance(), m.lod2Distance(), m.cullDistance());
|
m.lod1Distance(), m.lod2Distance(), m.cullDistance());
|
||||||
ctrl.setLodLoadCallback(lod -> {
|
ctrl.setLodLoadCallback(lod -> {
|
||||||
convertUnshadedToLighting(lod);
|
convertUnshadedToPbr(lod);
|
||||||
collectSceneLitMaterials(lod);
|
collectSceneLitMaterials(lod);
|
||||||
});
|
});
|
||||||
lodRoot.addControl(ctrl);
|
lodRoot.addControl(ctrl);
|
||||||
@@ -221,11 +242,7 @@ public class WorldObjectsState extends BaseAppState {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
private void convertUnshadedToPbr(Spatial spatial) {
|
||||||
* Ersetzt Unshaded-Materialien in geladenen j3o-Modellen durch Lighting.j3md,
|
|
||||||
* damit diese auf den Tag/Nacht-Zyklus reagieren.
|
|
||||||
*/
|
|
||||||
private void convertUnshadedToLighting(Spatial spatial) {
|
|
||||||
if (spatial instanceof Geometry geo) {
|
if (spatial instanceof Geometry geo) {
|
||||||
Material mat = geo.getMaterial();
|
Material mat = geo.getMaterial();
|
||||||
if (mat == null) return;
|
if (mat == null) return;
|
||||||
@@ -235,25 +252,24 @@ public class WorldObjectsState extends BaseAppState {
|
|||||||
MatParam color = mat.getParam("Color");
|
MatParam color = mat.getParam("Color");
|
||||||
RenderState origRS = mat.getAdditionalRenderState();
|
RenderState origRS = mat.getAdditionalRenderState();
|
||||||
|
|
||||||
Material litMat = new Material(assets, "Common/MatDefs/Light/Lighting.j3md");
|
Material pbrMat = new Material(assets, "Common/MatDefs/Light/PBRLighting.j3md");
|
||||||
litMat.setBoolean("UseMaterialColors", false);
|
pbrMat.setFloat("Metallic", 0.0f);
|
||||||
|
pbrMat.setFloat("Roughness", 0.85f);
|
||||||
|
|
||||||
if (colorMap != null && colorMap.getValue() instanceof Texture t) {
|
if (colorMap != null && colorMap.getValue() instanceof Texture t) {
|
||||||
litMat.setTexture("DiffuseMap", t);
|
pbrMat.setTexture("BaseColorMap", t);
|
||||||
} else if (color != null && color.getValue() instanceof ColorRGBA c) {
|
} else if (color != null && color.getValue() instanceof ColorRGBA c) {
|
||||||
litMat.setBoolean("UseMaterialColors", true);
|
pbrMat.setColor("BaseColor", new ColorRGBA(c.r, c.g, c.b, 1f));
|
||||||
litMat.setColor("Diffuse", new ColorRGBA(c.r, c.g, c.b, 1f));
|
|
||||||
litMat.setColor("Ambient", new ColorRGBA(c.r * 0.3f, c.g * 0.3f, c.b * 0.3f, 1f));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
RenderState rs = litMat.getAdditionalRenderState();
|
RenderState rs = pbrMat.getAdditionalRenderState();
|
||||||
rs.setBlendMode(origRS.getBlendMode());
|
rs.setBlendMode(origRS.getBlendMode());
|
||||||
rs.setFaceCullMode(origRS.getFaceCullMode());
|
rs.setFaceCullMode(origRS.getFaceCullMode());
|
||||||
|
|
||||||
geo.setMaterial(litMat);
|
geo.setMaterial(pbrMat);
|
||||||
} else if (spatial instanceof Node node) {
|
} else if (spatial instanceof Node node) {
|
||||||
for (Spatial child : new ArrayList<>(node.getChildren())) {
|
for (Spatial child : new ArrayList<>(node.getChildren())) {
|
||||||
convertUnshadedToLighting(child);
|
convertUnshadedToPbr(child);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -264,9 +280,26 @@ public class WorldObjectsState extends BaseAppState {
|
|||||||
if (mat == null) return;
|
if (mat == null) return;
|
||||||
String name = mat.getMaterialDef().getName();
|
String name = mat.getMaterialDef().getName();
|
||||||
if ("Tree".equals(name) || "TreeLeaf".equals(name)) {
|
if ("Tree".equals(name) || "TreeLeaf".equals(name)) {
|
||||||
|
// j3o-Loading setzt keine j3md-Defaults → Uniforms explizit setzen
|
||||||
|
// (Werte für Mittag; werden sofort in update() durch DayNightState überschrieben)
|
||||||
|
mat.setVector3("SunColor", new Vector3f(1.00f, 0.95f, 0.88f));
|
||||||
|
mat.setVector3("AmbientColor", new Vector3f(0.08f, 0.10f, 0.16f));
|
||||||
|
mat.setVector3("LightDir", new Vector3f(0f, -1f, 0f));
|
||||||
sceneLitMaterials.add(mat);
|
sceneLitMaterials.add(mat);
|
||||||
} else if ("Fern".equals(name)) {
|
} else if ("Fern".equals(name)) {
|
||||||
windMaterials.add(mat);
|
windMaterials.add(mat);
|
||||||
|
} else if ("PBRLighting".equals(name)) {
|
||||||
|
// Emissive = Ambient-Ersatz: JME3-PBR ignoriert AmbientLight ohne LightProbe.
|
||||||
|
// EmissivePower=1 nötig – Standard ist 3.0, was 0.08 → 0.0005 zerstört.
|
||||||
|
mat.setFloat("EmissivePower", 1f);
|
||||||
|
mat.setFloat("EmissiveIntensity", 1f);
|
||||||
|
mat.setColor("Emissive", new ColorRGBA(0.08f, 0.10f, 0.16f, 1f));
|
||||||
|
pbrMaterials.add(mat);
|
||||||
|
} else if ("Lighting".equals(name)) {
|
||||||
|
// Phong-Material: Ambient-Multiplikator auf Weiß setzen, damit g_AmbientLightColor voll wirkt.
|
||||||
|
mat.setColor("Ambient", ColorRGBA.White.clone());
|
||||||
|
} else {
|
||||||
|
log.info("[WorldObjects] Material-Def '{}' an '{}' – unbekannt, übersprungen.", name, geo.getName());
|
||||||
}
|
}
|
||||||
} else if (spatial instanceof Node node) {
|
} else if (spatial instanceof Node node) {
|
||||||
for (Spatial child : node.getChildren()) {
|
for (Spatial child : node.getChildren()) {
|
||||||
@@ -286,12 +319,13 @@ public class WorldObjectsState extends BaseAppState {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (hasTex || hasNmap) {
|
if (hasTex || hasNmap) {
|
||||||
Material mat = new Material(assets, "Common/MatDefs/Light/Lighting.j3md");
|
Material mat = new Material(assets, "Common/MatDefs/Light/PBRLighting.j3md");
|
||||||
mat.setBoolean("UseMaterialColors", false);
|
mat.setFloat("Metallic", 0.0f);
|
||||||
|
mat.setFloat("Roughness", 0.85f);
|
||||||
if (hasTex) {
|
if (hasTex) {
|
||||||
Texture t = assets.loadTexture(m.texturePath());
|
Texture t = assets.loadTexture(m.texturePath());
|
||||||
t.setWrap(Texture.WrapMode.Repeat);
|
t.setWrap(Texture.WrapMode.Repeat);
|
||||||
mat.setTexture("DiffuseMap", t);
|
mat.setTexture("BaseColorMap", t);
|
||||||
}
|
}
|
||||||
if (hasNmap) {
|
if (hasNmap) {
|
||||||
Texture n = assets.loadTexture(m.normalMapPath());
|
Texture n = assets.loadTexture(m.normalMapPath());
|
||||||
|
|||||||
Binary file not shown.
@@ -3,3 +3,5 @@ Models/imported/wooden+cabin+3d+model.j3o 105.61634 4.85395 58.69108 0.00000 1.0
|
|||||||
Models/imported/bank1.j3o 106.96240 2.89958 70.01086 0.00000 1.00000 0.00000 0.00000 false true true 30.00000 80.00000 120.00000 BENCH 5be97ffb-e413-42e5-9815-9d14d1e3b93f
|
Models/imported/bank1.j3o 106.96240 2.89958 70.01086 0.00000 1.00000 0.00000 0.00000 false true true 30.00000 80.00000 120.00000 BENCH 5be97ffb-e413-42e5-9815-9d14d1e3b93f
|
||||||
Models/trees/pine/medium/pine_medium_20260706_190947.j3o -6.42357 1.22971 -1318.06396 5.19824 1.00000 0.00000 0.00000 false true true 30.00000 80.00000 120.00000
|
Models/trees/pine/medium/pine_medium_20260706_190947.j3o -6.42357 1.22971 -1318.06396 5.19824 1.00000 0.00000 0.00000 false true true 30.00000 80.00000 120.00000
|
||||||
Models/trees/pine/medium/pine_medium_20260706_190953.j3o -17.84356 1.24567 -1316.45410 0.26793 1.00000 0.00000 0.00000 false true true 30.00000 80.00000 120.00000
|
Models/trees/pine/medium/pine_medium_20260706_190953.j3o -17.84356 1.24567 -1316.45410 0.26793 1.00000 0.00000 0.00000 false true true 30.00000 80.00000 120.00000
|
||||||
|
Models/plants/misc/heliconia+plant+3d+model.j3o -7.48228 1.22979 -1320.31714 0.00000 1.00000 0.00000 0.00000 false true true 30.00000 80.00000 120.00000
|
||||||
|
Models/plants/misc/kaktusfeige.j3o -6.18754 1.22995 -1320.34875 0.00000 2.50000 0.00000 0.00000 true true true 30.00000 80.00000 120.00000
|
||||||
|
|||||||
Reference in New Issue
Block a user