Chromatic Aberration effect

All topics about ZGameEditor goes here.

Moderator: Moderators

Post Reply
User avatar
rrTea
Posts: 475
Joined: Sat Feb 15, 2014 9:54 am

Chromatic Aberration effect

Post by rrTea »

I'm trying to add a bit of CA to a project, like in this image for example.
Image

My idea was to render everything into a texture and draw RGB channels separately using addition as blending mode. This actually works perfectly, but only where there are some pixels (the rest has Alpha 0). For example in this case I'd expect the background to be blue (since the RenderTarget has blue as the ClearColor) but it ends up black. I'm not sure I'm explaining it properly but this should show it clearly enough:

Code: Select all

<?xml version="1.0" encoding="iso-8859-1" ?>
<ZApplication Name="App" Caption="ZGameEditor application" ClearColor="0.502 0.502 1 1" ScreenMode="0" Camera="cam_Ortho" LightPosition="0 10 5" ViewportRatio="3" FileVersion="2">
  <OnLoaded>
    <ZExpression>
      <Expression>
<![CDATA[float TilesPerY = 12;
float TilesPerX = 21;

cam_Ortho.OrthoZoom = TilesPerY;

float CameraRatio = 16/9;

ProjectionRender.Scale.X = TilesPerY*CameraRatio;
ProjectionRender.Scale.Y = TilesPerY;]]>
      </Expression>
    </ZExpression>
  </OnLoaded>
  <OnUpdate>
    <ZExpression>
      <Expression>
<![CDATA[transf_Box.Rotate.X = noise2(App.Time*0.0234,sin(App.Time*0.054));
transf_Box.Rotate.Y = noise2(App.Time*0.0235,cos(App.Time*0.034));
transf_Box.Rotate.Z = noise2(sin(App.Time*0.07+0.5), App.Time*0.07);]]>
      </Expression>
    </ZExpression>
  </OnUpdate>
  <OnBeginRenderPass>
    <SetRenderTarget RenderTarget="rendTarg_CamFeedDouble"/>
  </OnBeginRenderPass>
  <OnRender>
    <RenderTransformGroup Name="transf_Box" Scale="3 3 3" Rotate="0.1015 0.1675 0.139">
      <Children>
        <UseMaterial Material="mat_Lit"/>
        <RenderMesh Mesh="mesh_Box"/>
        <UseMaterial Material="mat_Wireframe"/>
        <RenderTransform Scale="2 2 2"/>
        <RenderMesh Mesh="mesh_Crystal"/>
      </Children>
    </RenderTransformGroup>
    <RenderTransformGroup Name="ProjectionRender" Comment="Used at the end of the rendering pass" Scale="21.3333 12 1">
      <Children>
        <Group>
          <Children>
            <SetRenderTarget RenderTarget="rendTarg_CamFeed"/>
            <UseMaterial Material="mat_CamFeedDouble"/>
            <RenderMesh Mesh="mesh_Rectangle"/>
            <SetRenderTarget Comment="Free"/>
          </Children>
        </Group>
        <Group Comment="Base">
          <Children>
            <UseMaterial Material="mat_ColorMondrian"/>
            <RenderSetColor Color="0 0 0 1"/>
            <RenderMesh Mesh="mesh_Rectangle"/>
          </Children>
        </Group>
        <Group Comment="Separate RGB">
          <Children>
            <UseMaterial Material="mat_CamFeed"/>
            <RenderSetColor Comment="Red" Color="1 0 0 1"/>
            <RenderMesh Mesh="mesh_Rectangle"/>
            <RenderSetColor Comment="Green" Color="0 1 0 1"/>
            <RenderTransform Name="transf_G" Rotate="0 0 -0.0007"/>
            <RenderMesh Mesh="mesh_Rectangle"/>
            <RenderSetColor Comment="Blue" Color="0 0 1 1"/>
            <RenderTransform Name="transf_B" Rotate="0 0 -0.0021"/>
            <RenderMesh Mesh="mesh_Rectangle"/>
          </Children>
        </Group>
      </Children>
    </RenderTransformGroup>
  </OnRender>
  <Content>
    <Material Name="mat_ColorMondrian" Shading="1" Light="0"/>
    <RenderTarget Name="rendTarg_CamFeedDouble" Comment="512 * 288" CustomWidth="512" CustomHeight="288" ClearColor="0.5333 0.7725 0.9294 1"/>
    <RenderTarget Name="rendTarg_CamFeed" Comment="256 * 144" CustomWidth="256" CustomHeight="144" ClearColor="0.5333 0.7725 0.9294 1" Filter="1"/>
    <Material Name="mat_CamFeedDouble" Shading="1" Light="0" ZBuffer="0">
      <Textures>
        <MaterialTexture Name="matTex_CamFeedDouble" RenderTarget="rendTarg_CamFeedDouble" TextureWrapMode="2" TexCoords="1"/>
      </Textures>
    </Material>
    <Material Name="mat_CamFeed" Shading="1" Light="0" Blend="2" ZBuffer="0">
      <Textures>
        <MaterialTexture RenderTarget="rendTarg_CamFeed" TextureWrapMode="2" TexCoords="1"/>
      </Textures>
    </Material>
    <Camera Name="cam_Ortho" Kind="1" Position="0 0 15" OrthoZoom="12"/>
    <Camera Name="cam_Perspective" Position="0 -3.8 30" Rotation="-0.02 0 0"/>
    <Mesh Name="mesh_Rectangle">
      <Producers>
        <MeshBox Grid2DOnly="255"/>
      </Producers>
    </Mesh>
    <Material Name="mat_Lit"/>
    <Mesh Name="mesh_Box">
      <Producers>
        <MeshBox/>
      </Producers>
    </Mesh>
    <Material Name="mat_Wireframe" Shading="2" Light="0"/>
    <Mesh Name="mesh_Crystal">
      <Producers>
        <MeshSphere ZSamples="19"/>
        <MeshNoise Scale="3 3 3" NoiseSpeed="3.5 2.44 1.03" NoiseScale="2.3 1.9 2.49"/>
        <MeshTransform Scale="0.5 0.5 0.5"/>
      </Producers>
    </Mesh>
  </Content>
</ZApplication>
One other problem I noticed with this approach is that sometimes a perfectly white RenderNet renders incorrectly (as middle gray instead of white) while everything else renders normally but I can't reproduce it in isolation. Anyway is it possible to achieve this effect using components?
Last edited by rrTea on Thu Dec 06, 2018 10:21 am, edited 1 time in total.
User avatar
Kjell
Posts: 1876
Joined: Sat Feb 23, 2008 11:15 pm

Re: Color refraction effect

Post by Kjell »

Hi rrTea,

Try the following approach :wink:

Code: Select all

<?xml version="1.0" encoding="iso-8859-1" ?>
<ZApplication Name="App" Caption="ZGameEditor application" ViewportRatio="3" FileVersion="2">
  <OnUpdate>
    <ZExpression>
      <Expression>
<![CDATA[//

DiamondTransform.Rotate.X = sin(App.Time);
DiamondTransform.Rotate.Y = cos(App.Time);

//

BoxTransform.Rotate.X = App.Time/12;
BoxTransform.Rotate.Z = App.Time/16;

//

ClearMaterial.Color.B = sin(App.Time)/4+0.25;]]>
      </Expression>
    </ZExpression>
  </OnUpdate>
  <OnBeginRenderPass>
    <SetRenderTarget RenderTarget="Canvas"/>
  </OnBeginRenderPass>
  <OnRender>
    <UseMaterial Material="BoxMaterial"/>
    <RenderTransformGroup Name="BoxTransform">
      <Children>
        <RenderMesh Mesh="BoxMesh"/>
      </Children>
    </RenderTransformGroup>
    <UseMaterial Material="DiamondMaterial"/>
    <RenderTransformGroup Name="DiamondTransform">
      <Children>
        <RenderMesh Mesh="DiamondMesh"/>
      </Children>
    </RenderTransformGroup>
    <SetRenderTarget/>
    <ZExpression Comment="Identity Matrix">
      <Expression>
<![CDATA[//

mat4 m;

for(int i=0; i<4; i++)
{
  m[i,i] = 1;
}

setMatrix(0, m);
setMatrix(1, m);]]>
      </Expression>
    </ZExpression>
    <UseMaterial Material="ClearMaterial"/>
    <RenderMesh Mesh="CanvasMesh"/>
    <UseMaterial Material="CanvasMaterial"/>
    <Repeat Name="CanvasRepeat" Count="3" WhileExp="//">
      <OnIteration>
        <ZExpression>
          <Expression>
<![CDATA[//

switch(CanvasRepeat.Iteration)
{
  case 0:
    CanvasColor.Color.R = 1;
    CanvasColor.Color.B = 0;

    CanvasTransform.Translate.X = -2/320;
    break;

  case 1:
    CanvasColor.Color.R = 0;
    CanvasColor.Color.G = 1;

    CanvasTransform.Translate.X = 0;
    break;

  case 2:
    CanvasColor.Color.G = 0;
    CanvasColor.Color.B = 1;

    CanvasTransform.Translate.X = 2/320;
    break;
}]]>
          </Expression>
        </ZExpression>
        <RenderSetColor Name="CanvasColor" Color="0 0 1 1"/>
        <RenderTransformGroup Name="CanvasTransform" Translate="0.0063 0 0">
          <Children>
            <RenderMesh Mesh="CanvasMesh"/>
          </Children>
        </RenderTransformGroup>
      </OnIteration>
    </Repeat>
  </OnRender>
  <Content>
    <Mesh Name="BoxMesh">
      <Producers>
        <MeshBox Scale="-2 2 2"/>
      </Producers>
    </Mesh>
    <Material Name="BoxMaterial" Shading="1" Color="0.251 0.251 0.251 1"/>
    <Mesh Name="DiamondMesh">
      <Producers>
        <MeshSphere ZSamples="3" RadialSamples="8"/>
      </Producers>
    </Mesh>
    <Material Name="DiamondMaterial" Shading="2" Light="0"/>
    <RenderTarget Name="Canvas" CustomWidth="320" CustomHeight="180" Filter="1"/>
    <Mesh Name="CanvasMesh">
      <Producers>
        <MeshBox Grid2DOnly="255"/>
      </Producers>
    </Mesh>
    <Material Name="CanvasMaterial" Blend="2" ZBuffer="0">
      <Textures>
        <MaterialTexture RenderTarget="Canvas" TextureWrapMode="2" TexCoords="1"/>
      </Textures>
    </Material>
    <Material Name="ClearMaterial" Shading="1" Color="0 0 0.1147 1" Light="0" ZBuffer="0"/>
  </Content>
</ZApplication>
K
User avatar
rrTea
Posts: 475
Joined: Sat Feb 15, 2014 9:54 am

Re: Color refraction effect

Post by rrTea »

Hi Kjell!

Isn't this just a "correct" / much better put up version of what I'm already doing? (And without manual AA and other unnecessary things I should have omitted anyway since that is not directly connected with the question etc.)

1. Render everything into RenderTarget
2. Free RenderTarget
3. Prepare the base (black) against which to render the RenderTarget texture
4. Render each channel of the RenderTarget texture using addition + slight offset

But I'd like to have a particular color in the background, and with this approach I can only achieve this by always rendering a big mesh in this color in the background before rendering anything. I can't set any other color other than black in step 3 because then the whole image gets brighter. Like if in the last line of the OnUpdate / ZExpression in your example I added

Code: Select all

ClearMaterial.Color.B = sin(App.Time)/4+0.25;
ClearMaterial.Color.R = 1;
ClearMaterial.Color.G = 1;
the inverted cube would also get yellow (it should stay grey).

I'm trying to avoid having to manually always making sure to draw a huge background mesh under all conditions. The simplest way I managed to achieve this is to just draw the background mesh in OnBeginRenderPass (which I can also use as a wallpaper) but from what I understand this is not what OnBeginRenderPass is meant for.
User avatar
Kjell
Posts: 1876
Joined: Sat Feb 23, 2008 11:15 pm

Re: Color refraction effect

Post by Kjell »

Hi rrTea,

Ah, i see what you're getting at. I was trying to illustrate in my example that you have to use a black frame-buffer to render your 3 channels onto because of the additive blending, but you wanted to simply clear the RenderTarget with a non-transparent color value. This is a bug / oversight .. line 2326 of Renderer.pas neglects to pass the alpha value of the RenderTarget.ClearColor, while it obviously should. In the meantime you use a DIY solution ..

Code: Select all

<?xml version="1.0" encoding="iso-8859-1" ?>
<ZApplication Name="App" Caption="ZGameEditor application" ViewportRatio="3" FileVersion="2">
  <OnLoaded>
    <ZExternalLibrary ModuleName="opengl32">
      <Source>
<![CDATA[//

void glClear(int mode){}
void glClearColor(float red, float green, float blue, float alpha){}]]>
      </Source>
    </ZExternalLibrary>
  </OnLoaded>
  <OnUpdate>
    <ZExpression>
      <Expression>
<![CDATA[//

DiamondTransform.Rotate.X = sin(App.Time);
DiamondTransform.Rotate.Y = cos(App.Time);

//

BoxTransform.Rotate.X = App.Time/12;
BoxTransform.Rotate.Z = App.Time/16;

//

ClearMaterial.Color.B = sin(App.Time)/4+0.25;]]>
      </Expression>
    </ZExpression>
  </OnUpdate>
  <OnBeginRenderPass>
    <SetRenderTarget RenderTarget="Canvas"/>
    <ZExpression>
      <Expression>
<![CDATA[//

glClearColor(0.5, 0, 0, 1);
glClear(0x4100);]]>
      </Expression>
    </ZExpression>
  </OnBeginRenderPass>
  <OnRender>
    <UseMaterial Material="BoxMaterial"/>
    <RenderTransformGroup Name="BoxTransform" Rotate="8.4503 0 6.3377">
      <Children>
        <RenderMesh Mesh="BoxMesh"/>
      </Children>
    </RenderTransformGroup>
    <UseMaterial Material="DiamondMaterial"/>
    <RenderTransformGroup Name="DiamondTransform">
      <Children>
        <RenderMesh Mesh="DiamondMesh"/>
      </Children>
    </RenderTransformGroup>
    <SetRenderTarget/>
    <ZExpression Comment="Identity Matrix">
      <Expression>
<![CDATA[//

mat4 m;

for(int i=0; i<4; i++)
{
  m[i,i] = 1;
}

setMatrix(0, m);
setMatrix(1, m);]]>
      </Expression>
    </ZExpression>
    <UseMaterial Material="ClearMaterial"/>
    <RenderMesh Mesh="CanvasMesh"/>
    <UseMaterial Material="CanvasMaterial"/>
    <Repeat Name="CanvasRepeat" Count="3" WhileExp="//">
      <OnIteration>
        <ZExpression>
          <Expression>
<![CDATA[//

switch(CanvasRepeat.Iteration)
{
  case 0:
    CanvasColor.Color.R = 1;
    CanvasColor.Color.B = 0;

    CanvasTransform.Translate.X = -2/320;
    break;

  case 1:
    CanvasColor.Color.R = 0;
    CanvasColor.Color.G = 1;

    CanvasTransform.Translate.X = 0;
    break;

  case 2:
    CanvasColor.Color.G = 0;
    CanvasColor.Color.B = 1;

    CanvasTransform.Translate.X = 2/320;
    break;
}]]>
          </Expression>
        </ZExpression>
        <RenderSetColor Name="CanvasColor" Color="0 0 1 1"/>
        <RenderTransformGroup Name="CanvasTransform" Translate="0.0063 0 0">
          <Children>
            <RenderMesh Mesh="CanvasMesh"/>
          </Children>
        </RenderTransformGroup>
      </OnIteration>
    </Repeat>
  </OnRender>
  <Content>
    <Mesh Name="BoxMesh">
      <Producers>
        <MeshBox Scale="-2 2 2"/>
      </Producers>
    </Mesh>
    <Material Name="BoxMaterial" Shading="1" Color="0.251 0.251 0.251 1"/>
    <Mesh Name="DiamondMesh">
      <Producers>
        <MeshSphere ZSamples="3" RadialSamples="8"/>
      </Producers>
    </Mesh>
    <Material Name="DiamondMaterial" Shading="2" Light="0"/>
    <RenderTarget Name="Canvas" CustomWidth="320" CustomHeight="180" Filter="1"/>
    <Mesh Name="CanvasMesh">
      <Producers>
        <MeshBox Grid2DOnly="255"/>
      </Producers>
    </Mesh>
    <Material Name="CanvasMaterial" Blend="2" ZBuffer="0">
      <Textures>
        <MaterialTexture RenderTarget="Canvas" TextureWrapMode="2" TexCoords="1"/>
      </Textures>
    </Material>
    <Material Name="ClearMaterial" Shading="1" Color="0 0 0.4414 1" Light="0" ZBuffer="0"/>
  </Content>
</ZApplication>
K
User avatar
rrTea
Posts: 475
Joined: Sat Feb 15, 2014 9:54 am

Re: Color refraction effect

Post by rrTea »

Ah I see,… Sorry I didn't explain it better! Well your example is still useful as it showed me how it's done "for real" ;) Thanks!
User avatar
VilleK
Site Admin
Posts: 2274
Joined: Mon Jan 15, 2007 4:50 pm
Location: Stockholm, Sweden
Contact:

Re: Color refraction effect

Post by VilleK »

Kjell wrote: Thu Dec 06, 2018 9:25 amThis is a bug / oversight .. line 2326 of Renderer.pas neglects to pass the alpha value of the RenderTarget.ClearColor, while it obviously should.
Strange, I wonder if there was a reason for that. I'll change it.
User avatar
rrTea
Posts: 475
Joined: Sat Feb 15, 2014 9:54 am

Re: Chromatic Aberration effect

Post by rrTea »

Ville: Actually I can see many cases where one'd like to draw only "what exists" in RenderTarget, for example superimposing a rendering of low resolution over a scene or something... or maybe for interface / HUD etc elements.

Kjell: I tried the DIY solution, and it works, but there are some cases where it gives unexpected results. For example bitmaps sometimes get a dark outline, and I can't see where would this be coming from. The code for the particle bitmap is a simple

Code: Select all

Pixel = 1;

float X1, Y1, B, S;
X1 = 0.5-x;
Y1 = 0.5-y;

B = 32/1f    ; // 64 = BitMapsize | 2 = Anti-Aliasing bias ( in pixels )

pixel.A = B*0.5-sqrt(X1*X1+Y1*Y1)*B;
and the material for rendering the particles uses Alpha/OneMinusSourceAlpha as blending mode. I also noticed the same effect on some other things like fonts etc.
Attachments
this is what it should look like
this is what it should look like
剪貼簿圖片 (1).png (10.69 KiB) Viewed 10897 times
with manual solution
with manual solution
剪貼簿圖片.png (20.84 KiB) Viewed 10897 times
User avatar
Kjell
Posts: 1876
Joined: Sat Feb 23, 2008 11:15 pm

Re: Chromatic Aberration effect

Post by Kjell »

Hi rrTea,
rrTea wrote: Fri Dec 07, 2018 4:39 amI tried the DIY solution, and it works, but there are some cases where it gives unexpected results. For example bitmaps sometimes get a dark outline, and I can't see where would this be coming from.
It might not give the results you expected, but it's actually behaving the way it should. When you're using Alpha/OneMinusSourceAlpha blending the alpha values of the frame-buffer you're rendering to are set / overridden by any drawn pixels. So the "dark outlines" appear because the frame-buffer is semi-transparent in those places.

K
Post Reply