hey guys.
I applied the shaders from TestNormalmap to my own model and noticed that the specular "spot" ("reflection") is not correct at all.
So I changed the TestNormalmap and used a jme.scene.Sphere for an earth Geometry and applied a diffuse, a normal and a specular map to it. The problem is actually already there. I changed the Testcase like this:
package jmetest.renderer.loader;
import java.io.InputStream;
import java.net.MalformedURLException;
import java.net.URISyntaxException;
import java.net.URL;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import jmetest.renderer.TestMipMaps;
import com.jme.app.SimpleGame;
import com.jme.image.Image;
import com.jme.image.Texture;
import com.jme.input.FirstPersonHandler;
import com.jme.input.KeyBindingManager;
import com.jme.input.KeyInput;
import com.jme.light.DirectionalLight;
import com.jme.math.FastMath;
import com.jme.math.Vector3f;
import com.jme.renderer.ColorRGBA;
import com.jme.scene.Node;
import com.jme.scene.SharedMesh;
import com.jme.scene.Spatial;
import com.jme.scene.TriMesh;
import com.jme.scene.Spatial.LightCombineMode;
import com.jme.scene.shape.Box;
import com.jme.scene.shape.Sphere;
import com.jme.scene.shape.Torus;
import com.jme.scene.state.GLSLShaderObjectsState;
import com.jme.scene.state.MaterialState;
import com.jme.scene.state.RenderState;
import com.jme.scene.state.TextureState;
import com.jme.system.DisplaySystem;
import com.jme.system.JmeException;
import com.jme.util.TextureManager;
import com.jme.util.resource.ResourceLocatorTool;
import com.jme.util.resource.SimpleResourceLocator;
import com.jmex.model.collada.ColladaImporter;
/**
* TestNormalmap
*/
public class TestNormalmap extends SimpleGame {
private static final Logger logger = Logger.getLogger(TestNormalmap.class.getName());
private Vector3f lightDir = new Vector3f();
private GLSLShaderObjectsState so;
private String currentShaderStr = "jmetest/data/images/normalmap";
private Sphere lightSphere;
public static void main(String[] args) {
TestNormalmap app = new TestNormalmap();
app.setConfigShowMode(ConfigShowMode.AlwaysShow);
app.start();
}
protected void simpleUpdate() {
if (KeyBindingManager.getKeyBindingManager().isValidCommand("reloadShader", false)) {
reloadShader();
}
float spinValX = FastMath.sin(timer.getTimeInSeconds() * 2.0f);
float spinValY = FastMath.cos(timer.getTimeInSeconds() * 2.0f);
lightDir.set(spinValX, spinValY, -1.0f).normalizeLocal();
lightSphere.setLocalTranslation(lightDir.negate().multLocal(30));
}
public void reloadShader() {
GLSLShaderObjectsState testShader = DisplaySystem.getDisplaySystem().getRenderer()
.createGLSLShaderObjectsState();
try {
testShader.load(TestColladaLoading.class.getClassLoader().getResource(currentShaderStr + ".vert"),
TestColladaLoading.class.getClassLoader().getResource(currentShaderStr + ".frag"));
testShader.apply();
DisplaySystem.getDisplaySystem().getRenderer().checkCardError();
} catch (JmeException e) {
logger.log(Level.WARNING, "Failed to reload shader", e);
return;
}
so.load(TestColladaLoading.class.getClassLoader().getResource(currentShaderStr + ".vert"),
TestColladaLoading.class.getClassLoader().getResource(currentShaderStr + ".frag"));
so.setUniform("baseMap", 0);
so.setUniform("normalMap", 1);
so.setUniform("specularMap", 2);
logger.info("Shader reloaded...");
}
protected void simpleInitGame() {
KeyBindingManager.getKeyBindingManager().set("reloadShader", KeyInput.KEY_F);
// Our model is Z up so orient the camera properly.
cam.setAxes(new Vector3f(-1, 0, 0), new Vector3f(0, 0, 1), new Vector3f(0, 1, 0));
cam.setLocation(new Vector3f(0, -100, 0));
// Create a directional light
DirectionalLight dr = new DirectionalLight();
dr.setDiffuse(new ColorRGBA(1.0f, 1.0f, 1.0f, 1.0f));
dr.setAmbient(new ColorRGBA(0.2f, 0.2f, 0.2f, 1.0f));
dr.setSpecular(new ColorRGBA(0.7f, 0.7f, 0.7f, 1.0f));
dr.setDirection(lightDir);
dr.setEnabled(true);
lightState.detachAll();
lightState.attach(dr);
so = display.getRenderer().createGLSLShaderObjectsState();
// Check is GLSL is supported on current hardware.
if (!GLSLShaderObjectsState.isSupported()) {
logger.severe("Your graphics card does not support GLSL programs, and thus cannot run this test.");
quit();
}
reloadShader();
TextureState ts = display.getRenderer().createTextureState();
// Base texture
Texture baseMap = TextureManager.loadTexture(TestNormalmap.class
.getClassLoader().getResource(
"jmetest/data/images/Fieldstone.jpg"),
Texture.MinificationFilter.Trilinear, Texture.MagnificationFilter.Bilinear);
ts.setTexture(baseMap, 0);
// Normal map
Texture normalMap = TextureManager.loadTexture(TestNormalmap.class
.getClassLoader().getResource(
"jmetest/data/images/FieldstoneNormal.jpg"),
Texture.MinificationFilter.Trilinear, Texture.MagnificationFilter.Bilinear,
Image.Format.GuessNoCompression, 0.0f, true);
ts.setTexture(normalMap, 1);
// Specular map
Texture specMap = TextureManager.loadTexture(TestNormalmap.class
.getClassLoader().getResource(
"jmetest/data/images/FieldstoneSpec.jpg"),
Texture.MinificationFilter.Trilinear, Texture.MagnificationFilter.Bilinear);
ts.setTexture(specMap, 2);
try {
ResourceLocatorTool.addResourceLocator(ResourceLocatorTool.TYPE_TEXTURE, new SimpleResourceLocator(
TestMipMaps.class.getClassLoader().getResource("jmetest/data/model/collada/")));
} catch (URISyntaxException e1) {
logger.warning("Unable to add texture directory to RLT: " + e1.toString());
}
// this stream points to the model itself.
InputStream modelStream = TestColladaLoading.class.getClassLoader().getResourceAsStream(
"jmetest/data/model/collada/Test_Ball_Hard.dae");
if (modelStream == null) {
logger.info("Unable to find file, did you include jme-test.jar in classpath?");
System.exit(0);
}
Sphere model = new Sphere("earth", new Vector3f(0, 0, 0), 100, 100, 20.0f, true);
// Torus model = new Torus("earth", 50, 50, 5, 10);
lightSphere = new Sphere("earth", new Vector3f(0, 0, 0), 10, 10, 1.0f, true);
lightSphere.setLightCombineMode(LightCombineMode.Off);
// Test materialstate (should be set through the import anyway)
MaterialState ms = display.getRenderer().createMaterialState();
ms.setColorMaterial(MaterialState.ColorMaterial.AmbientAndDiffuse);
ms.setAmbient(new ColorRGBA(1.0f, 1.0f, 1.0f, 1.0f));
ms.setDiffuse(new ColorRGBA(1.0f, 1.0f, 1.0f, 1.0f));
ms.setSpecular(new ColorRGBA(1.0f, 1.0f, 1.0f, 1.0f));
ms.setShininess(25.0f);
// Set all states on model
model.setRenderState(ts);
model.setRenderState(so);
model.setRenderState(ms);
ColladaImporter.cleanUp();
rootNode.attachChild(model);
rootNode.attachChild(lightSphere);
rootNode.updateGeometricState(0, true);
input = new FirstPersonHandler(cam, 80, 1);
}
}
And the unwanted result looks like seen in the image attached with my earth textures. As you can see I added a sphere for where the DirectionalLight comes from and you can notice that the specular spot is somewhere it simply cannot be. (Actually it is being drawn (or sucked in) to that point and then it comes out of it again). Start the test above with the original textures of this test, you will know what i mean.
also the shader has a bug (hardcoded texture scaling in the shader), heres the fix:
Index: src/jmetest/data/images/normalmap.vert
===================================================================
--- src/jmetest/data/images/normalmap.vert (revision 4706)
+++ src/jmetest/data/images/normalmap.vert (working copy)
@@ -8,7 +8,7 @@
{
/* Transform vertices and pass on texture coordinates */
gl_Position = ftransform();
- gl_TexCoord[0] = gl_TextureMatrix[0] * gl_MultiTexCoord0 * vec4(4.0, 4.0, 1.0, 1.0);
+ gl_TexCoord[0] = gl_TextureMatrix[0] * gl_MultiTexCoord0;
/* Transform vertex into viewspace */
vec4 vertexViewSpace = gl_ModelViewMatrix * gl_Vertex;
I have compared the shader to several other resources (including the shader pendant in jme3) and the specular color computation seems completely sound to me. I also tried it with reflect() and the result is the same. Furthermore, I tried this with oder Geometries (like Torus) and they all have a spot where the specular seems to get sucked in to.