appleseed Users Forum

Fun perturbing texture nodes


#1

Playing with Appleseed texture nodes.
There are some artifacts on the shadows edge I do not get rid of. Neverless, I really like how patterns turned out to be.

Those renders are generated with appleseed standard textures. Like Voronoi3D or Noise3D. Some variation is created by perturbing input coordinates.

First, I did not know how to perturb coordinates using Appleseed standard shaders.
Using OSL, I nibbled on a noise shader (Basing on Musgrave’s FBM or Multifractal), which does not generate a color output, but a vector output.

shader fieldNoise ( 

    string inMode = "Addition"
    [[ string label = "Chose Mode",
       string widget = "popup",
       string options = "Multiply|Addition" ]],

    int inOctaves = 1
    [[ string label = "Octaves",
       string widget = "slider" ]],

    vector inFrequency = vector(1,1,1)
    [[ string label = "Frequency"]],
    
    float inOffset = 1
    [[ string label = "Offset" ]],
    
    float inLacunarity = 2.13
    [[ string label = "Lacunarity"]],
    
    float inH = 1
    [[ string label = "H"]],
    
    point inP = P
    [[ string label = "Input Coords" ]],

    output vector outVec = 0
){
    vector offset = inOffset * normalize(inFrequency);
    point pos = inP*inFrequency;
    if (inMode == "Multiply") {
        vector vec = vector(1.0);

        for(int i=0; i< inOctaves; ++i) {
            vec *= ( noise("perlin", pos)+offset) * pow( inLacunarity, -inH*i);
            pos *= inLacunarity;
        }
        outVec = vec;
    } else if (inMode == "Addition") {
        vector vec = vector(0.0);

        for(int i=0; i< inOctaves; ++i) {
            vec += noise("perlin", pos) * pow( inLacunarity, -inH*i);
            pos *= inLacunarity;
        }
        outVec = vec;
    }
}

Now, I have a basic tool to create a vector field noise, which could be used to perturb textures. But, values are limited to vectors with x,y,z components inside some range [-c … c].
There needed to be a mapping, which maps those vector fields to a coordinate slot.

shader blendVectors
[[
    string as_node_name = "blend coordinates",
    string as_category = "util"
]]
(
    point inP = P
    [[ string label = "input Coordinates"]],

    vector inV0 = 0,
    float inA0 = 0
    [[ string label = "amplitude 0"]],

    vector inV1 = 0,
    float inA1 = 0
    [[ string label = "amplitude 1"]],

    vector inV2 = 0,
    float inA2 = 0
    [[ string label = "amplitude 2"]],

    output point outP = P
    )
{
    point pos = inP;
    pos += inA0*inV0;
    pos += inA1*inV1;
    pos += inA2*inV2;
    outP = pos;
}

#2

Very cool, especially that you were able to write your own OSL shaders to solve your problem!

@luis Don’t we have OSL nodes that would allow to do what @leonard7e is doing here?


#3

Hi Franz,
I do have some basic programming skills. But, I did not had courage to join an open source project yet.

I like to show a very basic node setup, perturbing voronoi node. (Mostly to show how the previous renders were done.)

not perturbed …

perturbed


#4

Hi.
You have some interesting results there, really cool.
Regarding your questions, there are several approaches.

To disturb the inputs for the 2D noise node, we have in the manifold2d noise a simple Perlin noise distortion built-in, see https://appleseed-maya.readthedocs.io/en/master/shaders/utilities/as_manifold2d.html#noise
This would apply if you want to distort the UV coords passed to the node.

Or you can use the built-in parameter “distortion”, which adds a vector Perlin noise offset with each octave, https://appleseed-maya.readthedocs.io/en/master/shaders/texture/as_noise2d.html#recursion-parameters

I suppose we could also either offer a vector variant of the node or extend the existing node with vector output, that would definitively be worthwhile.


#5

Hi Luis,
playing with as_manifold2d. Something like that.

Nodes which operate on vector fields or generate vector fields would be awesome.

With build-in distortion for noise I rather feel limited. It constrains where/how distortion is applied, and which kind of distortion is applied.


#6

At the moment, I have to restart Blender each time a shader has been changed.

Do you know a more elegant way to update shaders in Blenderseed? (Is there need to switch to Cycles for shader editing?)


#7

Trying to use a matrix to perturb coords.
Some noise nibblings …

The matrix based shader …

for each mode (multiply, addition) there is a line

pos = transform(in_Transform, pos) * in_Lacunarity;

The shader …

shader fieldNoiseM
    [[ string as_node_name = "Generate noise vector field"
    ,  string as_classification = "utility" ]]
(
    string in_Mode = "Addition"
    [[ string label = "Chose Mode",
       string widget = "popup",
       string options = "Multiply|Addition" ]],

    matrix in_Transform =
       matrix(1)
    [[ string label = "Matrix" ]],

    int in_Octaves = 1
    [[ string label = "Octaves",
       string widget = "slider" ]],

    vector in_Frequency = vector(1,1,1)
    [[ string label = "Frequency"]],

    float in_Lacunarity = 2.13
    [[ string label = "Lacunarity"]],

    float in_H = 1
    [[ string label = "H"]],

    float in_Offset = 1
    [[ string label = "Offset"]],

    point in_P = P
    [[ string label = "Input Coords" ]],

    string in_OutputMode = "Signed"
    [[ string label = "output to",
       string widget = "popup",
       string options = "Signed|Unsigned" ]],

    output vector outVec = 0,
){
    point pos = in_P*in_Frequency;

    if (in_Mode == "Multiply") {
        vector offset = in_Frequency * in_Offset;
        vector vec = vector(1.0);

        for(int i=0; i< in_Octaves; ++i) {
            vec *= (( (vector) noise("perlin", pos)) + offset)
                    * pow( in_Lacunarity, -in_H*i);

            pos = transform(in_Transform, pos) * in_Lacunarity;
        }
        outVec = vec;
    } else if (in_Mode == "Addition") {
        vector vec = vector(0.0);

        for(int i=0; i< in_Octaves; ++i) {
            vec += transform(in_Transform,
                        (vector) noise("perlin", pos))
                    * pow( in_Lacunarity, -in_H*i);
            pos = transform(in_Transform, pos) * in_Lacunarity;
        }
        outVec = vec;
    }

    // limit output coordinats to [0 .. 1]
    outVec = sigmoid(outVec);

    // default is (in_OutputMode == "Unigned")
    if (in_OutputMode == "Signed") {
        outVec = 2*outVec - vector(1);
    }
}

From 20th december I will be offline till next year.
Happy rendering.


#8

Very cool!

(Side note: a couple typos: chose -> choose, coordinats -> coordinates, Unigned -> unsigned)


#9

Hi Franz,
thank you for the correction. Didnt saw myself … my english rumbles. Names corrected for the file.

Two 3d voronoi nodes, both perturbed, and colors blended with asBlendColor. Created bump map from asBlendColor node output.

fieldNoiseMMatrix creates initial matrix for use in FieldNoiseM.
perturbCoords uses a vector to perturb coordinate input. If no coordinates input is present, it defaults to ‘P’.

The shaders are now in a git repository.


#10

Do you know a way how to reload OSL shaders in blenerseed, without the need to restart blender?


#11

According to our blenderseed developer @Jonathan_Dent this is currently not possible as the shader classes don’t unregister. An OSL script node, which allows loading of OSL source files (similar to the one Cycles has), is in the works.


#12

Hi Mango3, thank you for your detailed answer.

For debugging OSL shaders I will temporarly use Cycles OSL Script node.


#13

Hi Leonard, Mango3 relayed your question to me a few days ago and I gave him the quick answer, but i was wondering something:

You say you are interested in ‘reloading the shader’. Are you making changes to the input parameters, or just the guts of the shader execution? Reason I ask is that the shader files themselves (the .oso files) aren’t loaded into Blender. Instead they are scanned for creating the node UI. At render time we pass the filepath of the shader to appleseed and only at that time is the shader actually executed.

So if your input parameters don’t change you can make all the modifications you want to the actual shader execution, just make sure you recompile the .oso file when you want to see changes.

Input or UI changes are not currently updateable while Blender is still running, however like Mango3 said that should be changing soon. Esteban (one of the core devs) is working on a way to compile and run an OSL shader from source code (an .osl file) at runtime. That will allow for an OSL script node similar to what Cycles currently has.


#14

Hello Jonathan.

I need to reload shader to do some shader debugging.

Osltoy looks interesting, but all I can get is a black canvas.

Atm, for debugging shaders I change to Cycles. Honestly, playing with OSL shaders I preffer Appleseed over Cycles. You do a good job with the Nodes and shader Metadata. Looking forward for OSL script node.

Mh. I was not aware that blenderseed currently could do it too, if there is no change in the shader parameters … will try it.