From 0de5fe39a3163e417a803f194ec85842cdb09c14 Mon Sep 17 00:00:00 2001 From: "Kae..pl" Date: Mon, 25 Jul 2011 20:50:52 +0000 Subject: [PATCH] Fix to loading normal maps. git-svn-id: https://jmonkeyengine.googlecode.com/svn/trunk@7918 75d07b2b-3a1a-0410-a2c5-0572b91ccdca --- .../blender/helpers/v249/MaterialHelper.java | 9 +- .../blender/helpers/v249/TextureHelper.java | 102 ++++++++++++++++-- 2 files changed, 100 insertions(+), 11 deletions(-) diff --git a/engine/src/blender/com/jme3/scene/plugins/blender/helpers/v249/MaterialHelper.java b/engine/src/blender/com/jme3/scene/plugins/blender/helpers/v249/MaterialHelper.java index 018cde33d..74235780d 100644 --- a/engine/src/blender/com/jme3/scene/plugins/blender/helpers/v249/MaterialHelper.java +++ b/engine/src/blender/com/jme3/scene/plugins/blender/helpers/v249/MaterialHelper.java @@ -252,11 +252,9 @@ public class MaterialHelper extends AbstractBlenderHelper { Structure tex = pTex.fetchData(dataRepository.getInputStream()).get(0); Texture texture = textureHelper.getTexture(tex, dataRepository); - - if (texture != null) { - // NOTE: Enable mipmaps FOR ALL TEXTURES EVER - texture.setMinFilter(MinFilter.Trilinear); + // NOTE: Enable mipmaps FOR ALL TEXTURES EVER + texture.setMinFilter(MinFilter.Trilinear); if ((mapto & 0x01) != 0) {// Col // Map to COLOR channel or DIFFUSE @@ -276,7 +274,8 @@ public class MaterialHelper extends AbstractBlenderHelper { } } if ((mapto & 0x02) != 0) {// Nor - result.setTexture(TEXTURE_TYPE_NORMAL, texture); + Texture normalMapTexture = textureHelper.convertToNormalMapTexture(texture, ((Number)tex.getFieldValue("norfac")).floatValue()); + result.setTexture(TEXTURE_TYPE_NORMAL, normalMapTexture); if (vertexColor) { result.setBoolean(shadeless ? "VertexColor" : "UseVertexColor", false); } diff --git a/engine/src/blender/com/jme3/scene/plugins/blender/helpers/v249/TextureHelper.java b/engine/src/blender/com/jme3/scene/plugins/blender/helpers/v249/TextureHelper.java index aaaabef7f..b2d8a7957 100644 --- a/engine/src/blender/com/jme3/scene/plugins/blender/helpers/v249/TextureHelper.java +++ b/engine/src/blender/com/jme3/scene/plugins/blender/helpers/v249/TextureHelper.java @@ -31,6 +31,9 @@ */ package com.jme3.scene.plugins.blender.helpers.v249; +import java.awt.color.ColorSpace; +import java.awt.image.BufferedImage; +import java.awt.image.ColorConvertOp; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; @@ -40,10 +43,13 @@ import java.nio.ByteBuffer; import java.util.logging.Level; import java.util.logging.Logger; +import jme3tools.converters.ImageToAwt; + import com.jme3.asset.AssetNotFoundException; import com.jme3.asset.TextureKey; import com.jme3.asset.BlenderKey.FeaturesToLoad; import com.jme3.math.FastMath; +import com.jme3.math.Vector3f; import com.jme3.scene.plugins.blender.data.FileBlockHeader; import com.jme3.scene.plugins.blender.data.Structure; import com.jme3.scene.plugins.blender.exception.BlenderFileException; @@ -174,14 +180,12 @@ public class TextureHelper extends AbstractBlenderHelper { int height = dataRepository.getBlenderKey().getGeneratedTextureHeight(); switch (type) { - case TEX_NONE:// No texture, do nothing - break; case TEX_IMAGE:// (it is first because probably this will be most commonly used) Pointer pImage = (Pointer) tex.getFieldValue("ima"); - if (pImage.isNotNull()){ - Structure image = pImage.fetchData(dataRepository.getInputStream()).get(0); - result = this.getTextureFromImage(image, dataRepository); - } + if (pImage.isNotNull()){ + Structure image = pImage.fetchData(dataRepository.getInputStream()).get(0); + result = this.getTextureFromImage(image, dataRepository); + } break; case TEX_CLOUDS: result = this.clouds(tex, width, height, dataRepository); @@ -213,6 +217,8 @@ public class TextureHelper extends AbstractBlenderHelper { case TEX_DISTNOISE: result = this.distnoise(tex, width, height, dataRepository); break; + case TEX_NONE:// No texture, do nothing + break; case TEX_PLUGIN: case TEX_ENVMAP:// TODO: implement envmap texture LOGGER.log(Level.WARNING, "Unsupported texture type: {0} for texture: {1}", new Object[]{type, tex.getName()}); @@ -1550,6 +1556,90 @@ public class TextureHelper extends AbstractBlenderHelper { } } + /** + * This method converts the given texture into normal-map texture. + * @param source + * the source texture + * @param strengthFactor + * the normal strength factor + * @return normal-map texture + */ + public Texture convertToNormalMapTexture(Texture source, float strengthFactor) { + Image image = source.getImage(); + BufferedImage sourceImage = ImageToAwt.convert(image, false, false, 0); + BufferedImage heightMap = new BufferedImage(sourceImage.getWidth(), sourceImage.getHeight(), BufferedImage.TYPE_INT_ARGB); + BufferedImage bumpMap = new BufferedImage(sourceImage.getWidth(), sourceImage.getHeight(), BufferedImage.TYPE_INT_ARGB); + ColorConvertOp gscale = new ColorConvertOp(ColorSpace.getInstance(ColorSpace.CS_GRAY), null); + gscale.filter(sourceImage, heightMap); + + Vector3f S = new Vector3f(); + Vector3f T = new Vector3f(); + Vector3f N = new Vector3f(); + + for (int x = 0; x < bumpMap.getWidth(); ++x) { + for (int y = 0; y < bumpMap.getHeight(); ++y) { + // generating bump pixel + S.x = 1; + S.y = 0; + S.z = strengthFactor * this.getHeight(heightMap, x + 1, y) - strengthFactor * this.getHeight(heightMap, x - 1, y); + T.x = 0; + T.y = 1; + T.z = strengthFactor * this.getHeight(heightMap, x, y + 1) - strengthFactor * this.getHeight(heightMap, x, y - 1); + + float den = (float) Math.sqrt(S.z * S.z + T.z * T.z + 1); + N.x = -S.z; + N.y = -T.z; + N.z = 1; + N.divideLocal(den); + + // setting thge pixel in the result image + bumpMap.setRGB(x, y, this.vectorToColor(N.x, N.y, N.z)); + } + } + ByteBuffer byteBuffer = BufferUtils.createByteBuffer(image.getWidth() * image.getHeight() * 3); + ImageToAwt.convert(bumpMap, Format.RGB8, byteBuffer); + return new Texture2D(new Image(Format.RGB8, image.getWidth(), image.getHeight(), byteBuffer)); + } + + /** + * This method returns the height represented by the specified pixel in the given texture. + * The given texture should be a height-map. + * @param image + * the height-map texture + * @param x + * pixel's X coordinate + * @param y + * pixel's Y coordinate + * @return height reprezented by the given texture in the specified location + */ + protected int getHeight(BufferedImage image, int x, int y) { + if (x < 0) { + x = 0; + } else if (x >= image.getWidth()) { + x = image.getWidth() - 1; + } + if (y < 0) { + y = 0; + } else if (y >= image.getHeight()) { + y = image.getHeight() - 1; + } + return image.getRGB(x, y) & 0xff; + } + + /** + * This method transforms given vector's coordinates into ARGB color (A is always = 255). + * @param x X factor of the vector + * @param y Y factor of the vector + * @param z Z factor of the vector + * @return color representation of the given vector + */ + protected int vectorToColor(float x, float y, float z) { + int r = Math.round(255 * (x + 1f) / 2f); + int g = Math.round(255 * (y + 1f) / 2f); + int b = Math.round(255 * (z + 1f) / 2f); + return (255 << 24) + (r << 16) + (g << 8) + b; + } + /** * This class returns a texture read from the file or from packed blender data. *