I’ve run through this and it all works very nicely. I’ll put the code for the java and shaders at the bottom of this post in case anyone else is trying to do this. I’ve also put in in a respository for the full working example Bitbucket. And I’ve done a more in the context of my game write up here https://richardonsoftware.wordpress.com/night-and-day-done-not-stupidly/
package mygame;
import com.jme3.app.SimpleApplication;
import com.jme3.material.Material;
import com.jme3.math.Vector2f;
import com.jme3.math.Vector3f;
import com.jme3.math.Vector4f;
import com.jme3.scene.Geometry;
import com.jme3.scene.Mesh;
import com.jme3.scene.VertexBuffer;
import com.jme3.shader.VarType;
import com.jme3.util.BufferUtils;
public class Main extends SimpleApplication {
private Material mat;
private float dayNightPeriod = 4;
private float time;
public static void main(String[] args) {
Main app = new Main();
app.start();
}
@Override
public void simpleInitApp() {
//the points in 3d space where the geometry will be
Vector3f [] vertices = new Vector3f[8];
//one square
vertices[0] = new Vector3f(0,0,0);
vertices[1] = new Vector3f(3,0,0);
vertices[2] = new Vector3f(0,3,0);
vertices[3] = new Vector3f(3,3,0);
//a second square
vertices[4] = new Vector3f(3,0,0);
vertices[5] = new Vector3f(6,0,0);
vertices[6] = new Vector3f(3,3,0);
vertices[7] = new Vector3f(6,3,0);
//combine those vetexes into triangles
int [] indexes = {
//first square
2,0,1,1,3,2,
//second square
6,4,5,5,7,6
};
//we're not using a texture but if we were this would define whtich parts of the image are where
Vector2f[] texCoord = new Vector2f[8];
texCoord[0] = new Vector2f(0,0);
texCoord[1] = new Vector2f(1,0);
texCoord[2] = new Vector2f(0,1);
texCoord[3] = new Vector2f(1,1);
texCoord[4] = new Vector2f(0,0);
texCoord[5] = new Vector2f(1,0);
texCoord[6] = new Vector2f(0,1);
texCoord[7] = new Vector2f(1,1);
//Set the first colour buffer, this will be the sunlight color
Vector4f[] sunlightColour = new Vector4f[8]; //these are Vector4f because we have a red, green, blue and transparency per vertex
//both the squares at full brightness in sunlight
sunlightColour[0] = new Vector4f(1,1,1,1);
sunlightColour[1] = new Vector4f(1,1,1,1);
sunlightColour[2] = new Vector4f(1,1,1,1);
sunlightColour[3] = new Vector4f(1,1,1,1);
sunlightColour[4] = new Vector4f(1,1,1,1);
sunlightColour[5] = new Vector4f(1,1,1,1);
sunlightColour[6] = new Vector4f(1,1,1,1);
sunlightColour[7] = new Vector4f(1,1,1,1);
Vector4f[] sourceLightColour = new Vector4f[8];
sourceLightColour[0] = new Vector4f(0.9f,0.9f,0.9f,1); //first square at 90% brightness in sourcelight
sourceLightColour[1] = new Vector4f(0.9f,0.9f,0.9f,1);
sourceLightColour[2] = new Vector4f(0.9f,0.9f,0.9f,1);
sourceLightColour[3] = new Vector4f(0.9f,0.9f,0.9f,1);
sourceLightColour[4] = new Vector4f(0.3f,0.3f,0.3f,1);//second square at 30% brightness in sourcelight
sourceLightColour[5] = new Vector4f(0.3f,0.3f,0.3f,1);
sourceLightColour[6] = new Vector4f(0.3f,0.3f,0.3f,1);
sourceLightColour[7] = new Vector4f(0.3f,0.3f,0.3f,1);
//now we have all the data we create the mesh
//for more details https://jmonkeyengine.github.io/wiki/jme3/advanced/custom_meshes.html
Mesh mesh = new Mesh();
mesh.setBuffer(VertexBuffer.Type.Position, 3, BufferUtils.createFloatBuffer(vertices));
mesh.setBuffer(VertexBuffer.Type.Index, 3, BufferUtils.createIntBuffer(indexes));
mesh.setBuffer(VertexBuffer.Type.TexCoord, 2, BufferUtils.createFloatBuffer(texCoord));
mesh.setBuffer(VertexBuffer.Type.Color, 4, BufferUtils.createFloatBuffer(sunlightColour));
//we're using the conventional Color buffer for sunlight and using one of the (usually) unused TexCoord5 to hold the source light
mesh.setBuffer(VertexBuffer.Type.TexCoord5, 4, BufferUtils.createFloatBuffer(sourceLightColour));
mesh.updateBound();
Geometry geom = new Geometry("mesh", mesh);
mat = new Material(assetManager, "MatDefs/RepeatingUnshaded.j3md");
//mat = new Material(assetManager,"Common/MatDefs/Misc/Unshaded.j3md");
mat.setBoolean("VertexColor", true);
geom.setMaterial(mat);
rootNode.attachChild(geom);
}
@Override
public void simpleUpdate(float tpf) {
time += tpf;
if (time>dayNightPeriod){
time = 0;
}
mat.setParam("SunlightIntensity", VarType.Float,time/dayNightPeriod);
}
}
Vertex shader
#import "Common/ShaderLib/GLSLCompat.glsllib"
#import "Common/ShaderLib/Skinning.glsllib"
#import "Common/ShaderLib/Instancing.glsllib"
attribute vec3 inPosition;
#if defined(HAS_COLORMAP) || (defined(HAS_LIGHTMAP) && !defined(SEPARATE_TEXCOORD))
#define NEED_TEXCOORD1
#endif
attribute vec2 inTexCoord;
attribute vec2 inTexCoord2;
attribute vec4 inColor;
varying vec2 texCoord1;
varying vec2 texCoord2;
attribute vec4 inTexCoord5; //!changed! this is the source light that is passed to us
varying vec4 texCoord5; //!changed! and this is how we'll pass it through to the fragment shader
varying vec4 vertColor;
void main(){
#ifdef NEED_TEXCOORD1
texCoord1 = inTexCoord;
#endif
#ifdef SEPARATE_TEXCOORD
texCoord2 = inTexCoord2;
#endif
#ifdef HAS_VERTEXCOLOR
vertColor = inColor;
#endif
vec4 modelSpacePos = vec4(inPosition, 1.0);
#ifdef NUM_BONES
Skinning_Compute(modelSpacePos);
#endif
texCoord5 = inTexCoord5; //!changed! its the fragment shader that wants this so we just pass it on
gl_Position = TransformWorldViewProjection(modelSpacePos);
}
Fragment shader
#import "Common/ShaderLib/GLSLCompat.glsllib"
#if defined(HAS_GLOWMAP) || defined(HAS_COLORMAP) || (defined(HAS_LIGHTMAP) && !defined(SEPARATE_TEXCOORD))
#define NEED_TEXCOORD1
#endif
#if defined(DISCARD_ALPHA)
uniform float m_AlphaDiscardThreshold;
#endif
uniform float m_SunlightIntensity; //!changed!
uniform vec4 m_Color;
uniform sampler2D m_ColorMap;
uniform sampler2D m_LightMap;
varying vec2 texCoord1;
varying vec2 texCoord2;
varying vec4 vertColor;
varying vec4 texCoord5; //!changed!this is the source color passed through to us
void main(){
vec4 color = vec4(1.0);
#ifdef HAS_COLORMAP
color *= texture2D(m_ColorMap, texCoord1);
#endif
#ifdef HAS_VERTEXCOLOR
//!changed! This is the actual combining of the two colours
color.x *= max(vertColor.x * m_SunlightIntensity,texCoord5.x);
color.y *= max(vertColor.y * m_SunlightIntensity,texCoord5.y);
color.z *= max(vertColor.z * m_SunlightIntensity,texCoord5.z);
color.a *= vertColor.a;
#endif
#ifdef HAS_COLOR
color *= m_Color;
#endif
#ifdef HAS_LIGHTMAP
#ifdef SEPARATE_TEXCOORD
color.rgb *= texture2D(m_LightMap, texCoord2).rgb;
#else
color.rgb *= texture2D(m_LightMap, texCoord1).rgb;
#endif
#endif
#if defined(DISCARD_ALPHA)
if(color.a < m_AlphaDiscardThreshold){
discard;
}
#endif
gl_FragColor = color;
}