Project1

标题: Bitmap类旋转问题[已解决] [打印本页]

作者: Mirora_Mikasa    时间: 2016-10-23 00:56
标题: Bitmap类旋转问题[已解决]
本帖最后由 Mirora_Mikasa 于 2016-10-24 23:36 编辑

不小心开到隔壁去了,我来重开一帖

原本的问题是:如何实现位图的旋转
现在我实现之后,发现,效率极其低下,32*32的图片生成360个角度用了少说10s
我的方法:https://rpg.blue/home.php?mod=sp ... o=blog&id=15610
所以有没有什么方法能提高其运输效率
作者: RaidenInfinity    时间: 2016-10-23 07:54
本帖最后由 RaidenInfinity 于 2016-10-23 07:58 编辑

使用Bitmap的get_pixel和set_pixel难免缓慢,而RGSS3并没有提供可以直接更改位图数据的方法(如C# Bitmap的LockBits)。
因此,无论如何还是建议使用Sprite来显示图形的旋转。

Sprite的旋转是以原点(ox和oy)作为支点,并逆时针旋转。

假设我们有这样的一段代码:


生成的方形:


angle = 20的时候


如果想要以中心为支点来旋转,必须将原点设置到中心。
a.ox = a.width / 2
a.oy = a.height / 2

就会得到想要的效果了:


虽然有点答非所问,不过关于位图本身的旋转,我本身还在测试中。有结果后再回答。

作者: RaidenInfinity    时间: 2016-10-23 09:57
本帖最后由 RaidenInfinity 于 2016-10-23 10:30 编辑

RUBY 代码复制
  1. #Simple Bitmap Rotation by RaidenInfinity
  2.  
  3. module Math
  4.  
  5.     def self.deg_to_rad(x)
  6.       return x * (Math::PI / 180.0)
  7.     end
  8.  
  9.     def self.get_rotation_matrix(angle)
  10.       case angle
  11.         when 0; return [1,0,0,1]
  12.         when 90; return [0,1,-1,0]
  13.         when 180; return [0,-1,1,0]
  14.         when 270; return [-1,0,0,-1]
  15.       end
  16.       return [cos(deg_to_rad(angle)),-sin(deg_to_rad(angle)),
  17.                       sin(deg_to_rad(angle)),cos(deg_to_rad(angle))]
  18.     end
  19.  
  20.     def self.matrix_multiply_2x2_1x2(std,vec)
  21.       return [std[0] * vec[0] + std[1] * vec[1],
  22.               std[2] * vec[0] + std[3] * vec[1]]
  23.     end   
  24.  
  25.     def self.transpose_matrix_2x2(mat)   
  26.       return [mat[0],mat[2],mat[1],mat[3]]
  27.     end      
  28.  
  29. end
  30.  
  31. class Bitmap
  32.  
  33.   def get_rotated_bitmap(angle)
  34.     mat = Math.get_rotation_matrix(angle)
  35.     arr = get_rotated_size(mat)
  36.     bmp = Bitmap.new(arr[0],arr[1])
  37.     old_ox = (self.width / 2).round.to_i
  38.     old_oy = (self.width / 2).round.to_i
  39.     new_ox = (arr[0] / 2).round.to_i
  40.     new_oy = (arr[1] / 2).round.to_i
  41.     #Reverse Mapping
  42.     mat = Math.transpose_matrix_2x2(mat)
  43.     arr[0].times{|i|
  44.       arr[1].times{|j|
  45.         vec = m_mult(mat,[i - new_ox,j - new_oy])
  46.         c = self.get_pixel((vec[0] + old_ox).round,(vec[1] + old_oy).round)
  47.         bmp.set_pixel(i,j, c)
  48.       }
  49.     }     
  50.     return bmp
  51.   end
  52.  
  53.   def get_rotated_size(mat)
  54.     arr = [m_mult(mat,[0,0]),m_mult(mat,[self.width,0]),
  55.          m_mult(mat,[0,self.height]),m_mult(mat,[self.width,self.height])]
  56.     ax = [arr[0][0], arr[1][0], arr[2][0], arr[3][0]]
  57.     ay = [arr[0][1], arr[1][1], arr[2][1], arr[3][1]]
  58.     return [(ax.max - ax.min).round.to_i.abs, (ay.max - ay.min).round.to_i.abs]
  59.   end
  60.  
  61.   def m_mult(std,vec); Math.matrix_multiply_2x2_1x2(std,vec) end
  62.  
  63. end


尝试写了一个也许比较快的版本。32x32的位图从0到359度,耗时大概2.5秒上下(我的主机核是Pentium E5200 2.50GHz)

测试运行代码:
RUBY 代码复制
  1. a = Bitmap.new(32,32)
  2. a.fill_rect(0,0,32,32,Color.new(255,0,0,255))
  3.  
  4. list = []
  5. z = Time.now
  6. 360.times{|i|
  7.   #p i
  8.   list.push(a.get_rotated_bitmap(i))
  9. }  
  10. z -= Time.now
  11. p z


也许你能参考来优化,或者在比较强的电脑上也许运行速度会更快。
这段脚本的主要优化原理是使用矩阵,避免每个像素都调用三角函数。

作者: Mirora_Mikasa    时间: 2016-10-23 23:04
本帖最后由 Mirora_Mikasa 于 2016-10-24 00:07 编辑

非常感谢,虽说在下还没有学到矩阵是个啥..........

另外有一个问题:
RUBY 代码复制
  1. list = {}
  2. 360.times do |i|
  3.   list[i] = RSTG_Bitmap.new(bit,i)
  4. end
  5. 360.times do |i|
  6.   b = Sprite.new
  7.   b.x,b.y = 200,200
  8.   b.bitmap = list[i].bitmap
  9.   b.ox,b.oy = list[i].ox,list[i].oy
  10.   Graphics.update
  11.   b.dispose
  12. end


这样一个代码在运行时他会提示我 undefined method 'bitmap' for nil:NilClass
但是把第二个 360.times do |i| 改为 360.downto 1 do |i| 便可以正常的运行,所以想请教下是为什么........
作者: RaidenInfinity    时间: 2016-10-26 13:19
你可以试下把list宣告为数组(Array)而不是键值表(Hash)

RUBY 代码复制
  1. list = []
  2. 360.times do |i|
  3.   list.push(RSTG_Bitmap.new(bit,i))
  4. end


如果你仍然想要用Hash,也请用
RUBY 代码复制
  1. p list

检查你的列表里面是否有list[0] = nil的情况

总结:p是个好东西。在控制台打印出变量的内容可以协助解决很多问题。




欢迎光临 Project1 (https://rpg.blue/) Powered by Discuz! X3.1