Can you inspect a model to find its skin?

I’m creating scenes that can have any number of entities.

Each can have any of the models in the builtin craft.models.

Each needs to use a glow effect at any given time, like in this demo.

In the demo, each robot’s glow relies on materials prepared like this:


        robot.model = craft.model(asset.builtin.Blocky_Characters.Robot)
        robot.material = craft.material(asset.builtin.Materials.Specular)
        robot.material.map = readImage(asset.builtin.Blocky_Characters.RobotSkin)

Notice that for material.map I have to directly read the image used for the model’s skin.

But as I said, in the real project, entities can use any craft model, not just robots.

So is there a way to access this skin dynamically, in other words, without knowing what it is beforehand?

Because if there isn’t, in order to be able to use this effect in my project, I think I will need to manually hand-code the image that goes with every single craft model.

And if the models or skins are ever changed in the future the project will break.

So, like, that’s not good, man. :slight_smile:

To use this approach, I think I have to be able to do something like this:


function assignMaterial(thisEntity)
       local skinImage = thisEntity.skin
       thisEntity.material = craft.material(asset.builtin.Materials.Specular)
       thisEntity.material.map = skinImage
end

…but I can’t do that because thisEntity.skin isn’t an attribute that actually exists.

Is there some way to do this without hand-coding the value for skin for each model?

@UberGoober You could probably put them in a table along with other info and use that to identify what material you want.

@dave1707 wouldnt I still have to hand-code them, leaving them open to breaking the entire code if updates change anything referenced?

@UberGoober - the image for the model will be loaded with the other model files, probable a png file. If you could identify it you could probably use saveImage() - but, the models loaded are probably licensed so you may not be able to use it.
You may be able to load a single colour png image as a texture - if so you could also load a varicoulored mesh texture to identify the key vertices on the model then colour the model section as needed. You need a graphics package to do so.

@Bri_G I’m not sure I get what you’re saying, are you suggesting creating a routine that reads every single image in the Codea built-ins, and then compares it to the model to identify which image is that model’s skin?

Because if that’s not what you’re suggesting, don’t I still have to know the file name beforehand?

@UberGoober - you seem concerned with losing models/skins and not being able to retain them to avoid their loss in updates.Just suggesting how you could retain the textures or at least the texture map to edit if needed. Not for all - just the ones you hoped to retain.

@UberGoober Here’s an example with a table. I can identify each character by the name I gave them in the first position of the table. Does this help in what you’re after.

function setup()
    mtab={
        {   "robot",
            asset.builtin.Blocky_Characters.Robot,
            asset.builtin.Materials.Specular,
            asset.builtin.Blocky_Characters.RobotSkin
        },
        {   "man",
            asset.builtin.Blocky_Characters.Man,
            asset.builtin.Materials.Specular,
            asset.builtin.Blocky_Characters.ManSkin
        },
        {   "orc",
            asset.builtin.Blocky_Characters.Orc,
            asset.builtin.Materials.Specular,
            asset.builtin.Blocky_Characters.OrcSkin
        },
        {   "woman",
            asset.builtin.Blocky_Characters.Woman,
            asset.builtin.Materials.Specular,
            asset.builtin.Blocky_Characters.WomanSkin
        },
        {   "soldier",
            asset.builtin.Blocky_Characters.Soldier,
            asset.builtin.Materials.Specular,
            asset.builtin.Blocky_Characters.SoldierSkin
        },
        }
    
    tab={}
    scene = craft.scene()
    scene.sun.rotation=quat.eulerAngles(30,45,30)
    v=scene.camera:add(OrbitViewer, vec3(0,0,0), 200, 0, 1000)
    v.ry=180
    
    cameraComponent = scene.camera:get(craft.camera)
    cameraComponent.hdr = true
    cameraComponent.colorTextureEnabled = true
    
    bloom = craft.bloomEffect()
    cameraComponent:addPostEffect(bloom)
    
    bloom.threshold = 4
    bloom.intensity = 1.2
    bloom.softThreshold = 0.4
    bloom.iterations = 8
    
    for z=1,50 do
        local robot = scene:entity()
        v=z%5+1
        robot.model = craft.model(mtab[v][2])
        robot.material = craft.material(mtab[v][3])
        robot.material.map = readImage(mtab[v][4])
        
        x=math.random(-50,50)
        y=math.random(-50,50)
        z=math.random(-50,50)
        robot.position = vec3(x,y,z)
        table.insert(tab,{rb=robot,x=x,y=y,z=z,r=0,a=false})
    end
    parameter.integer("pos",1,#tab,position)
    parameter.integer("Rotate",-180,180,0,rotate)
    parameter.boolean("int",false,intensity)
end

function update(dt)
    scene:update(dt)
end

function rotate()
    tab[pos].r=Rotate
end

function draw()
    update(DeltaTime)
    tab[pos].rb.eulerAngles = vec3(0,tab[pos].r, 0)
    scene:draw()
end

function position()
    Rotate=tab[pos].r
    int=tab[pos].a
end

function intensity()
    if int then
        tab[pos].rb.material.diffuse = vec3(2.5,1.5,4)
        tab[pos].a=true
    else
        tab[pos].rb.material.diffuse = vec3(1,1,1)
        tab[pos].a=false
    end
end

In case anyone else has this issue: you can dynamically get the material that’s using the skin on any of the default models with the technique @piinthesky shows here:

https://codea.io/talk/discussion/comment/83517#Comment_83517

…the secret is the undocumented function entity.model:getMaterial(0)

@UberGoober I’ve made a note to write documentation for this and other Craft functions

@Simeon as reported in the orignal thread
https://codea.io/talk/discussion/10831/add-transparency-to-a-3d-obj-mtl-model
i did not actually suceed to reproduce what @John showed and would really like to do so! Help please @John.

@Simeon when you document it, please give significant emphasis to the apparent fact that model:getMaterial(i) is indexed starting with 0, unlike everything else in lua. Since it’s at variance with the whole rest of the language, I think it will be very easy for people to get tripped up by this.

@UberGoober given that this is undocumented, I think we should change it to a 1-based index to match the rest of the language

@Simeon oh I absolutely agree, I didn’t know that was an option.