Jump to content

[TOPIC: topicViewTemplate]
[GLOBAL: userSmallPhoto]
Photo

Stencil buffer or something like
Started by nick.g Mar 29 2017 09:31 AM

11 replies to this topic
graphics stencil buffer overlap colors mask overlay color

Best Answer StarCrunch , 30 March 2017 - 01:50 PM

Hi.

 

I had a go and seem to have something working. This uses the memory bitmap plugin, so see the instructions for that.

local memoryBitmap = require("plugin.memoryBitmap")

-- Save the current texture filter settings. Temporarily set them to
-- nearest mode, since we want to snap to colors rather than blend
-- with our neighbors.
local def = display.getDefault("minTextureFilter")

display.setDefault("minTextureFilter", "nearest")

-- Make a one-dimensional texture to store as many colors as we support. It
-- might be best if this is a power-of-2, but maybe it doesn't matter.
local Width = 4

local colors = memoryBitmap.newTexture{ width = Width, height = 1, format = "rgb" }

-- Put color #1 in column #1, #2 in column #2, etc.
colors:setPixel(1, 1, 0, 1, 0) -- green at (1, 1)
colors:setPixel(2, 1, 1, 0, 0) -- red at (2, 1)

-- Restore the previous filter mode.
display.setDefault("minTextureFilter", def)

-- Render our geometry in a canvas so that we can reference it in our effect
local function Rect (canvas, x, y, w, h)
  local rect = display.newRect(x, y, w, h)

  rect.blendMode = "add" -- Accumulate the object...

  rect:setFillColor(1 / Width) -- ...by this much. (The final result is the
                               -- offset into our color set.) This emulates
                               -- stencil addition, basically.
  canvas:draw(rect)

  return rect
end

-- Define the region that will display the effect.
local region = display.newRect(display.contentCenterX, display.contentCenterY, 250, 250)

-- Make a canvas into which the objects will be rendered.
local canvas = graphics.newTexture{ type = "canvas", width = region.width, height = region.height }

-- Create a P-shaped object like the one in your example above, stuffing
-- the pieces into the canvas.
Rect(canvas, -10, 20, 110, 20)
Rect(canvas, 35, -40, 20, 100)
Rect(canvas, -10, -80, 70, 20)
Rect(canvas, -35, 0, 20, 140)

local r = Rect(canvas, -50, -80, 60, 20)

r.rotation = -45

-- Commit the draw calls to the canvas.
canvas:invalidate()

-- Register an effect to the draw region that takes the canvas in sampler #0 and
-- the color map in sampler #1. 
region.fill = {
  type = "composite",
  paint1 = { type = "image", filename = canvas.filename, baseDir = canvas.baseDir },
  paint2 = { type = "image", filename = colors.filename, baseDir = colors.baseDir }
}

-- Create a blend effect.
local kernel = { category = "composite", name = "blender" }

kernel.fragment = [[
  P_COLOR vec4 FragmentKernel (P_UV vec2 uv)
  {
    P_COLOR float frac = texture2D(CoronaSampler0, uv).r; // Fetch the accumulated offset from
                                                          // the canvas

    if (frac > 0.0) // Any object crossed this pixel?
    {
      P_COLOR vec3 color = texture2D(CoronaSampler1, vec2(frac, 0.0)).rgb; // Read the color from
                                                                           // that offset in the
                                                                           // color set
			
      return vec4(color, 1.0);
    }
		
    else return vec4(0.0); // No object: transparent
  }
]]

graphics.defineEffect(kernel)

-- Apply the effect to the region.
region.fill.effect = "composite.custom.blender"

I've tried to explain what's going on, but let me know if you need more information. Obviously if this is dynamic you'll need to adjust some of this.

[TOPIC CONTROLS]
This topic has been archived. This means that you cannot reply to this topic.
[/TOPIC CONTROLS]
[modOptionsDropdown]
[/modOptionsDropdown]
[reputationFilter]
[TOPIC: post.html]
#1

nick.g

[GLOBAL: userInfoPane.html]
nick.g
  • Observer

  • 6 posts
  • Corona SDK

Hi,

I'm new in Corona, so I have a problem.

I have to know how to change colour for overlay zone like on image.

Attached File  1.png   8.83KB   0 downloads

 

This is not a mixing colour. There are three different colours, that I need to setup. 

Red, purple and blue.

 

On the last engine , I created this with stencil buffer, but I can't fine options to do it with Corona.

 

BTW for lines I have the same problem. I need this result 

Attached File  5.png   10.74KB   0 downloads

 

There are two lines, and when these lines crossing or overlay, I need the third colour. 

 

Thanks a lot

 

Regards.



[TOPIC: post.html]
#2

Rob Miracle

[GLOBAL: userInfoPane.html]
Rob Miracle
  • Moderator

  • 26,075 posts
  • Enterprise

There are two things that might help you.

 

Blend Modes:   https://docs.coronalabs.com/api/type/Paint/blendMode.html

 

and

 

Fills: https://docs.coronalabs.com/guide/graphics/path.html

 

Rob



[TOPIC: post.html]
#3

nick.g

[GLOBAL: userInfoPane.html]
nick.g
  • Observer

  • 6 posts
  • Corona SDK

There are two things that might help you.

 

Blend Modes:   https://docs.coronalabs.com/api/type/Paint/blendMode.html

 

and

 

Fills: https://docs.coronalabs.com/guide/graphics/path.html

 

Rob

 

Thanks Rob.

But Blend Modes just use base two colours from object to create third colour. But I need to setup different colours. 

I can't create for example blue colour when I will mix red and green. Or for example I need specific colour.

So, I have to do it dynamically because these two circles will moved.

Solution can be, for example - something like overlay_object.color = pink. 

Or some api like stencil, where we can test how many objects in these zone and change colour for example.

 

Like this 

cjoKk.png



[TOPIC: post.html]
#4

SGS

[GLOBAL: userInfoPane.html]
SGS
  • Corona Geek

  • 2,120 posts
  • Corona SDK

Can you replicate what you want in photoshop easily?  A lot of photoshop filters and blend modes can be done in Corona.  If you can't do it in photoshop with simple layer blends then you will have to code it dynamically.



[TOPIC: post.html]
#5

nick.g

[GLOBAL: userInfoPane.html]
nick.g
  • Observer

  • 6 posts
  • Corona SDK

Can you replicate what you want in photoshop easily?  A lot of photoshop filters and blend modes can be done in Corona.  If you can't do it in photoshop with simple layer blends then you will have to code it dynamically.

Thanks. Will try to do it in Photoshop. As I understood there is a library to create filters and blend modes in Corona?

BTW how I can code it dynamically. Maybe this is a solution. How can I get overlay zone? Is there some api or methods.

Thanks a lot for answers. 



[TOPIC: post.html]
#6

SGS

[GLOBAL: userInfoPane.html]
SGS
  • Corona Geek

  • 2,120 posts
  • Corona SDK

These are the filters and blends you can do in Corona.



[TOPIC: post.html]
#7

nick.g

[GLOBAL: userInfoPane.html]
nick.g
  • Observer

  • 6 posts
  • Corona SDK

Tried to do it via blend and filters. Not successful. 

So, I have to do it manually and dynamically. But I don't know how. 

Can I use dynamic mask for example? I know how to create it for circles, but not for lines

 

Thanks



[TOPIC: post.html]
#8

Rob Miracle

[GLOBAL: userInfoPane.html]
Rob Miracle
  • Moderator

  • 26,075 posts
  • Enterprise

I did a little research on stencil buffers and that sounds like something a custom shader would do. We have several community members who are really good writing OpenGL shaders. Let me see if I can get someone to look into this thread and offer some advice.

 

Rob



[TOPIC: post.html]
#9

StarCrunch

[GLOBAL: userInfoPane.html]
StarCrunch
  • Contributor

  • 815 posts
  • Corona SDK

  Best Answer

Hi.

 

I had a go and seem to have something working. This uses the memory bitmap plugin, so see the instructions for that.

local memoryBitmap = require("plugin.memoryBitmap")

-- Save the current texture filter settings. Temporarily set them to
-- nearest mode, since we want to snap to colors rather than blend
-- with our neighbors.
local def = display.getDefault("minTextureFilter")

display.setDefault("minTextureFilter", "nearest")

-- Make a one-dimensional texture to store as many colors as we support. It
-- might be best if this is a power-of-2, but maybe it doesn't matter.
local Width = 4

local colors = memoryBitmap.newTexture{ width = Width, height = 1, format = "rgb" }

-- Put color #1 in column #1, #2 in column #2, etc.
colors:setPixel(1, 1, 0, 1, 0) -- green at (1, 1)
colors:setPixel(2, 1, 1, 0, 0) -- red at (2, 1)

-- Restore the previous filter mode.
display.setDefault("minTextureFilter", def)

-- Render our geometry in a canvas so that we can reference it in our effect
local function Rect (canvas, x, y, w, h)
  local rect = display.newRect(x, y, w, h)

  rect.blendMode = "add" -- Accumulate the object...

  rect:setFillColor(1 / Width) -- ...by this much. (The final result is the
                               -- offset into our color set.) This emulates
                               -- stencil addition, basically.
  canvas:draw(rect)

  return rect
end

-- Define the region that will display the effect.
local region = display.newRect(display.contentCenterX, display.contentCenterY, 250, 250)

-- Make a canvas into which the objects will be rendered.
local canvas = graphics.newTexture{ type = "canvas", width = region.width, height = region.height }

-- Create a P-shaped object like the one in your example above, stuffing
-- the pieces into the canvas.
Rect(canvas, -10, 20, 110, 20)
Rect(canvas, 35, -40, 20, 100)
Rect(canvas, -10, -80, 70, 20)
Rect(canvas, -35, 0, 20, 140)

local r = Rect(canvas, -50, -80, 60, 20)

r.rotation = -45

-- Commit the draw calls to the canvas.
canvas:invalidate()

-- Register an effect to the draw region that takes the canvas in sampler #0 and
-- the color map in sampler #1. 
region.fill = {
  type = "composite",
  paint1 = { type = "image", filename = canvas.filename, baseDir = canvas.baseDir },
  paint2 = { type = "image", filename = colors.filename, baseDir = colors.baseDir }
}

-- Create a blend effect.
local kernel = { category = "composite", name = "blender" }

kernel.fragment = [[
  P_COLOR vec4 FragmentKernel (P_UV vec2 uv)
  {
    P_COLOR float frac = texture2D(CoronaSampler0, uv).r; // Fetch the accumulated offset from
                                                          // the canvas

    if (frac > 0.0) // Any object crossed this pixel?
    {
      P_COLOR vec3 color = texture2D(CoronaSampler1, vec2(frac, 0.0)).rgb; // Read the color from
                                                                           // that offset in the
                                                                           // color set
			
      return vec4(color, 1.0);
    }
		
    else return vec4(0.0); // No object: transparent
  }
]]

graphics.defineEffect(kernel)

-- Apply the effect to the region.
region.fill.effect = "composite.custom.blender"

I've tried to explain what's going on, but let me know if you need more information. Obviously if this is dynamic you'll need to adjust some of this.



[TOPIC: post.html]
#10

nick.g

[GLOBAL: userInfoPane.html]
nick.g
  • Observer

  • 6 posts
  • Corona SDK

Hi

Thanks a lot it's very useful. I tried to do this code. The result is

 

Attached File  Снимок экрана 2017-03-31 в 21.46.29.png   9.59KB   1 downloads

 

So, as I understood something wrong with offset for colour choose.

I'm not clearly understood what is Width varible. Number of colours, but with this  

  rect:setFillColor(1 / Width)

Thanks a lot for your code. Will investigate and try to change :)

 

Regards



[TOPIC: post.html]
#11

StarCrunch

[GLOBAL: userInfoPane.html]
StarCrunch
  • Contributor

  • 815 posts
  • Corona SDK

Whoops, sorry. Change each instance of "minTextureFilter" to "magTextureFilter". I did notice the colors were off, but figured it was a reasonable start. Just tried now with the other key and it seems to work.

 

Width is the maximum number of colors in the "color set". I rounded it up to 4, though as I say in the comments maybe a non-power-of-2 would be okay. In Corona's shaders, texture coordinates will have been mapped to the [0, 1] range, so pixel #1 is found in the interval [0, 1 / Width], #2 in [1 / Width, 2 / Width], etc. Nearest filtering keeps these from blending together.

 

By assigning 1 / Width as the "color", we're basically assigning the per-object density. Additive blending makes these layer on as they cross the same spot. Rather than containing conventional color information, the canvas contains these densities; "denser" parts have a further offset into the color set.

 

Off-hand I don't know if it's wise to read right at the color set's pixel boundary; non-power-of-2 widths might have issues, for instance. Maybe subtracting half a pixel would be more robust. This could be string.format()'d into the shader source using Width, or added as a shader parameter.



[TOPIC: post.html]
#12

nick.g

[GLOBAL: userInfoPane.html]
nick.g
  • Observer

  • 6 posts
  • Corona SDK

Yep it's working. Thanks a lot. :D  :D

Will try to do it dynamically with three colours and circles like in first post. 

Thanks




[topic_controls]
[/topic_controls]