Page 1 of 1

Efficient way to add noise on a gradient sky?

Posted: Thu May 21, 2020 7:04 pm
by Ats
Hello. Today I'm trying to add a noise gradient to make a nice sky.
Something a bit like that: https://blenderartists.org/t/grainy-noi ... nt/1229520

So I put together a working example, but I'm not happy at the generating speed of it... I tried to optimize the number of pixels to produce by playing with the width/height of the bitmap, and the repetition of the texture on the X axis. But still, there's a pause each time the texture is regenerated.
And right now, the bitmap size don't even match the resolution of the full screen (F9), so the noise is quite big and blurry...
Is there an efficient way to achieve that?

I'd like to get what we see on the rotating cube, but on the sky behind.

Code: Select all

<?xml version="1.0" encoding="iso-8859-1" ?>
<ZApplication Name="App" Caption="ZGameEditor application" FullScreen="255" ScreenMode="0" ClipFar="200" FileVersion="2">
  <OnUpdate>
    <ZExpression>
      <Expression>
<![CDATA[Timer -= App.DeltaTime;
if (Timer <= 0)
{
  Timer = 2;
  SkyColorBottom.X = 0.4 * rnd();
  SkyColorBottom.Y = 0.4 * rnd();
  SkyColorBottom.Z = 0.4 * rnd();
  SkyColorTop.X = 1 - 0.4 * rnd();
  SkyColorTop.Y = 1 - 0.4 * rnd();
  SkyColorTop.Z = 1 - 0.4 * rnd();
  @RefreshContent(Component: SkyBitmap);
}

rotateCube.Rotate.X+=.2*App.DeltaTime;
rotateCube.Rotate.Y+=.2*App.DeltaTime;]]>
      </Expression>
    </ZExpression>
  </OnUpdate>
  <OnRender>
    <RenderTransformGroup Scale="8 8 0">
      <Children>
        <UseMaterial Material="SkyMaterial"/>
        <RenderMesh Mesh="CubeMesh"/>
      </Children>
    </RenderTransformGroup>
    <RenderTransformGroup Name="rotateCube" Rotate="246.1398 242.6618 0">
      <Children>
        <RenderMesh Mesh="CubeMesh"/>
      </Children>
    </RenderTransformGroup>
  </OnRender>
  <Content>
    <Bitmap Name="SkyBitmap" Width="256" Height="768">
      <Producers>
        <BitmapExpression Name="SkyColorBitmap">
          <Expression>
<![CDATA[// Noise
float n = rnd()*.4;
// Color
float r = SkyColorTop.X*Y + SkyColorBottom.X*(1-Y*.7);
float g = SkyColorTop.Y*Y + SkyColorBottom.Y*(1-Y*.7);
float b = SkyColorTop.Z*Y + SkyColorBottom.Z*(1-Y*.7);
// https://en.wikipedia.org/wiki/Blend_modes#Soft_Light
//if (n < 0.5)
//{
  Pixel.R = 2*r*n + r*r*(1-2*n);
  Pixel.G = 2*g*n + g*g*(1-2*n);
  Pixel.B = 2*b*n + b*b*(1-2*n);
/*
}
else
{
  Pixel.R = 2*r*(1-n) + sqrt(r)*(2*n-1);
  Pixel.G = 2*g*(1-n) + sqrt(g)*(2*n-1);
  Pixel.B = 2*b*(1-n) + sqrt(b)*(2*n-1);
}
*/
Pixel.A = 1;]]>
          </Expression>
        </BitmapExpression>
      </Producers>
    </Bitmap>
    <Material Name="SkyMaterial" Shading="1" Light="0" Blend="1" ZBuffer="0">
      <Textures>
        <MaterialTexture Texture="SkyBitmap" TextureScale="4 1 1" TextureWrapMode="1" TexCoords="1" Origin="0 0 0"/>
      </Textures>
    </Material>
    <Mesh Name="CubeMesh">
      <Producers>
        <MeshBox/>
      </Producers>
    </Mesh>
    <Variable Name="SkyColorBottom" Type="7"/>
    <Variable Name="SkyColorTop" Type="7"/>
    <Variable Name="Timer"/>
  </Content>
</ZApplication>
Oh, by the way, the purpose is to generate sky gradients on the fly, the sky gradient could be a 64x64 bitmap with a 4096*4096 noise generated only once and blended into i,t if that could help for the speed. But is it possible to blend two materialTextures of different sizes inside a material? Or blend two materials?

Re: Efficient way to add noise on a gradient sky?

Posted: Thu May 21, 2020 8:34 pm
by Kjell
Hi Ats,
Ats wrote: Thu May 21, 2020 7:04 pmOh, by the way, the purpose is to generate sky gradients on the fly, the sky gradient could be a 64x64 bitmap with a 4096*4096 noise generated only once and blended into i,t if that could help for the speed. But is it possible to blend two materialTextures of different sizes inside a material?
Sure :) here's a simple example ..

Code: Select all

<?xml version="1.0" encoding="iso-8859-1" ?>
<ZApplication Name="App" Caption="ZGameEditor application" ScreenMode="0" ViewportRatio="3" RenderOrder="1" FileVersion="2">
  <OnLoaded>
    <SpawnModel Model="Box"/>
    <CallComponent Component="GradientRefresh"/>
  </OnLoaded>
  <OnUpdate>
    <Timer Interval="2">
      <OnTimer>
        <CallComponent Component="GradientRefresh"/>
      </OnTimer>
    </Timer>
  </OnUpdate>
  <OnRender>
    <UseMaterial Material="SkyMaterial"/>
    <RenderMesh Mesh="SkyMesh"/>
  </OnRender>
  <Content>
    <Bitmap Name="NoiseBitmap" Width="256" Height="256">
      <Producers>
        <BitmapExpression>
          <Expression>
<![CDATA[//

float s = random(0.8, 0.2);

//

Pixel.R = s;
Pixel.G = s;
Pixel.B = s;]]>
          </Expression>
        </BitmapExpression>
      </Producers>
    </Bitmap>
    <Bitmap Name="GradientBitmap" Width="2" Height="2">
      <Producers>
        <BitmapExpression>
          <Expression>
<![CDATA[//

if(Y)
{
  Pixel.R = GradientData[3];
  Pixel.G = GradientData[4];
  Pixel.B = GradientData[5];
}
else
{
  Pixel.R = GradientData[0];
  Pixel.G = GradientData[1];
  Pixel.B = GradientData[2];
}]]>
          </Expression>
        </BitmapExpression>
      </Producers>
    </Bitmap>
    <Array Name="GradientData" SizeDim1="6"/>
    <ZExpression Name="GradientRefresh">
      <Expression>
<![CDATA[//

GradientData[0] = random(0.2, 0.2);
GradientData[1] = random(0.2, 0.2);
GradientData[2] = random(0.2, 0.2);

GradientData[3] = random(0.8, 0.2);
GradientData[4] = random(0.8, 0.2);
GradientData[5] = random(0.8, 0.2);

//

@RefreshContent(Component: GradientBitmap);]]>
      </Expression>
    </ZExpression>
    <Model Name="Box" RotationVelocity="0.2 0.2 0">
      <OnRender>
        <UseMaterial Material="BoxMaterial"/>
        <RenderMesh Mesh="BoxMesh"/>
      </OnRender>
    </Model>
    <Mesh Name="BoxMesh">
      <Producers>
        <MeshBox/>
      </Producers>
    </Mesh>
    <Material Name="BoxMaterial">
      <Textures>
        <MaterialTexture Texture="GradientBitmap" TextureScale="1 0.25 1" TextureY="0.125" TextureWrapMode="2"/>
        <MaterialTexture Texture="NoiseBitmap" TextureWrapMode="1" TexCoords="1"/>
      </Textures>
    </Material>
    <Mesh Name="SkyMesh">
      <Producers>
        <MeshBox Scale="8 4.5 1" Grid2DOnly="255"/>
      </Producers>
    </Mesh>
    <Material Name="SkyMaterial" ZBuffer="0">
      <Textures>
        <MaterialTexture Texture="GradientBitmap" TextureScale="1 0.5 1" TexCoords="1"/>
        <MaterialTexture Texture="NoiseBitmap" TextureScale="5 2.8125 1" TextureWrapMode="1" TexCoords="1"/>
      </Textures>
    </Material>
  </Content>
</ZApplication>
K

Re: Efficient way to add noise on a gradient sky?

Posted: Fri May 22, 2020 8:59 am
by Ats
Thanks, Kjell. As always, I'm amazed by the simplicity of your examples. I didn't even know that a 2x2 bitmap would suffice to make a beautiful gradient and that the linear filter would do the trick :D