|
@@ -69,7 +69,7 @@ import java.util.logging.Logger;
|
|
|
* Setting the parameters can modify the behavior of a
|
|
|
* shader.
|
|
|
* <p/>
|
|
|
- *
|
|
|
+ *
|
|
|
* @author Kirill Vainer
|
|
|
*/
|
|
|
public class Material implements CloneableSmartAsset, Cloneable, Savable {
|
|
@@ -146,7 +146,7 @@ public class Material implements CloneableSmartAsset, Cloneable, Savable {
|
|
|
public String getName() {
|
|
|
return name;
|
|
|
}
|
|
|
-
|
|
|
+
|
|
|
/**
|
|
|
* This method sets the name of the material.
|
|
|
* The name is not the same as the asset name.
|
|
@@ -222,11 +222,11 @@ public class Material implements CloneableSmartAsset, Cloneable, Savable {
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
- * Compares two materials and returns true if they are equal.
|
|
|
+ * Compares two materials and returns true if they are equal.
|
|
|
* This methods compare definition, parameters, additional render states.
|
|
|
- * Since materials are mutable objects, implementing equals() properly is not possible,
|
|
|
+ * Since materials are mutable objects, implementing equals() properly is not possible,
|
|
|
* hence the name contentEquals().
|
|
|
- *
|
|
|
+ *
|
|
|
* @param otherObj the material to compare to this material
|
|
|
* @return true if the materials are equal.
|
|
|
*/
|
|
@@ -234,15 +234,15 @@ public class Material implements CloneableSmartAsset, Cloneable, Savable {
|
|
|
if (!(otherObj instanceof Material)) {
|
|
|
return false;
|
|
|
}
|
|
|
-
|
|
|
+
|
|
|
Material other = (Material) otherObj;
|
|
|
-
|
|
|
+
|
|
|
// Early exit if the material are the same object
|
|
|
if (this == other) {
|
|
|
return true;
|
|
|
}
|
|
|
|
|
|
- // Check material definition
|
|
|
+ // Check material definition
|
|
|
if (this.getMaterialDef() != other.getMaterialDef()) {
|
|
|
return false;
|
|
|
}
|
|
@@ -251,12 +251,12 @@ public class Material implements CloneableSmartAsset, Cloneable, Savable {
|
|
|
if (this.paramValues.size() != other.paramValues.size()) {
|
|
|
return false;
|
|
|
}
|
|
|
-
|
|
|
+
|
|
|
// Checking technique
|
|
|
if (this.technique != null || other.technique != null) {
|
|
|
// Techniques are considered equal if their names are the same
|
|
|
- // E.g. if user chose custom technique for one material but
|
|
|
- // uses default technique for other material, the materials
|
|
|
+ // E.g. if user chose custom technique for one material but
|
|
|
+ // uses default technique for other material, the materials
|
|
|
// are not equal.
|
|
|
String thisDefName = this.technique != null ? this.technique.getDef().getName() : "Default";
|
|
|
String otherDefName = other.technique != null ? other.technique.getDef().getName() : "Default";
|
|
@@ -290,7 +290,7 @@ public class Material implements CloneableSmartAsset, Cloneable, Savable {
|
|
|
return false;
|
|
|
}
|
|
|
}
|
|
|
-
|
|
|
+
|
|
|
return true;
|
|
|
}
|
|
|
|
|
@@ -305,7 +305,7 @@ public class Material implements CloneableSmartAsset, Cloneable, Savable {
|
|
|
hash = 29 * hash + (this.additionalState != null ? this.additionalState.contentHashCode() : 0);
|
|
|
return hash;
|
|
|
}
|
|
|
-
|
|
|
+
|
|
|
/**
|
|
|
* Returns the currently active technique.
|
|
|
* <p>
|
|
@@ -436,7 +436,7 @@ public class Material implements CloneableSmartAsset, Cloneable, Savable {
|
|
|
public Collection<MatParam> getParams() {
|
|
|
return paramValues.values();
|
|
|
}
|
|
|
-
|
|
|
+
|
|
|
/**
|
|
|
* Returns the ListMap of all parameters set on this material.
|
|
|
*
|
|
@@ -473,7 +473,7 @@ public class Material implements CloneableSmartAsset, Cloneable, Savable {
|
|
|
*/
|
|
|
public void setParam(String name, VarType type, Object value) {
|
|
|
checkSetParam(type, name);
|
|
|
-
|
|
|
+
|
|
|
if (type.isTextureType()) {
|
|
|
setTextureParam(name, type, (Texture)value);
|
|
|
} else {
|
|
@@ -501,7 +501,7 @@ public class Material implements CloneableSmartAsset, Cloneable, Savable {
|
|
|
if (matParam == null) {
|
|
|
return;
|
|
|
}
|
|
|
-
|
|
|
+
|
|
|
paramValues.remove(name);
|
|
|
if (matParam instanceof MatParamTexture) {
|
|
|
int texUnit = ((MatParamTexture) matParam).getUnit();
|
|
@@ -728,7 +728,7 @@ public class Material implements CloneableSmartAsset, Cloneable, Savable {
|
|
|
renderer.renderMesh(mesh, lodLevel, 1, null);
|
|
|
}
|
|
|
}
|
|
|
-
|
|
|
+
|
|
|
/**
|
|
|
* Uploads the lights in the light list as two uniform arrays.<br/><br/> *
|
|
|
* <p>
|
|
@@ -747,30 +747,30 @@ public class Material implements CloneableSmartAsset, Cloneable, Savable {
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
- Uniform lightData = shader.getUniform("g_LightData");
|
|
|
- lightData.setVector4Length(numLights * 3);//8 lights * max 3
|
|
|
+ Uniform lightData = shader.getUniform("g_LightData");
|
|
|
+ lightData.setVector4Length(numLights * 3);//8 lights * max 3
|
|
|
Uniform ambientColor = shader.getUniform("g_AmbientLightColor");
|
|
|
-
|
|
|
|
|
|
- if (startIndex != 0) {
|
|
|
+
|
|
|
+ if (startIndex != 0) {
|
|
|
// apply additive blending for 2nd and future passes
|
|
|
rm.getRenderer().applyRenderState(additiveLight);
|
|
|
- ambientColor.setValue(VarType.Vector4, ColorRGBA.Black);
|
|
|
+ ambientColor.setValue(VarType.Vector4, ColorRGBA.Black);
|
|
|
}else{
|
|
|
ambientColor.setValue(VarType.Vector4, getAmbientColor(lightList,true));
|
|
|
}
|
|
|
-
|
|
|
+
|
|
|
int lightDataIndex = 0;
|
|
|
TempVars vars = TempVars.get();
|
|
|
Vector4f tmpVec = vars.vect4f1;
|
|
|
int curIndex;
|
|
|
int endIndex = numLights + startIndex;
|
|
|
for (curIndex = startIndex; curIndex < endIndex && curIndex < lightList.size(); curIndex++) {
|
|
|
-
|
|
|
-
|
|
|
- Light l = lightList.get(curIndex);
|
|
|
+
|
|
|
+
|
|
|
+ Light l = lightList.get(curIndex);
|
|
|
if(l.getType() == Light.Type.Ambient){
|
|
|
- endIndex++;
|
|
|
+ endIndex++;
|
|
|
continue;
|
|
|
}
|
|
|
ColorRGBA color = l.getColor();
|
|
@@ -781,14 +781,14 @@ public class Material implements CloneableSmartAsset, Cloneable, Savable {
|
|
|
l.getType().getId(),
|
|
|
lightDataIndex);
|
|
|
lightDataIndex++;
|
|
|
-
|
|
|
+
|
|
|
switch (l.getType()) {
|
|
|
case Directional:
|
|
|
DirectionalLight dl = (DirectionalLight) l;
|
|
|
- Vector3f dir = dl.getDirection();
|
|
|
+ Vector3f dir = dl.getDirection();
|
|
|
//Data directly sent in view space to avoid a matrix mult for each pixel
|
|
|
tmpVec.set(dir.getX(), dir.getY(), dir.getZ(), 0.0f);
|
|
|
- rm.getCurrentCamera().getViewMatrix().mult(tmpVec, tmpVec);
|
|
|
+ rm.getCurrentCamera().getViewMatrix().mult(tmpVec, tmpVec);
|
|
|
// tmpVec.divideLocal(tmpVec.w);
|
|
|
// tmpVec.normalizeLocal();
|
|
|
lightData.setVector4InArray(tmpVec.getX(), tmpVec.getY(), tmpVec.getZ(), -1, lightDataIndex);
|
|
@@ -802,7 +802,7 @@ public class Material implements CloneableSmartAsset, Cloneable, Savable {
|
|
|
Vector3f pos = pl.getPosition();
|
|
|
float invRadius = pl.getInvRadius();
|
|
|
tmpVec.set(pos.getX(), pos.getY(), pos.getZ(), 1.0f);
|
|
|
- rm.getCurrentCamera().getViewMatrix().mult(tmpVec, tmpVec);
|
|
|
+ rm.getCurrentCamera().getViewMatrix().mult(tmpVec, tmpVec);
|
|
|
//tmpVec.divideLocal(tmpVec.w);
|
|
|
lightData.setVector4InArray(tmpVec.getX(), tmpVec.getY(), tmpVec.getZ(), invRadius, lightDataIndex);
|
|
|
lightDataIndex++;
|
|
@@ -810,37 +810,37 @@ public class Material implements CloneableSmartAsset, Cloneable, Savable {
|
|
|
lightData.setVector4InArray(0,0,0,0, lightDataIndex);
|
|
|
lightDataIndex++;
|
|
|
break;
|
|
|
- case Spot:
|
|
|
+ case Spot:
|
|
|
SpotLight sl = (SpotLight) l;
|
|
|
Vector3f pos2 = sl.getPosition();
|
|
|
Vector3f dir2 = sl.getDirection();
|
|
|
float invRange = sl.getInvSpotRange();
|
|
|
float spotAngleCos = sl.getPackedAngleCos();
|
|
|
tmpVec.set(pos2.getX(), pos2.getY(), pos2.getZ(), 1.0f);
|
|
|
- rm.getCurrentCamera().getViewMatrix().mult(tmpVec, tmpVec);
|
|
|
+ rm.getCurrentCamera().getViewMatrix().mult(tmpVec, tmpVec);
|
|
|
// tmpVec.divideLocal(tmpVec.w);
|
|
|
lightData.setVector4InArray(tmpVec.getX(), tmpVec.getY(), tmpVec.getZ(), invRange, lightDataIndex);
|
|
|
lightDataIndex++;
|
|
|
-
|
|
|
+
|
|
|
//We transform the spot direction in view space here to save 5 varying later in the lighting shader
|
|
|
//one vec4 less and a vec4 that becomes a vec3
|
|
|
//the downside is that spotAngleCos decoding happens now in the frag shader.
|
|
|
tmpVec.set(dir2.getX(), dir2.getY(), dir2.getZ(), 0.0f);
|
|
|
- rm.getCurrentCamera().getViewMatrix().mult(tmpVec, tmpVec);
|
|
|
+ rm.getCurrentCamera().getViewMatrix().mult(tmpVec, tmpVec);
|
|
|
tmpVec.normalizeLocal();
|
|
|
lightData.setVector4InArray(tmpVec.getX(), tmpVec.getY(), tmpVec.getZ(), spotAngleCos, lightDataIndex);
|
|
|
lightDataIndex++;
|
|
|
- break;
|
|
|
+ break;
|
|
|
default:
|
|
|
throw new UnsupportedOperationException("Unknown type of light: " + l.getType());
|
|
|
}
|
|
|
}
|
|
|
- vars.release();
|
|
|
+ vars.release();
|
|
|
//Padding of unsued buffer space
|
|
|
while(lightDataIndex < numLights * 3) {
|
|
|
lightData.setVector4InArray(0f, 0f, 0f, 0f, lightDataIndex);
|
|
|
- lightDataIndex++;
|
|
|
- }
|
|
|
+ lightDataIndex++;
|
|
|
+ }
|
|
|
return curIndex;
|
|
|
}
|
|
|
|
|
@@ -887,10 +887,10 @@ public class Material implements CloneableSmartAsset, Cloneable, Savable {
|
|
|
case Directional:
|
|
|
DirectionalLight dl = (DirectionalLight) l;
|
|
|
Vector3f dir = dl.getDirection();
|
|
|
- //FIXME : there is an inconstency here due to backward
|
|
|
+ //FIXME : there is an inconstency here due to backward
|
|
|
//compatibility of the lighting shader.
|
|
|
- //The directional light direction is passed in the
|
|
|
- //LightPosition uniform. The lighting shader needs to be
|
|
|
+ //The directional light direction is passed in the
|
|
|
+ //LightPosition uniform. The lighting shader needs to be
|
|
|
//reworked though in order to fix this.
|
|
|
tmpLightPosition.set(dir.getX(), dir.getY(), dir.getZ(), -1);
|
|
|
lightPos.setValue(VarType.Vector4, tmpLightPosition);
|
|
@@ -987,11 +987,11 @@ public class Material implements CloneableSmartAsset, Cloneable, Savable {
|
|
|
for (TechniqueDef techDef : techDefs) {
|
|
|
if (rendererCaps.containsAll(techDef.getRequiredCaps())) {
|
|
|
// use the first one that supports all the caps
|
|
|
- tech = new Technique(this, techDef);
|
|
|
+ tech = new Technique(this, techDef);
|
|
|
techniques.put(name, tech);
|
|
|
if(tech.getDef().getLightMode() == renderManager.getPreferredLightMode() ||
|
|
|
tech.getDef().getLightMode() == LightMode.Disable){
|
|
|
- break;
|
|
|
+ break;
|
|
|
}
|
|
|
}
|
|
|
lastTech = techDef;
|
|
@@ -1078,7 +1078,7 @@ public class Material implements CloneableSmartAsset, Cloneable, Savable {
|
|
|
Uniform u = uniforms.getValue(i);
|
|
|
if (!u.isSetByCurrentMaterial()) {
|
|
|
if (u.getName().charAt(0) != 'g') {
|
|
|
- // Don't reset world globals!
|
|
|
+ // Don't reset world globals!
|
|
|
// The benefits gained from this are very minimal
|
|
|
// and cause lots of matrix -> FloatBuffer conversions.
|
|
|
u.clearValue();
|
|
@@ -1093,21 +1093,21 @@ public class Material implements CloneableSmartAsset, Cloneable, Savable {
|
|
|
* <p>
|
|
|
* The material is rendered as follows:
|
|
|
* <ul>
|
|
|
- * <li>Determine which technique to use to render the material -
|
|
|
- * either what the user selected via
|
|
|
- * {@link #selectTechnique(java.lang.String, com.jme3.renderer.RenderManager)
|
|
|
- * Material.selectTechnique()},
|
|
|
- * or the first default technique that the renderer supports
|
|
|
+ * <li>Determine which technique to use to render the material -
|
|
|
+ * either what the user selected via
|
|
|
+ * {@link #selectTechnique(java.lang.String, com.jme3.renderer.RenderManager)
|
|
|
+ * Material.selectTechnique()},
|
|
|
+ * or the first default technique that the renderer supports
|
|
|
* (based on the technique's {@link TechniqueDef#getRequiredCaps() requested rendering capabilities})<ul>
|
|
|
- * <li>If the technique has been changed since the last frame, then it is notified via
|
|
|
- * {@link Technique#makeCurrent(com.jme3.asset.AssetManager, boolean, java.util.EnumSet)
|
|
|
- * Technique.makeCurrent()}.
|
|
|
- * If the technique wants to use a shader to render the model, it should load it at this part -
|
|
|
- * the shader should have all the proper defines as declared in the technique definition,
|
|
|
- * including those that are bound to material parameters.
|
|
|
- * The technique can re-use the shader from the last frame if
|
|
|
+ * <li>If the technique has been changed since the last frame, then it is notified via
|
|
|
+ * {@link Technique#makeCurrent(com.jme3.asset.AssetManager, boolean, java.util.EnumSet)
|
|
|
+ * Technique.makeCurrent()}.
|
|
|
+ * If the technique wants to use a shader to render the model, it should load it at this part -
|
|
|
+ * the shader should have all the proper defines as declared in the technique definition,
|
|
|
+ * including those that are bound to material parameters.
|
|
|
+ * The technique can re-use the shader from the last frame if
|
|
|
* no changes to the defines occurred.</li></ul>
|
|
|
- * <li>Set the {@link RenderState} to use for rendering. The render states are
|
|
|
+ * <li>Set the {@link RenderState} to use for rendering. The render states are
|
|
|
* applied in this order (later RenderStates override earlier RenderStates):<ol>
|
|
|
* <li>{@link TechniqueDef#getRenderState() Technique Definition's RenderState}
|
|
|
* - i.e. specific renderstate that is required for the shader.</li>
|
|
@@ -1120,22 +1120,22 @@ public class Material implements CloneableSmartAsset, Cloneable, Savable {
|
|
|
* <li>Uniforms bound to material parameters are updated based on the current material parameter values.</li>
|
|
|
* <li>Uniforms bound to world parameters are updated from the RenderManager.
|
|
|
* Internally {@link UniformBindingManager} is used for this task.</li>
|
|
|
- * <li>Uniforms bound to textures will cause the texture to be uploaded as necessary.
|
|
|
+ * <li>Uniforms bound to textures will cause the texture to be uploaded as necessary.
|
|
|
* The uniform is set to the texture unit where the texture is bound.</li></ul>
|
|
|
- * <li>If the technique uses a shader, the model is then rendered according
|
|
|
+ * <li>If the technique uses a shader, the model is then rendered according
|
|
|
* to the lighting mode specified on the technique definition.<ul>
|
|
|
- * <li>{@link LightMode#SinglePass single pass light mode} fills the shader's light uniform arrays
|
|
|
+ * <li>{@link LightMode#SinglePass single pass light mode} fills the shader's light uniform arrays
|
|
|
* with the first 4 lights and renders the model once.</li>
|
|
|
- * <li>{@link LightMode#MultiPass multi pass light mode} light mode renders the model multiple times,
|
|
|
- * for the first light it is rendered opaque, on subsequent lights it is
|
|
|
+ * <li>{@link LightMode#MultiPass multi pass light mode} light mode renders the model multiple times,
|
|
|
+ * for the first light it is rendered opaque, on subsequent lights it is
|
|
|
* rendered with {@link BlendMode#AlphaAdditive alpha-additive} blending and depth writing disabled.</li>
|
|
|
* </ul>
|
|
|
- * <li>For techniques that do not use shaders,
|
|
|
+ * <li>For techniques that do not use shaders,
|
|
|
* fixed function OpenGL is used to render the model (see {@link GL1Renderer} interface):<ul>
|
|
|
* <li>OpenGL state ({@link FixedFuncBinding}) that is bound to material parameters is updated. </li>
|
|
|
- * <li>The texture set on the material is uploaded and bound.
|
|
|
+ * <li>The texture set on the material is uploaded and bound.
|
|
|
* Currently only 1 texture is supported for fixed function techniques.</li>
|
|
|
- * <li>If the technique uses lighting, then OpenGL lighting state is updated
|
|
|
+ * <li>If the technique uses lighting, then OpenGL lighting state is updated
|
|
|
* based on the light list on the geometry, otherwise OpenGL lighting is disabled.</li>
|
|
|
* <li>The mesh is uploaded and rendered.</li>
|
|
|
* </ul>
|
|
@@ -1147,10 +1147,11 @@ public class Material implements CloneableSmartAsset, Cloneable, Savable {
|
|
|
*/
|
|
|
public void render(Geometry geom, LightList lights, RenderManager rm) {
|
|
|
autoSelectTechnique(rm);
|
|
|
+ TechniqueDef techDef = technique.getDef();
|
|
|
|
|
|
- Renderer r = rm.getRenderer();
|
|
|
+ if (techDef.isNoRender()) return;
|
|
|
|
|
|
- TechniqueDef techDef = technique.getDef();
|
|
|
+ Renderer r = rm.getRenderer();
|
|
|
|
|
|
if (rm.getForcedRenderState() != null) {
|
|
|
r.applyRenderState(rm.getForcedRenderState());
|
|
@@ -1169,7 +1170,7 @@ public class Material implements CloneableSmartAsset, Cloneable, Savable {
|
|
|
// reset unchanged uniform flag
|
|
|
clearUniformsSetByCurrent(technique.getShader());
|
|
|
rm.updateUniformBindings(technique.getWorldBindUniforms());
|
|
|
-
|
|
|
+
|
|
|
|
|
|
// setup textures and uniforms
|
|
|
for (int i = 0; i < paramValues.size(); i++) {
|
|
@@ -1212,24 +1213,24 @@ public class Material implements CloneableSmartAsset, Cloneable, Savable {
|
|
|
// any unset uniforms will be set to 0
|
|
|
resetUniformsNotSetByCurrent(shader);
|
|
|
r.setShader(shader);
|
|
|
-
|
|
|
+
|
|
|
renderMeshFromGeometry(r, geom);
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* Called by {@link RenderManager} to render the geometry by
|
|
|
* using this material.
|
|
|
- *
|
|
|
+ *
|
|
|
* Note that this version of the render method
|
|
|
* does not perform light filtering.
|
|
|
- *
|
|
|
+ *
|
|
|
* @param geom The geometry to render
|
|
|
* @param rm The render manager requesting the rendering
|
|
|
*/
|
|
|
public void render(Geometry geom, RenderManager rm) {
|
|
|
render(geom, geom.getWorldLightList(), rm);
|
|
|
}
|
|
|
-
|
|
|
+
|
|
|
public void write(JmeExporter ex) throws IOException {
|
|
|
OutputCapsule oc = ex.getCapsule(this);
|
|
|
oc.write(def.getAssetName(), "material_def", null);
|
|
@@ -1304,14 +1305,14 @@ public class Material implements CloneableSmartAsset, Cloneable, Savable {
|
|
|
continue;
|
|
|
}
|
|
|
}
|
|
|
-
|
|
|
+
|
|
|
if (im.getFormatVersion() == 0 && param.getName().startsWith("m_")) {
|
|
|
// Ancient version of jME3 ...
|
|
|
param.setName(param.getName().substring(2));
|
|
|
}
|
|
|
-
|
|
|
+
|
|
|
if (def.getMaterialParam(param.getName()) == null) {
|
|
|
- logger.log(Level.WARNING, "The material parameter is not defined: {0}. Ignoring..",
|
|
|
+ logger.log(Level.WARNING, "The material parameter is not defined: {0}. Ignoring..",
|
|
|
param.getName());
|
|
|
} else {
|
|
|
checkSetParam(param.getVarType(), param.getName());
|