Skip to content

Commit 5975b3f

Browse files
authored
Partial fix for Issue #2087 (NegativeScaleTest) (#2091)
* solution drafted * solution tested and confirmed * tested scale component combinations * removed unnecessary import * fixed instatiation of a new object every frame
1 parent 53301c7 commit 5975b3f

File tree

3 files changed

+58
-10
lines changed

3 files changed

+58
-10
lines changed

jme3-core/src/main/java/com/jme3/material/Material.java

+28-8
Original file line numberDiff line numberDiff line change
@@ -890,16 +890,36 @@ private boolean isBO(final VarType type) {
890890
return type == VarType.BufferObject;
891891
}
892892

893-
private void updateRenderState(RenderManager renderManager, Renderer renderer, TechniqueDef techniqueDef) {
893+
private void updateRenderState(Geometry geometry, RenderManager renderManager, Renderer renderer, TechniqueDef techniqueDef) {
894894
if (renderManager.getForcedRenderState() != null) {
895-
renderer.applyRenderState(renderManager.getForcedRenderState());
895+
mergedRenderState.set(renderManager.getForcedRenderState());
896+
} else if (techniqueDef.getRenderState() != null) {
897+
// copyMergedTo writes to mergedRenderState
898+
techniqueDef.getRenderState().copyMergedTo(additionalState, mergedRenderState);
896899
} else {
897-
if (techniqueDef.getRenderState() != null) {
898-
renderer.applyRenderState(techniqueDef.getRenderState().copyMergedTo(additionalState, mergedRenderState));
899-
} else {
900-
renderer.applyRenderState(RenderState.DEFAULT.copyMergedTo(additionalState, mergedRenderState));
901-
}
900+
RenderState.DEFAULT.copyMergedTo(additionalState, mergedRenderState);
902901
}
902+
// test if the face cull mode should be flipped before render
903+
if (mergedRenderState.isFaceCullFlippable() && isNormalsBackward(geometry.getWorldScale())) {
904+
mergedRenderState.flipFaceCull();
905+
}
906+
renderer.applyRenderState(mergedRenderState);
907+
}
908+
909+
/**
910+
* Returns true if the geometry world scale indicates that normals will be backward.
911+
* @param scalar geometry world scale
912+
* @return
913+
*/
914+
private boolean isNormalsBackward(Vector3f scalar) {
915+
// count number of negative scalar vector components
916+
int n = 0;
917+
if (scalar.x < 0) n++;
918+
if (scalar.y < 0) n++;
919+
if (scalar.z < 0) n++;
920+
// An odd number of negative components means the normal vectors
921+
// are backward to what they should be.
922+
return n == 1 || n == 3;
903923
}
904924

905925
/**
@@ -1028,7 +1048,7 @@ public void render(Geometry geometry, LightList lights, RenderManager renderMana
10281048
}
10291049

10301050
// Apply render state
1031-
updateRenderState(renderManager, renderer, techniqueDef);
1051+
updateRenderState(geometry, renderManager, renderer, techniqueDef);
10321052

10331053
// Get world overrides
10341054
SafeArrayList<MatParamOverride> overrides = geometry.getWorldMatParamOverrides();

jme3-core/src/main/java/com/jme3/material/RenderState.java

+25
Original file line numberDiff line numberDiff line change
@@ -1711,4 +1711,29 @@ public String toString() {
17111711
+ (blendMode.equals(BlendMode.Custom)? "\ncustomBlendFactors=("+sfactorRGB+", "+dfactorRGB+", "+sfactorAlpha+", "+dfactorAlpha+")":"")
17121712
+"\n]";
17131713
}
1714+
1715+
/**
1716+
* Flips the given face cull mode so that {@code Back} becomes
1717+
* {@code Front} and {@code Front} becomes {@code Back}.
1718+
* <p>{@code FrontAndBack} and {@code Off} are unaffected. This is important
1719+
* for flipping the cull mode when normal vectors are found to be backward.
1720+
* @param cull
1721+
* @return flipped cull mode
1722+
*/
1723+
public void flipFaceCull() {
1724+
switch (cullMode) {
1725+
case Back: cullMode = FaceCullMode.Front; break;
1726+
case Front: cullMode = FaceCullMode.Back; break;
1727+
}
1728+
}
1729+
1730+
/**
1731+
* Checks if the face cull mode is "flippable".
1732+
* <p>The cull mode is flippable when it is either {@code Front} or {@code Back}.
1733+
* @return
1734+
*/
1735+
public boolean isFaceCullFlippable() {
1736+
return cullMode == FaceCullMode.Front || cullMode == FaceCullMode.Back;
1737+
}
1738+
17141739
}

jme3-examples/src/main/java/jme3test/model/TestGltfLoading.java

+5-2
Original file line numberDiff line numberDiff line change
@@ -134,7 +134,7 @@ public void simpleInitApp() {
134134
//loadModel("Models/gltf/manta/scene.gltf", Vector3f.ZERO, 0.2f);
135135
//loadModel("Models/gltf/bone/scene.gltf", Vector3f.ZERO, 0.1f);
136136
// loadModel("Models/gltf/box/box.gltf", Vector3f.ZERO, 1);
137-
loadModel("Models/gltf/duck/Duck.gltf", new Vector3f(0, -1, 0), 1);
137+
loadModel("Models/gltf/duck/Duck.gltf", new Vector3f(0, 1, 0), 1);
138138
// loadModel("Models/gltf/DamagedHelmet/glTF/DamagedHelmet.gltf", Vector3f.ZERO, 1);
139139
// loadModel("Models/gltf/hornet/scene.gltf", new Vector3f(0, -0.5f, 0), 0.4f);
140140
//// loadModel("Models/gltf/adamHead/adamHead.gltf", Vector3f.ZERO, 0.6f);
@@ -226,10 +226,13 @@ private <T extends Control> T findControl(Spatial s, Class<T> controlClass) {
226226
}
227227

228228
private void loadModel(String path, Vector3f offset, float scale) {
229+
loadModel(path, offset, new Vector3f(scale, scale, scale));
230+
}
231+
private void loadModel(String path, Vector3f offset, Vector3f scale) {
229232
GltfModelKey k = new GltfModelKey(path);
230233
//k.setKeepSkeletonPose(true);
231234
Spatial s = assetManager.loadModel(k);
232-
s.scale(scale);
235+
s.scale(scale.x, scale.y, scale.z);
233236
s.move(offset);
234237
assets.add(s);
235238
if (playAnim) {

0 commit comments

Comments
 (0)