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 编辑
#Simple Bitmap Rotation by RaidenInfinity
module Math
def self.deg_to_rad(x)
return x * (Math::PI / 180.0)
end
def self.get_rotation_matrix(angle)
case angle
when 0; return [1,0,0,1]
when 90; return [0,1,-1,0]
when 180; return [0,-1,1,0]
when 270; return [-1,0,0,-1]
end
return [cos(deg_to_rad(angle)),-sin(deg_to_rad(angle)),
sin(deg_to_rad(angle)),cos(deg_to_rad(angle))]
end
def self.matrix_multiply_2x2_1x2(std,vec)
return [std[0] * vec[0] + std[1] * vec[1],
std[2] * vec[0] + std[3] * vec[1]]
end
def self.transpose_matrix_2x2(mat)
return [mat[0],mat[2],mat[1],mat[3]]
end
end
class Bitmap
def get_rotated_bitmap(angle)
mat = Math.get_rotation_matrix(angle)
arr = get_rotated_size(mat)
bmp = Bitmap.new(arr[0],arr[1])
old_ox = (self.width / 2).round.to_i
old_oy = (self.width / 2).round.to_i
new_ox = (arr[0] / 2).round.to_i
new_oy = (arr[1] / 2).round.to_i
#Reverse Mapping
mat = Math.transpose_matrix_2x2(mat)
arr[0].times{|i|
arr[1].times{|j|
vec = m_mult(mat,[i - new_ox,j - new_oy])
c = self.get_pixel((vec[0] + old_ox).round,(vec[1] + old_oy).round)
bmp.set_pixel(i,j, c)
}
}
return bmp
end
def get_rotated_size(mat)
arr = [m_mult(mat,[0,0]),m_mult(mat,[self.width,0]),
m_mult(mat,[0,self.height]),m_mult(mat,[self.width,self.height])]
ax = [arr[0][0], arr[1][0], arr[2][0], arr[3][0]]
ay = [arr[0][1], arr[1][1], arr[2][1], arr[3][1]]
return [(ax.max - ax.min).round.to_i.abs, (ay.max - ay.min).round.to_i.abs]
end
def m_mult(std,vec); Math.matrix_multiply_2x2_1x2(std,vec) end
end
#Simple Bitmap Rotation by RaidenInfinity
module Math
def self.deg_to_rad(x)
return x * (Math::PI / 180.0)
end
def self.get_rotation_matrix(angle)
case angle
when 0; return [1,0,0,1]
when 90; return [0,1,-1,0]
when 180; return [0,-1,1,0]
when 270; return [-1,0,0,-1]
end
return [cos(deg_to_rad(angle)),-sin(deg_to_rad(angle)),
sin(deg_to_rad(angle)),cos(deg_to_rad(angle))]
end
def self.matrix_multiply_2x2_1x2(std,vec)
return [std[0] * vec[0] + std[1] * vec[1],
std[2] * vec[0] + std[3] * vec[1]]
end
def self.transpose_matrix_2x2(mat)
return [mat[0],mat[2],mat[1],mat[3]]
end
end
class Bitmap
def get_rotated_bitmap(angle)
mat = Math.get_rotation_matrix(angle)
arr = get_rotated_size(mat)
bmp = Bitmap.new(arr[0],arr[1])
old_ox = (self.width / 2).round.to_i
old_oy = (self.width / 2).round.to_i
new_ox = (arr[0] / 2).round.to_i
new_oy = (arr[1] / 2).round.to_i
#Reverse Mapping
mat = Math.transpose_matrix_2x2(mat)
arr[0].times{|i|
arr[1].times{|j|
vec = m_mult(mat,[i - new_ox,j - new_oy])
c = self.get_pixel((vec[0] + old_ox).round,(vec[1] + old_oy).round)
bmp.set_pixel(i,j, c)
}
}
return bmp
end
def get_rotated_size(mat)
arr = [m_mult(mat,[0,0]),m_mult(mat,[self.width,0]),
m_mult(mat,[0,self.height]),m_mult(mat,[self.width,self.height])]
ax = [arr[0][0], arr[1][0], arr[2][0], arr[3][0]]
ay = [arr[0][1], arr[1][1], arr[2][1], arr[3][1]]
return [(ax.max - ax.min).round.to_i.abs, (ay.max - ay.min).round.to_i.abs]
end
def m_mult(std,vec); Math.matrix_multiply_2x2_1x2(std,vec) end
end
尝试写了一个也许比较快的版本。32x32的位图从0到359度,耗时大概2.5秒上下(我的主机核是Pentium E5200 2.50GHz)
测试运行代码:
a = Bitmap.new(32,32)
a.fill_rect(0,0,32,32,Color.new(255,0,0,255))
list = []
z = Time.now
360.times{|i|
#p i
list.push(a.get_rotated_bitmap(i))
}
z -= Time.now
p z
a = Bitmap.new(32,32)
a.fill_rect(0,0,32,32,Color.new(255,0,0,255))
list = []
z = Time.now
360.times{|i|
#p i
list.push(a.get_rotated_bitmap(i))
}
z -= Time.now
p z
也许你能参考来优化,或者在比较强的电脑上也许运行速度会更快。
这段脚本的主要优化原理是使用矩阵,避免每个像素都调用三角函数。
作者: Mirora_Mikasa 时间: 2016-10-23 23:04
本帖最后由 Mirora_Mikasa 于 2016-10-24 00:07 编辑
非常感谢,虽说在下还没有学到矩阵是个啥..........
另外有一个问题:
list = {}
360.times do |i|
list[i] = RSTG_Bitmap.new(bit,i)
end
360.times do |i|
b = Sprite.new
b.x,b.y = 200,200
b.bitmap = list[i].bitmap
b.ox,b.oy = list[i].ox,list[i].oy
Graphics.update
b.dispose
end
list = {}
360.times do |i|
list[i] = RSTG_Bitmap.new(bit,i)
end
360.times do |i|
b = Sprite.new
b.x,b.y = 200,200
b.bitmap = list[i].bitmap
b.ox,b.oy = list[i].ox,list[i].oy
Graphics.update
b.dispose
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)
list = []
360.times do |i|
list.push(RSTG_Bitmap.new(bit,i))
end
list = []
360.times do |i|
list.push(RSTG_Bitmap.new(bit,i))
end
如果你仍然想要用Hash,也请用
检查你的列表里面是否有list[0] = nil的情况
总结:p是个好东西。在控制台打印出变量的内容可以协助解决很多问题。
欢迎光临 Project1 (https://rpg.blue/) |
Powered by Discuz! X3.1 |