Displacement map prototype (#26709)
Requires https://github.com/space-wizards/RobustToolbox/pull/5023 This uses the new engine features (above) to add a displacement map shader. This allows deforming a sprite based on another sprite. Primary use case is automatically adapting human clothing sprites to different species, something we want to make species like Vox a reality. A basic example of wiring this up with Vox has been added. The system is however incredibly simple and **will** need more work by a content developer to select and toggle displacement maps when appropriate. I am leaving that to somebody else. For example right now the displacement map is applied even if a species already has custom-fit sprites for a piece of clothing, such as the grey jumpsuit for Vox. Basic Aseprite plugins to help with authoring displacement maps have also been made.
This commit is contained in:
committed by
GitHub
parent
b4212a08f4
commit
2f7d0dedbd
78
Tools/SS14 Aseprite Plugins/Displacement Map Flip.lua
Normal file
78
Tools/SS14 Aseprite Plugins/Displacement Map Flip.lua
Normal file
@@ -0,0 +1,78 @@
|
||||
local sprite = app.editor.sprite
|
||||
local cel = app.cel
|
||||
|
||||
if sprite.selection.isEmpty then
|
||||
print("You need to select something sorry")
|
||||
return
|
||||
end
|
||||
|
||||
local diag = Dialog{
|
||||
title = "Flip Displacement Map"
|
||||
}
|
||||
|
||||
diag:check{
|
||||
id = "horizontal",
|
||||
label = "flip horizontal?"
|
||||
}
|
||||
|
||||
diag:check{
|
||||
id = "vertical",
|
||||
label = "flip vertical?"
|
||||
}
|
||||
|
||||
diag:button{
|
||||
text = "ok",
|
||||
focus = true,
|
||||
onclick = function(ev)
|
||||
local horizontal = diag.data["horizontal"]
|
||||
local vertical = diag.data["vertical"]
|
||||
|
||||
local selection = sprite.selection
|
||||
local image = cel.image:clone()
|
||||
|
||||
for x = 0, selection.bounds.width do
|
||||
for y = 0, selection.bounds.height do
|
||||
local xSel = x + selection.origin.x
|
||||
local ySel = y + selection.origin.y
|
||||
|
||||
local xImg = xSel - cel.position.x
|
||||
local yImg = ySel - cel.position.y
|
||||
|
||||
if xImg < 0 or xImg >= image.width or yImg < 0 or yImg >= image.height then
|
||||
goto continue
|
||||
end
|
||||
|
||||
local imgValue = image:getPixel(xImg, yImg)
|
||||
local color = Color(imgValue)
|
||||
|
||||
if horizontal then
|
||||
color.red = 128 + -(color.red - 128)
|
||||
end
|
||||
|
||||
if vertical then
|
||||
color.green = 128 + -(color.green - 128)
|
||||
end
|
||||
|
||||
image:drawPixel(
|
||||
xImg,
|
||||
yImg,
|
||||
app.pixelColor.rgba(color.red, color.green, color.blue, color.alpha))
|
||||
|
||||
::continue::
|
||||
end
|
||||
end
|
||||
|
||||
cel.image = image
|
||||
|
||||
diag:close()
|
||||
end
|
||||
}
|
||||
|
||||
diag:button{
|
||||
text = "cancel",
|
||||
onclick = function(ev)
|
||||
diag:close()
|
||||
end
|
||||
}
|
||||
|
||||
diag:show()
|
||||
135
Tools/SS14 Aseprite Plugins/Displacement Map Visualizer.lua
Normal file
135
Tools/SS14 Aseprite Plugins/Displacement Map Visualizer.lua
Normal file
@@ -0,0 +1,135 @@
|
||||
-- Displacement Map Visualizer
|
||||
--
|
||||
-- This script will create a little preview window that will test a displacement map.
|
||||
--
|
||||
-- TODO: Handling of sizes != 127 doesn't work properly and rounds differently from the real shader. Ah well.
|
||||
|
||||
local scale = 4
|
||||
|
||||
-- This script requires UI
|
||||
if not app.isUIAvailable then
|
||||
return
|
||||
end
|
||||
|
||||
local getOffsetPixel = function(x, y, image, rect)
|
||||
local posX = x - rect.x
|
||||
local posY = y - rect.y
|
||||
|
||||
if posX < 0 or posX >= image.width or posY < 0 or posY >= image.height then
|
||||
return image.spec.transparentColor
|
||||
end
|
||||
|
||||
return image:getPixel(posX, posY)
|
||||
end
|
||||
|
||||
local pixelValueToColor = function(sprite, value)
|
||||
return Color(value)
|
||||
end
|
||||
|
||||
local applyDisplacementMap = function(width, height, size, displacement, displacementRect, target, targetRect)
|
||||
-- print(Color(displacement:getPixel(17, 15)).red)
|
||||
local image = target:clone()
|
||||
image:resize(width, height)
|
||||
image:clear()
|
||||
|
||||
for x = 0, width - 1 do
|
||||
for y = 0, height - 1 do
|
||||
local value = getOffsetPixel(x, y, displacement, displacementRect)
|
||||
local color = pixelValueToColor(sprite, value)
|
||||
|
||||
if color.alpha ~= 0 then
|
||||
local offset_x = (color.red - 128) / 127 * size
|
||||
local offset_y = (color.green - 128) / 127 * size
|
||||
|
||||
local colorValue = getOffsetPixel(x + offset_x, y + offset_y, target, targetRect)
|
||||
image:drawPixel(x, y, colorValue)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
return image
|
||||
end
|
||||
|
||||
local dialog = nil
|
||||
|
||||
local sprite = app.editor.sprite
|
||||
local spriteChanged = sprite.events:on("change",
|
||||
function(ev)
|
||||
dialog:repaint()
|
||||
end)
|
||||
|
||||
local layers = {}
|
||||
for i,layer in ipairs(sprite.layers) do
|
||||
table.insert(layers, 1, layer.name)
|
||||
end
|
||||
|
||||
local findLayer = function(sprite, name)
|
||||
for i, layer in ipairs(sprite.layers) do
|
||||
if layer.name == name then
|
||||
return layer
|
||||
end
|
||||
end
|
||||
|
||||
return nil
|
||||
end
|
||||
|
||||
dialog = Dialog{
|
||||
title = "Displacement map preview",
|
||||
onclose = function(ev)
|
||||
sprite.events:off(spriteChanged)
|
||||
end}
|
||||
|
||||
dialog:canvas{
|
||||
id = "canvas",
|
||||
width = sprite.width * scale,
|
||||
height = sprite.height * scale,
|
||||
onpaint = function(ev)
|
||||
local context = ev.context
|
||||
|
||||
local layerDisplacement = findLayer(sprite, dialog.data["displacement-select"])
|
||||
local layerTarget = findLayer(sprite, dialog.data["reference-select"])
|
||||
-- print(layerDisplacement.name)
|
||||
-- print(layerTarget.name)
|
||||
local celDisplacement = layerDisplacement:cel(1)
|
||||
local celTarget = layerTarget:cel(1)
|
||||
local image = applyDisplacementMap(
|
||||
sprite.width, sprite.height,
|
||||
dialog.data["size"],
|
||||
celDisplacement.image, celDisplacement.bounds,
|
||||
celTarget.image, celTarget.bounds)
|
||||
|
||||
context:drawImage(image, 0, 0, image.width, image.height, 0, 0, image.width * scale, context.width, context.height)
|
||||
end
|
||||
}
|
||||
|
||||
dialog:combobox{
|
||||
id = "displacement-select",
|
||||
label = "displacement layer",
|
||||
options = layers,
|
||||
onchange = function(ev)
|
||||
dialog:repaint()
|
||||
end
|
||||
}
|
||||
|
||||
dialog:combobox{
|
||||
id = "reference-select",
|
||||
label = "reference layer",
|
||||
options = layers,
|
||||
onchange = function(ev)
|
||||
dialog:repaint()
|
||||
end
|
||||
}
|
||||
|
||||
|
||||
dialog:slider{
|
||||
id = "size",
|
||||
label = "displacement size",
|
||||
min = 1,
|
||||
max = 127,
|
||||
value = 127,
|
||||
onchange = function(ev)
|
||||
dialog:repaint()
|
||||
end
|
||||
}
|
||||
|
||||
dialog:show{wait = false}
|
||||
Reference in New Issue
Block a user