Revealing text as on a scroll

I have some text in my current project that I want to reveal to the player from the middle outwards–imagine a scroll opening in both directions: the middle of the text is visible first, and the outer edges last.

I’ve experimented with several approaches–including changing the “frameSize” parameter of a DirectLabel; tinkering with its internal “text” object; and, using a TextNode, altering scale and texture scale in tandem–but thus far haven’t managed to come up with anything that quite works. (Simply altering scale alters the width of the text as well as its frame, which is not what I’m aiming for.)

Does anyone have any suggestions as to how I might accomplish this?

(I feel as though I’m missing some obvious solution, but I’m not seeing it at the moment… :/)

Hi Thaumaturge :slight_smile:,

A simple (although perhaps not the most efficient/straightforward) solution would be to use clipping planes:

from panda3d.core import *
from direct.showbase.ShowBase import ShowBase
from direct.interval.IntervalGlobal import *


class App(ShowBase):

  def __init__(self):

    ShowBase.__init__(self)

    text = TextNode("unrolled_scroll_text")
    text.setText("Text revealed as if by unrolling a scroll.")
    text_np = aspect2d.attachNewNode(text)
    p1, p2 = text_np.getTightBounds()
    x1 = p1.x
    x2 = p2.x
    x_center = (x1 + x2) / 2.
    scale = .07
    text_np.setScale(scale)
    
    text_np.setX(-x_center * scale)
    clip_plane_l = PlaneNode("clip_plane_left", Plane(Vec3(1., 0., 0.), Point3()))
    clip_plane_l.setClipEffect(1)
    clip_np_l = text_np.attachNewNode(clip_plane_l)
    clip_np_l.setX(x_center)
    text_np.setClipPlane(clip_np_l)
    clip_plane_r = PlaneNode("clip_plane_right", Plane(Vec3(-1., 0., 0.), Point3()))
    clip_plane_r.setClipEffect(1)
    clip_np_r = text_np.attachNewNode(clip_plane_r)
    clip_np_r.setX(x_center)
    text_np.setClipPlane(clip_np_r)
    
    interval_l = LerpPosInterval(clip_np_l, 3., Point3(x1, 0., 0.), blendType="easeOut")
    interval_l.loop()
    interval_r = LerpPosInterval(clip_np_r, 3., Point3(x2, 0., 0.), blendType="easeOut")
    interval_r.loop()


App().run()

However, if you are going to use several of these texts at the same time, beware that your graphics card might not support that many clipping planes.

Anyway, I hope this helps :slight_smile: .

Thank you for the response. :slight_smile:

I do intend to have multiple such “scrolls”–but probably not more than a few at a time, and more often only one at a time, so perhaps your solution might work with clipping planes being reused…

Another thought that has occurred to me, but that I haven’t yet tried, is using a DirectScrolledFrame with the scroll-bars deactivated. This might be a little simpler than the clipping-plane solution, if it works and performs well.

[edit] I’m glad to report that a combination of DirectScrolledFrame and OnscreenText (with appropriate parameters and updating) seems to work well (although I haven’t yet stress-tested it with multiple “scrolls”). :slight_smile: