Links

Categories

Tags


« | Main | »

Render World goes 3D

By Jewe | August 3, 2015

I have updated the “Render World” effect for IrfanView Sandbox 1.3 with global lighting. With striking results.

Render World Effect

Incredible Detail

The effect allows for incredibly detailed land textures. Click these thumbnail images to zoom in and out of the region.

Render World Effect Render World Effect Render World Effect Render World Effect Render World Effect
 

Download this script

The script is included with IrfanView Filter Sandbox 1.3.

Code

//------------------------------------------------------------------------------
// Render World
//
// written by Stefan Kuhn
// http://www.jewe.org
//
// Renders a three dimensional world map based on Perlin noise. This file
// requires IrfanView Sandbox plug-in version 1.3 or later.
//------------------------------------------------------------------------------

class RenderWorld implements Effect
{
    Slider XSeed, YSeed, Freq1, SPers, SOcts, SInt, Relief, Trace, SInt3, Freq3, Angle;
    Label Rand, Light, Land, Detail;

    const float[] Heights = {
        0.00,  // deep water
        0.20,  // shallow water
        0.25,  // dark sand
        0.30,  // sand
        0.35,  // dark grass
        0.50,  // grass
        0.70,  // dirt
        0.80,  // dark stone
        0.90,  // stone
        0.95,  // dirty snow
        1.00   // snow
    };

    const ColorRGB[] Hues = {
        ColorRGB::FromHSL(240, 0.5, 0.3),  // deep water
        ColorRGB::FromHSL(210, 0.4, 0.5),  // shallow water
        ColorRGB::FromHSL(60, 0.3, 0.5),   // dark sand
        ColorRGB::FromHSL(60, 0.3, 0.7),   // sand
        ColorRGB::FromHSL(110, 0.5, 0.3),  // dark grass
        ColorRGB::FromHSL(130, 0.3, 0.4),  // grass
        ColorRGB::FromHSL(40, 0.4, 0.3),   // dirt
        ColorRGB::FromHSL(0, 0, 0.3),      // dark stone
        ColorRGB::FromHSL(0, 0, 0.5),      // stone
        ColorRGB::FromHSL(0, 0, 0.8),      // dirty snow
        ColorRGB::FromHSL(0, 0, 0.9)       // snow
    };

    method RenderWorld()
    {
        Rand   = new Label("General Properties");
        XSeed  = new Slider("X Seed (Start Position)",       "", 0,   0, 255,   91);
        YSeed  = new Slider("Y Seed (Start Position)",       "", 0,   0, 255,   90);
        Freq1  = new Slider("Frequency (Zoom Factor)",       "", 2,  -1,   1,    0);
        Land   = new Label("Landscape Rendering");
        Freq3  = new Slider("Variation Frequency",           "", 1,   1,   5,    4);
        SInt3  = new Slider("Variation Amount",              "", 2,   0,   1,  0.5);
        Detail = new Label("Level of Detail");
        SOcts  = new Slider("Octaves",                       "", 0,   1,  10,   10);
        SPers  = new Slider("Persistence (Smoothing)",       "", 2,   0,   1,  0.4);
        SInt   = new Slider("Balance (Strength)",            "", 2,   0,   1, 0.95);
        Light  = new Label("Lighting");
        Relief = new Slider("Relief Strength",               "", 0,   0,  10,    2);
        Trace  = new Slider("Trace Distance (Render Time!)", "", 0,   1,  50,   20);
        Angle  = new Slider("Light Angle",               " deg", 0,-180, 180,  -45);

        Freq1.ToString = (sender) => string::format("%2.2f", Pow(10, sender.Value));
        Freq3.ToString = (sender) => string::format("%g x", Pow(10, sender.Value));
    }

    method Parameter[] GetParameters()
    {
        return {
            Rand, XSeed, YSeed, Freq1,
            Land, Freq3, SInt3,
            Detail, SOcts, SPers, SInt,
            Light, Relief, Trace, Angle
        };
    }

    method EffectInfo GetEffectInfo()
    {
        return new EffectInfo(
            "Render World",
            "by Jewe",
            "Renders a three dimensional world map. This may take a few minutes with big images."
        );
    }

    method DoEffect(Image img)
    {
        // create rasterizer for the image
        RasterizerSSE land = new RasterizerSSE(img);
        // set up Perlin noise
        PerlinNoise perlin = new PerlinNoise(SOcts.Value, SPers.Value);
        float zoom = Pow(10, Freq1.Value);
        float freq1 = 0.002 * 2.0 * zoom;
        float freq2 = 0.02 * 7.0 * zoom;
        float freq3 = 0.000001 * Pow(10, Freq3.Value) * zoom;
        float startX = XSeed.Value * img.Width * 0.5 / zoom;
        float startY = YSeed.Value * img.Height * 0.5 / zoom;
        float seed1X = startX * freq1;
        float seed1Y = startY * freq1;
        float seed2X = startX * freq2;
        float seed2Y = startY * freq2;
        float seed3X = startX * freq3;
        float seed3Y = startY * freq3;
        float int1 = SInt.Value;
        float int2 = 1.0 - int1;
        float int3 = SInt3.Value;
        float relief = Relief.Value;
        int traceDist = Trace.Value / Pow(4.0, Freq1.Value);
        float angle = Angle.Value;
        // render height field
        FloatMatrix heightMap = new FloatMatrix(img.Width, img.Height);
        heightMap.Process(function(x, y, z) {
            float fx = x;
            float fy = y;
            return (
                perlin.Random(seed1X + fx * freq1, seed1Y + fy * freq1) * int1 +
                perlin.Random(seed2X + fx * freq2, seed2Y + fy * freq2) * int2 +
                perlin.Random(seed3X + fx * freq3, seed3Y + fy * freq3) * int3)
                * 0.3 + 0.5;
        });
        // render global light
        FloatMatrix lightMap = new FloatMatrix(img.Width, img.Height);
        lightMap.Process(function(x, y, z) {
            float a = heightMap.Get(x, y);
            float b = heightMap.Avg(x, y, traceDist, angle);
            float c = heightMap.Avg(x, y, 1, angle);
            return (a - b + a - c) * relief;
        });
        // render land surface
        land.ProcessPixels(function(x, y, z) {
            ColorRGB c = GetLandColor(heightMap.Get(x, y));
            c.Add(lightMap.Get(x, y));
            z.Set(c);
        });
        // finalize
        land.Finalize();
    }

    function ColorRGB GetLandColor(float h)
    {
        int i = Max(Pred(h, Heights), 0);
        int j = Min(i + 1, Heights.length - 1);
        float a = Norm(h, Heights[i], Heights[j]);
        return ColorRGB::Blend(Hues[i], Hues[j], a);
    }
}

Topics: code examples, filter sandbox, news | Comments Off on Render World goes 3D

Comments are closed.