在Lua中的三维表格
我需要最佳的方法来存储三维像素表。我需要做的是有多个x,y表(基本上是三维的),以栅格化多个带透明度的二维像素图。你看,我可以轻松地创建两个维度,例如:
pixels = {{},{}}
pixels[1][5] = "green" --这只是一个例子
print(pixels[1][5])
然而,我不能像在Java中那样做...
pixels = {{}, {}, {}}
pixels[1][4][3] = "red" -- [x][y][z]
print(pixels[1][4][3])
这就是我想要的功能,但我已经通过以下方式恶心地绕过了这个问题...
pixels = {}
pixels["x23,y02,z05"] = "green"
print(pixels["x23,y02,z05"]")
我只是使用string.sub和string.concat来读取和设置表格...我真的希望例2的功能可以工作,但我知道可能需要以不同的方式实现。
除了经典的“数组中的数组中的数组”方案外,您还可以使用 Lua 表内部的优势。怎么做呢?Lua 表只是从键到值的映射,当您将其用作数组时,可以跳过一些键,这几乎不会花费任何代价。
t = { }
t[1] = "Hello"
t[500000] = "World" -- 不会分配额外的 499999 个元素
因此,如果您的数据是稀疏的(超过 50% 的三维点没有值),您可能会从中受益:
local n_x, n_y, n_z = 1920, 1080, 1000
local n_xy = n_x * n_y
function setValue(t, x, y, z, value)
assert(x > 0 and x < n_x)
assert(y > 0 and y < n_y)
assert(z > 0 and z < n_z)
t[((z-1) * n_xy) + ((y-1) * n_z) + x] = value
end
function getValue(t, x, y, z)
assert(x > 0 and x < n_x)
assert(y > 0 and y < n_y)
assert(z > 0 and z < n_z)
return t[((z-1) * n_xy) + ((y-1) * n_z) + x]
end
t = { }
setValue(t, 1, 1, 1, "red")
setValue(t, 1, 1, 2, "green")
有两种基本方法可以处理这个问题:
自动创建表格
自动创建表通过使用元表透明地生成子表,创建完后你应该能够忘记它们存在。
function newAutotable(dim)
local MT = {};
for i=1, dim do
MT[i] = {__index = function(t, k)
if i < dim then
t[k] = setmetatable({}, MT[i+1])
return t[k];
end
end}
end
return setmetatable({}, MT[1]);
end
-- 用法
local at = newAutotable(3);
print(at[0]) -- 返回表
print(at[0][1]) -- 返回表
print(at[0][1][2]) -- 返回 nil
at[0][1][2] = 2;
print(at[0][1][2]) -- 返回值
print(at[0][1][3][3]) -- 出错,因为只设置了3个维度
它们的不足之处在于它们生成了_大量_的表格 -- 显然的。这会有一些内存开销,而且每个深度级别增加了执行时间。
它们的优点在于它们可以完全动态改变大小。你甚至可以使它们无限深。虽然在你的使用情况下,这很可能是不必要的,甚至是个坏主意。
这种结构非常适合非整数索引,你甚至可以使深度依赖于 "模板结构",从而实现一个透明的动态配置表,但我走了神.....
扁平化的数组
另一种变体是扁平化的数组。user3125367 已经谈到了它们,但我想扩展一下,因为它可以更方便地完成并解释一些东西。
通常在 CG 中将多维数组扁平化是一个好主意,因为这样你可以很容易地进行许多矩阵操作。计算修改后的索引在处理时间方面也是比较廉价的。但需要指出的是,虽然有些显然,但这种方法只适用于数值键和矩阵的预定义大小。
function newMdArray(X, Y, Z)
local MT = { __call = function(t, x, y, z, v)
if x>X or y>Y or z>Z or x<1 or y<1 or z<1 then return; end
local k = x + X*(y-1) + X*Y*(z-1);
if v ~= nil then t[k] = v; end
return t[k];
end };
return setmetatable({}, MT);
end
-- 用法
local mdt = newMdArray(100, 100, 100);
local v = mdt(1, 2, 3);
mdt(1, 2, 3, v*.1);
这段代码摘自我另一个答案:dynamic tables or arrays
它可能可以进行一些优化(例如在闭包中计算 X*Y),但我想粘贴原始代码。无论如何,用这种方法可以通过使用正常的数组索引轻松地处理扁平化的结构:
for i=1, #mdt
mdt[i] = (mdt[i] or 0)*.5
end
也可以直接访问3D索引:
mdt(12, 13, 14, 0)
你还可以很容易地修改函数,使它在缺少关键字时返回默认值,只需在元表中添加 __index 字段或以及将表保存为矩阵维度。
- 如何将两个不同的lua文件合成一个 东西有点长 大佬请耐心看完 我是小白研究几天了都没搞定
- 如何在roblox studio中1:1导入真实世界的地形?
- 求解,lua_resume的第二次调用继续执行协程问题。
- 【上海普陀区】内向猫网络招募【Skynet游戏框架Lua后端程序员】
- SF爱好求教:如何用lua实现游戏内调用数据库函数实现账号密码注册?
- Lua实现网站后台开发
- LUA错误显式返回,社区常见的规约是怎么样的
- lua5.3下载库失败
- 请问如何实现文本框内容和某个网页搜索框内容连接,并把网页输出来的结果反馈到另外一个文本框上
- lua lanes多线程使用
- 一个kv数据库
- openresty 有没有比较轻量的 docker 镜像
- 想问一下,有大佬用过luacurl吗
- 在Lua执行过程中使用Load函数出现问题
- 为什么 neovim 里没有显示一些特殊字符?
- Lua比较两个表的值(不考虑键的顺序)
- 有个lua简单的项目,外包,有意者加微信 liuheng600456详谈,最好在成都
- 如何在 Visual Studio 2022 中运行 Lua 代码?
- addEventListener 返回 nil Lua
- Lua中获取用户配置主目录的跨平台方法
在你的第一个代码中:
等价于:
这里,
pixels[1]已经是一个表,这就是为什么你可以给pixels[1][5]赋值。但是在你的第二个代码中:
在这里,
pixels仍然是一个二维数组(有3个元素)。它等价于:pixels[1]是一个表,但是pixels[1][4]不是。你需要做的是给pixels[1][4]一个表构造器,像这样:pixels = {{}, {}, {}} pixels[1][4] = {} --将其初始化为空表 pixels[1][4][3] = "red" print(pixels[1][4][3])