Layering stimuli

Great- thanks!

Hi Chris,
I’ve forwarded some of this conversation to Mark, but he was hoping that
you could send him the full transcript.
Also, I do regularly check the “Discussions” page to understand what issues
others are having in case they are relevant. It would be great if you would
continue to post discussions there. Or perhaps we could come up with a
better way of distributing information among users?
Thanks,
Lindsey.

Hi Lindsey,

I’ve forwarded some of this conversation to Mark, but he was hoping that you could send him the full transcript.

It looks like you added Mark to the list of watchers on this discussion, so he should be able to see the whole thread on the web site now.

Also, I do regularly check the “Discussions” page to understand what issues others are having in case they are relevant. It would be great if you would continue to post discussions there.

I always do. However, when someone initially emails me directly (as you did), I usually keep the Tender discussion created from the email private, in case the user is going to send me files that they don’t want publicly available via the discussion forum. Once the discussion thread is closed, I make it public (unless it contains content that I think should remain private).

Chris

Ok- that makes sense, but I think it’ll be pretty rare that I have things
that I want kept private. Can we default to public unless I tell you
otherwise?
Also- I still don’t see our discussion on the website. Am I looking in the
right place? Discussion Area - MWorks Support
Lindsey.

Can we default to public unless I tell you otherwise?

Sure.

Also- I still don’t see our discussion on the website.

I just made it public. You should see it now.

Chris

Hi Chris and Lindsey,

I see that Chris has now exposed the GL blend parameters to many stimuli.

I’m having trouble fully figuring out how Chris chose the blending parameters for this plaid. To get a plaid with this kind of blending, I’d think you blend each grating with a 50% gray stimulus using the alpha parameter (to set contrast). Then, you linearly sum the plaids: call g the 50% gray value and p0 and p1 the plaid values: at every pixel, you find (p0-g) + (p1-g) + g and that is the resulting framebuffer value.
(The contrast setting blend is p0 = (dg-g)c0 + g by this notation, or dgc0 + g*(1-c0), where c0 is alpha/contrast, and df0 is the drifting grating pixel value before contrast is set.)

Is that right? And if so, can you briefly explain how you use source/dest_blend/alpha to get that?

Hi Mark,

Is that right? And if so, can you briefly explain how you use source/dest_blend/alpha to get that?

What you describe is exactly what my example implements.

Excluding plaid_opacity_rectangle and plaid_mask, the stimulus definitions in layer plaid amount to a sum of three components. Using your notation, those components are

  1. dg0 * c0
  2. dg1 * c1
  3. g * (1 - (c0 + c1))

Adding 1-3 and rearranging terms gives you

(dg0 - g) * c0 + (dg1 - g) * c1 + g

Taking your definitions of p0 and p1

p0 = (dg0 - g) * c0 + g
p1 = (dg1 - g) * c1 + g

we can rewrite the above sum as

(p0 - g) + (p1 - g) + g

which is exactly what you expected.

Maybe you were unclear about the meaning of some of the blend factors? Also, note that for both gratings, I relied on the default value of source_blend_factor (which is source_alpha).

Cheers,
Chris

Hi Chris,

I just wanted to circle back to this and make sure that I’m using this
correctly.

If I define the stimulus like this (see below), can I then just use
tStimOneGratingContrast and tMaskOneGratingContrast directly, to represent
the actual contrast of each stimulus (such that if tStimOne is 0.5 and
tMaskOne is 0.25, there’s a summed net contrast of 0.75)?

Thanks,
Lindsey.

layer stimOne {
drifting_grating stimOne_grating (
direction = tStimOneGratingDirectionDeg
starting_phase = tStimOneGratingPhaseDeg
spatial_frequency = tStimOneGratingSpatialFreqCPD
speed = tStimOneGratingTemporalFreqCPS/tStimOneGratingSpatialFreqCPD
grating_type = gratingType
x_size = tStimOneGratingDiameterDeg
x_position = tStimOneGratingAzimuthDeg
y_position = tStimOneGratingElevationDeg
alpha_multiplier = tStimOneGratingContrast
dest_blend_factor = zero
autoplay = true
)

drifting_grating stimOne_mask (
    direction = tMaskOneGratingDirectionDeg
    starting_phase = tMaskOneGratingPhaseDeg
    spatial_frequency = tStimOneGratingSpatialFreqCPD
    speed = tStimOneGratingTemporalFreqCPS/tStimOneGratingSpatialFreqCPD
    grating_type = gratingType
    x_size = tStimOneGratingDiameterDeg
    x_position = tStimOneGratingAzimuthDeg
    y_position = tStimOneGratingElevationDeg
    alpha_multiplier = tMaskOneGratingContrast
    dest_blend_factor = one
    autoplay = true
    )

rectangle stimOne_contrast_rectangle (
    color = 0.5, 0.5, 0.5
    x_size = tStimOneGratingDiameterDeg
    x_position = tStimOneGratingAzimuthDeg
    y_position = tStimOneGratingElevationDeg
    alpha_multiplier = tStimOneGratingContrast + tMaskOneGratingContrast
    source_blend_factor = one_minus_source_alpha
    dest_blend_factor = one
    )

// Make the plaid 100% opaque.  Without this, the plaid's net alpha

would
// be less than zero, and its color would be blended with the stimulus
// display background when the layer is drawn.
rectangle stimOne_opacity_rectangle (
x_size = tStimOneGratingDiameterDeg
x_position = tStimOneGratingAzimuthDeg
y_position = tStimOneGratingElevationDeg
source_blend_factor = zero
dest_blend_factor = one
source_alpha_blend_factor = one
dest_alpha_blend_factor = zero
)

mask stimOne_plaid_mask (
    mask = maskType
    std_dev = gratingStd
    mean = gratingMean
    edge_width = gratingEdge
    x_size = tStimOneGratingDiameterDeg
    x_position = tStimOneGratingAzimuthDeg
    y_position = tStimOneGratingElevationDeg
    )

}

Yes, that all looks correct. Just remember that the sum of tStimOneGratingContrast and tMaskOneGratingContrast must be less than or equal to one at all times.

Chris

Yes- thanks!
Lindsey.

What you describe is exactly what my example implements.

Great. And yes, this is helpful about how to set all the blend factors.

Hi Chris,
Say I wanted to make the mask grating completely opaque, such that you
could not see the stimulus grating beneath it (instead of them summing
linearly).
Do I just need to set the dest_blend_factor for the mask grating to zero?
Or is there something else that would need to be done?
Thanks,
Lindsey.

Hi Lindsey,

Say I wanted to make the mask grating completely opaque, such that you could not see the stimulus grating beneath it (instead of them summing linearly). Do I just need to set the dest_blend_factor for the mask grating to zero? Or is there something else that would need to be done?

All you need to do is set tStimOneGratingContrast to zero. You’re then free to vary tMaskOneGratingContrast between zero and one, and the result will be identical to what you’d get if you were just drawing the mask grating normally (i.e. by itself, with default blend factors).

Cheers,
Chris

Hi Chris,
Yes- I appreciate this would work if I did not want stimOne at all.
However, I actually want the stimOne to still be visible in the parts that
are not covered by the mask.
For instance, if I were to make the diameter of stimOne bigger than
maskOne, then I could have different orientations in the center and
surround.
Is this possible with the current blending options?
Lindsey.

I actually want the stimOne to still be visible in the parts that are not covered by the mask. For instance, if I were to make the diameter of stimOne bigger than
maskOne, then I could have different orientations in the center and surround.

I see. You won’t be able to accomplish that just by changing blending parameters. Actually, I’m not sure it’s even possible with the tools currently available, but let me think about it some more.

Chris

Hi Lindsey,

I was wrong. It is totally possible and not very difficult. See the attached example, which I believe implements what you’re after.

Note that this is a distinct construction from the plaid you wanted previously. There’s not a way to define a single pair of gratings that can sometimes combine, sometimes not. If you want both types of stimuli in the same experiment, you’ll need to define two separate pairs of gratings.

Cheers,
Chris

Attachment: opaque_grating.mwel.zip (1.25 KB)

Thanks! I’ll try it out.
Best,
Lindsey.

Hi Chris,
This seems to work well.
However, I’m having a strange problem where the phase of the two gratings
is not matched.
I set them both to have a starting phase of 0 (and confirmed in the output
that both were 0), but for some reason, they’re out of phase. I even tried
setting them to have the same variable controlling the phase (see below for
stimulus definition), but they were still out of phase. This suggests that
there must be some deeper issue. Can you look into it?
Thanks,
Lindsey

%define opaque_grating (direction_deg, phase_deg, diameter_deg, contrast,
spatial_freq_cpd, temporal_freq_cps, azimuth_deg, elevation_deg)

layer {
    // Grating
    drifting_grating (
        direction = direction_deg
        starting_phase = phase_deg
        spatial_frequency = spatial_freq_cpd
        speed = temporal_freq_cps/spatial_freq_cpd
        grating_type = gratingType
        x_size = diameter_deg
        x_position = azimuth_deg
        y_position = elevation_deg
        alpha_multiplier = contrast
        dest_blend_factor = zero
        autoplay = true
        )

    // Contrast rectangle
    rectangle (
        color = 0.5, 0.5, 0.5
        x_size = diameter_deg
        x_position = azimuth_deg
        y_position = elevation_deg
        alpha_multiplier = contrast
        source_blend_factor = one_minus_source_alpha
        dest_blend_factor = one
        )

    // Opacity rectangle
    rectangle (
        x_size = diameter_deg
        x_position = azimuth_deg
        y_position = elevation_deg
        source_blend_factor = zero
        dest_blend_factor = one
        source_alpha_blend_factor = one
        dest_alpha_blend_factor = zero
        )

    // Mask
    mask (
        mask = maskType
        std_dev = gratingStd
        mean = gratingMean
        edge_width = gratingEdge
        x_size = diameter_deg
        x_position = azimuth_deg
        y_position = elevation_deg
        )
}

%end

opaque_grating stimOne (
direction_deg = tStimOneGratingDirectionDeg
phase_deg = tStimOneGratingPhaseDeg
diameter_deg = tStimOneGratingDiameterDeg
contrast = tStimOneGratingContrast
spatial_freq_cpd = tStimOneGratingSpatialFreqCPD
temporal_freq_cps = tStimOneGratingTemporalFreqCPS
azimuth_deg = tStimOneGratingAzimuthDeg
elevation_deg = tStimOneGratingElevationDeg
)

opaque_grating maskOne (
direction_deg = tMaskOneGratingDirectionDeg
phase_deg = tStimOneGratingPhaseDeg
diameter_deg = tMaskOneGratingDiameterDeg
contrast = tMaskOneGratingContrast
spatial_freq_cpd = tStimOneGratingSpatialFreqCPD
temporal_freq_cps = tStimOneGratingTemporalFreqCPS
azimuth_deg = tStimOneGratingAzimuthDeg
elevation_deg = tStimOneGratingElevationDeg
)

Hi Lindsey,

Sorry for the delayed reply. I’m on vacation this week and will take a look at this next week.

Cheers,
Chris