package visualiser.layout; import javafx.geometry.Point3D; import javafx.scene.image.Image; import javafx.scene.image.ImageView; import javafx.scene.image.PixelWriter; import javafx.scene.image.WritableImage; import javafx.scene.paint.Color; import javafx.scene.paint.PhongMaterial; import javafx.scene.shape.Box; import javafx.scene.shape.MeshView; import javafx.scene.shape.Shape3D; import javafx.scene.shape.TriangleMesh; import visualiser.utils.PerlinNoiseGenerator; /** * Creates a SeaSurface */ public class SeaSurface extends Subject3D { private static Image image; /** * Sea Surface Constructor * * @param size size of the sea surface (has to be square for simplicity's sake) * @param freq frequency the perlin noise is to be generated at */ public SeaSurface(int size, double freq) { super(createSurface(size, freq), 0); image = new Image(getClass().getClassLoader().getResourceAsStream("images/skybox/ThickCloudsWaterDown2048.png")); } /** * Creates the sea surface * @param size size of sea noise array. * @param freq frequency of sea noise array. * @return The sea surface. */ private static Shape3D createSurface(int size, double freq) { float[][] noiseArray = PerlinNoiseGenerator.createNoise(size, freq); Image diffuseMap = createImage(noiseArray.length, noiseArray); //image PhongMaterial material = new PhongMaterial(); material.setDiffuseColor(Color.web("#FFFFFF")); material.setSpecularColor(Color.web("#000000")); material.setDiffuseMap(diffuseMap); Plane3D seaPlane = new Plane3D(noiseArray.length, noiseArray.length, 10, 10); MeshView seaSurface = new MeshView(seaPlane); seaSurface.setMaterial(material); seaSurface.setMouseTransparent(true); seaSurface.toFront(); return seaSurface; } /** * Create texture for uv mapping * * @param size size of the image to make * @param noise array of noise * @return image that is created */ private static Image createImage(double size, float[][] noise) { int width = (int) size; int height = (int) size; WritableImage wr = new WritableImage(width, height); PixelWriter pw = wr.getPixelWriter(); //interpolate colours based on noise for (int x = 0; x < width; x++) { for (int y = 0; y < height; y++) { float value = noise[x][y]; double gray = normalizeValue(value, -.5, .5, 0., 1.); gray = clamp(gray, 0, 1); //values to interpolate on Color brightBlue = new Color(0.06, 0.5, .78, 1); Color lightBlue = new Color(0.15, 0.68, .88, 1); Color lighterBlue = new Color(0.28, 0.73, .91, 1); Color colour = Color.WHITE.interpolate(brightBlue, gray).interpolate(lighterBlue, gray).interpolate(lightBlue, gray); pw.setColor(x, y, colour); } } return wr; } /** * Nomalises the values so that the colours are correct * * @param value value to normalise * @param min current min * @param max current max * @param newMin new min * @param newMax new max * @return returns normalised value */ private static double normalizeValue(double value, double min, double max, double newMin, double newMax) { return (value - min) * (newMax - newMin) / (max - min) + newMin; } /** * clamps a value between a min and max * * @param value value to clamp * @param min minimum value it can be * @param max maximum value it can be * @return result after clamp */ private static double clamp(double value, double min, double max) { if (Double.compare(value, min) < 0) return min; if (Double.compare(value, max) > 0) return max; return value; } /** * Prevent rescaling of sea surface * * @param scale ignored */ @Override public void setScale(double scale) { } }