Perspective/Projection Transforms?

Discuss how to use the Ren'Py engine to create visual novels and story-based games. New releases are announced in this section.
Forum rules
This is the right place for Ren'Py help. Please ask one question per thread, use a descriptive subject like 'NotFound error in option.rpy' , and include all the relevant information - especially any relevant code and traceback messages. Use the code tag to format scripts.
Post Reply
Message
Author
Human Bolt Diary
Regular
Posts: 111
Joined: Fri Oct 11, 2013 12:46 am
Contact:

Perspective/Projection Transforms?

#1 Post by Human Bolt Diary »

Hi everybody,

I've been looking through ATL and Transform() documentation, and I haven't seen anything regarding a perspective manipulation on an image and/or displayable. Is there a sort of Matrix Transform I'm not aware of, or is this feature not available at all?

apricotorange
Veteran
Posts: 479
Joined: Tue Jun 05, 2012 2:01 am
Contact:

Re: Perspective/Projection Transforms?

#2 Post by apricotorange »

Not available at the moment.

Asceai
Eileen-Class Veteran
Posts: 1258
Joined: Fri Sep 21, 2007 7:13 am
Projects: a battle engine
Contact:

Re: Perspective/Projection Transforms?

#3 Post by Asceai »

I wish.

Human Bolt Diary
Regular
Posts: 111
Joined: Fri Oct 11, 2013 12:46 am
Contact:

Re: Perspective/Projection Transforms?

#4 Post by Human Bolt Diary »

Asceai wrote:I wish.
Your wish has come true! (Kinda, not really)

My math skills are not nearly strong enough to seriously attempt this, but reading articles on the SNES Mode 7 put crazy ideas in my head.

The following displayable uses crop to make scanlines and a xzoom to fake out the perspective effect. As is, it's probably too inefficient/resource intensive for anything more complex than a tiny demo, but here we go:

Keyboard left and right keys to rotate, up key to activate/deactivate the effect. Make test_image whatever displayable you want to use.

Code: Select all


init python:
 test_image = Image("img_00.png") #Whatever image we're distorting
 
 class Perspective(renpy.Displayable):
  def __init__(self,image):
   super(renpy.Displayable,self).__init__()
   
   self.start_image = image
     
   self.W2 = config.screen_width * 0.5
   self.H2 = config.screen_height * 0.5
   
   self.active = False   
   self.dir = 0 #Rotation amount
   
  def render(self,width,height,st,at):
   render = renpy.Render(0, 0)
   
   #Rotate the image before cutting it into scanlines and displaying it
   self.img = Transform(self.start_image, xanchor=0.5,yanchor=0.5,rotate=self.dir)
   self.img = self.makeScanlines(self.img)   
   
   h = 1.0
   ay = self.H2

   for scanline in self.img:

    if self.active == False:
     zoom_factor = 1
    else:
     zoom_factor = 100.0 / ay
    self.t = Transform(scanline, xzoom=(1/zoom_factor))

    h +=1.0
    ay +=1.0
    
    child_render = renpy.render(self.t, 0, 0, st, at)
    cW,cH = child_render.get_size()
    render.blit(child_render, ((self.W2)-(cW/2),(self.H2)+h))
   
   return render
 
  #Keyboard Events
  def event(self, ev, x, y, st):
   import pygame
                        
   if ev.type == pygame.KEYDOWN:
    if ev.key == pygame.K_LEFT:
     if self.dir >= 360:
      self.dir = 0
     else:
      self.dir += 3
     renpy.redraw(self, 0)

    if ev.key == pygame.K_RIGHT:
     if self.dir <= -360:
      self.dir = 0
     else:
      self.dir -= 3
     renpy.redraw(self, 0)
    
    if ev.key == pygame.K_UP:
     if self.active == False:
      self.active = True
     else:
      self.active = False
     renpy.redraw(self, 0)
  
  #Cut image into scanlines  
  def makeScanlines(self, base_image):
   cut = []
   child_render = renpy.render(base_image, config.screen_width, config.screen_height, 0, 0)
   width = int(child_render.get_size()[0]) #Prevents get_size from returning a float
   height = int(child_render.get_size()[1])
   cut = [Transform(base_image, crop=(0,i,width,1)) for i in range(height)]
   return cut
   
#Screen drawn onto   
screen test:
 add Perspective(test_image):
  xanchor 0.5
  yanchor 0.5
 
# The game starts here.
label start:

 call screen test
 return


Asceai
Eileen-Class Veteran
Posts: 1258
Joined: Fri Sep 21, 2007 7:13 am
Projects: a battle engine
Contact:

Re: Perspective/Projection Transforms?

#5 Post by Asceai »

Yeah, argh. I suspect this would actually be more valuable as an image manipulator so you only have to do it once (unless you can keep a render around for a while and keep using it?)

Unin
Regular
Posts: 54
Joined: Wed Sep 01, 2010 8:08 pm
Location: Florida
Contact:

Re: Perspective/Projection Transforms?

#6 Post by Unin »

What version of ren'py did you use for that implementation? I'm not seeing anything at all when I call your screen test.

Should img_00.png have a minimum or maximum size compared to the screen?

Human Bolt Diary
Regular
Posts: 111
Joined: Fri Oct 11, 2013 12:46 am
Contact:

Re: Perspective/Projection Transforms?

#7 Post by Human Bolt Diary »

Copy/Pasting the code above into a new project works as of Ren'Py 6.17.6

It was meant to be used for small images, around 100x100. Testing with a 1000x1000 image, you'll have to alter the y value of the blit to get it on screen. Of course, using a large image will cause some pretty intense slowdown, even on a small window resolution.

The most important thing to note is that while the code above will give a reasonably distorted image, the math isn't actually correct, it's not stretching at the correct amounts per scanline.

Unin
Regular
Posts: 54
Joined: Wed Sep 01, 2010 8:08 pm
Location: Florida
Contact:

Re: Perspective/Projection Transforms?

#8 Post by Unin »

I can handle the projection geometry, I'm just trying to find a decent implementation for a flight sim I'm working on. you were right about the image's size, that was exactly the problem

Post Reply

Who is online

Users browsing this forum: Ahrefs [Bot], Google [Bot]