Package com.ardor3d.extension.terrain.util

Source Code of com.ardor3d.extension.terrain.util.NormalMapUtil

/**
* Copyright (c) 2008-2012 Ardor Labs, Inc.
*
* This file is part of Ardor3D.
*
* Ardor3D is free software: you can redistribute it and/or modify it
* under the terms of its license which may be found in the accompanying
* LICENSE file or at <http://www.ardor3d.com/LICENSE>.
*/

package com.ardor3d.extension.terrain.util;

import java.nio.ByteBuffer;

import com.ardor3d.image.Image;
import com.ardor3d.image.ImageDataFormat;
import com.ardor3d.image.PixelDataType;
import com.ardor3d.math.Vector3;

public class NormalMapUtil {

    /**
     * Generate an image from the given terrain height data to be used as a source for terrain normal maps.
     *
     * @param heightmap
     *            the base height data. Generally this is the most detailed height data available. It must be a square
     *            heightmap, with a side of "side" as passed below.
     * @param side
     *            the number of samples on a side of the heightmap. This could be calculated by taking the squareroot of
     *            heightmap.length, but generally this number is well known by the caller.
     * @param heightScale
     *            the scaling factor applied to the heightMap values to get real world height.
     * @param xGridSpacing
     *            real world spacing between grid in the x direction
     * @param zGridSpacing
     *            real world spacing between grid in the z direction
     * @return the normal image.
     */
    public static Image constructNormalMap(final float[] heightmap, final int side, final double heightScale,
            final double xGridSpacing, final double zGridSpacing) {
        int x, z;
        final Vector3 n = new Vector3();
        final Vector3 n2 = new Vector3();
        final ByteBuffer data = ByteBuffer.allocateDirect(side * side * 3);
        final Image normalMap = new Image(ImageDataFormat.RGB, PixelDataType.UnsignedByte, side, side, data, null);
        for (z = 0; z < side; ++z) {
            for (x = 0; x < side; ++x) {
                if (x == 0 || z == 0 || x == side - 1 || z == side - 1) {
                    n.set(0, 0, 1);
                } else {
                    // change across "x" from point to our "left" to point on our "right"
                    double dXh = heightmap[z * side + x - 1] - heightmap[z * side + x + 1];
                    if (dXh != 0) {
                        // alter by our height scale
                        dXh *= heightScale;
                        // determine slope of perpendicular line
                        final double slopeX = 2.0 * xGridSpacing / dXh;
                        // now plug into cos(arctan(x)) to get unit length vector
                        n.setX(Math.copySign(1.0 / Math.sqrt(1 + slopeX * slopeX), dXh));
                        n.setY(0);
                        n.setZ(Math.abs(slopeX * n.getX()));
                    } else {
                        n.set(0, 0, 1);
                    }

                    // change across "z" from point "above" us to point "below" us
                    double dZh = heightmap[(z - 1) * side + x] - heightmap[(z + 1) * side + x];
                    if (dZh != 0) {
                        // alter by our height scale
                        dZh *= heightScale;
                        // determine slope of perpendicular line
                        final double slopeZ = 2.0 * zGridSpacing / dZh;
                        // now plug into cos(arctan(x)) to get unit length vector
                        n2.setX(0);
                        n2.setY(Math.copySign(1.0 / Math.sqrt(1 + slopeZ * slopeZ), dZh));
                        n2.setZ(Math.abs(slopeZ * n2.getY()));
                    } else {
                        n2.set(0, 0, 1);
                    }

                    // add together the vectors across X and Z and normalize to get final normal
                    n.addLocal(n2).normalizeLocal();
                }
                // System.err.println(n);
                data.put(3 * (z * side + x) + 0, (byte) ((int) (127 * n.getX()) + 128));
                data.put(3 * (z * side + x) + 1, (byte) ((int) (127 * n.getY()) + 128));
                data.put(3 * (z * side + x) + 2, (byte) ((int) (127 * n.getZ()) + 128));
            }
        }

        return normalMap;
    }
}
TOP

Related Classes of com.ardor3d.extension.terrain.util.NormalMapUtil

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.