Howdy, Stranger!

It looks like you're new here. If you want to get involved, click one of these buttons!

how might i draw a die?

suppose i wanted to use a craft.model cube as a die (six-sided, half a pair of dice, ...). seems either i need six images, and somehow map each one to a face, or a single image that wraps the die properly. i can produce either kind of image, but so far all i've found (material.map) puts the whole image on all faces.

related: is there anything written up on creating asset packs, or any editable examples?

thanks ...

r

Comments

  • Posts: 1,754
    @RonJeffries - there are several examples of a die object from code, a search for Rubic cubes may help. Conversely if you search for a sky box - they use images viewed from the inside and the texture images are built in a specific way. All you need to do with the skybox is view it from the outside - if image placement on each face is important you may have to modify each image orientation. I'll see if I can find a few refs.

    @John has a skybox built into Craft - you could start with that.
  • dave1707dave1707 Mod
    Posts: 8,458

    @RonJeffries Heres something I just put together.

    displayMode(FULLSCREEN)
    
    function setup()
        noSmooth()
        rectMode(CORNER)
    
        img=image(600,100)    
        setContext(img)
        background(0, 0, 0, 255)
    
        fill(255)
        rect(0,0,600,100)
    
        fill(0)
        ellipse(50,50,20)
    
        ellipse(125,75,20)
        ellipse(175,25,20)
    
        ellipse(525,75,20)
        ellipse(550,50,20)
        ellipse(575,25,20)
    
        ellipse(425,75,20)
        ellipse(425,25,20)
        ellipse(475,75,20)
        ellipse(475,25,20)
    
        ellipse(350,50,20)
        ellipse(325,75,20)
        ellipse(325,25,20)
        ellipse(375,75,20)
        ellipse(375,25,20)
    
        ellipse(225,75,20)
        ellipse(250,75,20)
        ellipse(275,75,20)    
        ellipse(225,25,20)
        ellipse(250,25,20)
        ellipse(275,25,20)
        setContext()
    
        assert(OrbitViewer, "Please include Cameras (not Camera) as a dependency")
    
        scene = craft.scene()
        m = scene:entity()
        m.model = craft.model.cube(vec3(1,1,1))
        m.material = craft.material("Materials:Specular")
        m.material.map = img  
    
        uvs1={}
        c=0
        for x=1,6 do
            table.insert(uvs1,vec2(c/6,0))
            table.insert(uvs1,vec2((c+1)/6,0))
            table.insert(uvs1,vec2((c+1)/6,1))
            table.insert(uvs1,vec2(c/6,1))
            c=c+1
        end
        m.model.uvs=uvs1
    
        viewer = scene.camera:add(OrbitViewer, vec3(0), 10, 0, 2000)
        viewer.camera.farPlane=3000
    end
    
    function update(dt)
        scene:update(dt)
    end
    
    function draw()
        update(DeltaTime)
        scene:draw() 
        sprite(img,WIDTH/2,HEIGHT-100)   
    end
    
  • edited February 11 Posts: 649

    sweet, and very clear.
    questions: how did you find member table uvs, and how did you figure out the cube uv mapping was in that order?

    thanks!!

  • hmm, also nice that it didn't have to be done in triangles :)

  • @Bri_G hm, never thought to search for anything that specific, was searching for more general terms. guess i better up my search game. thanks!

  • edited February 11 Posts: 1,754

    @dave1707 - neat and fast response, is this another project to you library?

    p.s. Am I right and you don’t need to add Craft as a dependency now - totally forgot since haven’t used Craft for ages - hence my interest now.

  • dave1707dave1707 Mod
    Posts: 8,458

    @RonJeffries If you look at the reference under Craft, Craft.model, you’ll see the different tables and what they’re for. As for the mapping order, it was mostly by trial and error when Craft first came out. I spent a lot of time trying to figure out how to put a texture on a Craft.sphere before I was able to do it.

  • dave1707dave1707 Mod
    Posts: 8,458

    @Bri_G It’s in my library now. I copied code from a different project and then created the dice strip to wrap the cube.

  • dave1707dave1707 Mod
    Posts: 8,458

    The above code could be modified to use a sky box, an image in the shape of a cross to wrap a cube.

  • Posts: 1,754

    @dave1707 - that was the thoughts going through my head when I saw your code and ran it. I spent quite a long time building up sky texture boxes on graphic design programs to produce skyboxes - that’s where I found out about orientation of each face on the texture.

  • dave1707dave1707 Mod
    Posts: 8,458

    @Bri_G Heres code that will use a sky box. I didn’t pull one in, but they can be found if you search for sky box. I created my own skybox shape.

    displayMode(FULLSCREEN)
    
    function setup()
        rectMode(CORNER)
        noSmooth()
        img=image(400,300)
        setContext(img)
        background(0, 0, 0, 255)
        for x=0,3 do
            fill(math.random(255),math.random(255),math.random(255))
            rect(x*100,1*100,100,100)
        end
        fill(math.random(255),math.random(255),math.random(255))
        rect(100,0,100,100)
        fill(math.random(255),math.random(255),math.random(255))
        rect(100,200,100,100)
        fill(255)
        text("front",150,150)
        text("left",50,150)
        text("right",250,150)
        text("back",350,150)
        text("top",150,250)
        text("bottom",150,50)
        setContext()
        assert(OrbitViewer, "Please include Cameras (not Camera) as a dependency")
        scene = craft.scene()
        v=scene.camera:add(OrbitViewer, vec3(0,0,0), 60, 0, 200)
        createCube()
    end
    
    function createCube()
        ww=scene:entity()
        ww.position=vec3(0,-7,0)
        ww.model = craft.model.cube(vec3(10,10,10))
        ww.material = craft.material("Materials:Standard")
        ww.material.map = img
        ww.model.uvs=
            {   vec2(0,2/3),vec2(1/4,2/3),vec2(1/4,1/3),vec2(0,1/3),
                vec2(3/4,2/3),vec2(1,2/3),vec2(1,1/3),vec2(3/4,1/3),
                vec2(1/2,2/3),vec2(3/4,2/3),vec2(3/4,1/3),vec2(1/2,1/3),
                vec2(1/4,2/3),vec2(1/2,2/3),vec2(1/2,1/3),vec2(1/4,1/3),
                vec2(1/4,1),vec2(1/2,1),vec2(1/2,2/3),vec2(1/4,2/3),
                vec2(1/2,0),vec2(1/4,0),vec2(1/4,1/3),vec2(1/2,1/3) }
    end
    
    function draw()
        update(DeltaTime)
        scene:draw() 
        sprite(img,WIDTH/2,HEIGHT-200) 
    end
    
    function update(dt)
        scene:update(dt)
    end
    
  • neat, dave, thanks again. i think i need to think more about how UVs map, the vertex focus doesn't fit my mental model from blender, which is probably wrong.

    now i gotta look for the sphere mapping. :)

    thanks again.

  • dave1707dave1707 Mod
    edited February 12 Posts: 8,458

    @RonJeffries Look at the link below. My code for a textured sphere is near the bottom. You can zoom inside the sphere and view it there also.

    https://codea.io/talk/discussion/9133/craft-sphere-texture#latest
    
  • thanks!

  • Posts: 789

    @dave1707 really nice example and great entry point. Trying to make the cube(s) semi transparent by setting

        ww.material.opacity=0.1
    

    Which doesn’t seem to do anything. Probably a lot more complicated but wondered if you had pointers. Ideally want to have the surfaces facing the camera rendered semi transparent with the rear inside surfaces fully transparent. Imagine having a 3 x 3 x 3 rubics cube and beIng able to see through the front facing layer

  • Posts: 789

    Found the solution

    https://codea.io/talk/discussion/8858/transparency-in-craft

    ww.material.BlendMode=NORMAL
    
  • edited February 12 Posts: 1,754

    @dave1707 - just added some simple texturing to your code:


    function setup() rectMode(CORNER) noSmooth() spriteMode(CENTER) img=image(400,300) setContext(img) background(0, 0, 0, 255) sprite("Blocks:Brick Grey",150,50,100,100) sprite("Blocks:Brick Red",150,150,100,100) sprite("Blocks:Cotton Tan",150,250,100,100) sprite("Blocks:Cotton Green",50,150,100,100) sprite("Blocks:Cactus Inside",250,150,100,100) sprite("Blocks:Cotton Blue",350,150,100,100) text("front",150,150) text("left",50,150) text("right",250,150) text("back",350,150) text("top",150,250) text("bottom",150,50) setContext() assert(OrbitViewer, "Please include Cameras (not Camera) as a dependency") scene = craft.scene() v=scene.camera:add(OrbitViewer, vec3(0,0,0), 60, 0, 200) createCube() end

    Just replace the setup() function.

  • dave1707dave1707 Mod
    Posts: 8,458

    @West Heres a link to a Craft example where I use opacity. The blendmode is important, glad you found it. It’s the code at the beginning of the discussion.

    https://codea.io/talk/discussion/8800/craft-physics-example
    
  • dave1707dave1707 Mod
    Posts: 8,458

    @Bri_G That makes it different. You can change each side with whatever you want.

  • Posts: 490

    Here's my die code, for the record.

    -- DieCraft
    
    function setup(
        displayMode(FULLSCREEN)
        local dieimg = image(600,100)
        setContext(dieimg)
        background(255, 255, 255, 255)
        noFill()
        stroke(0, 0, 0, 255)
        strokeWidth(10)
        noSmooth()
        for k=1,6 do
            rect(100*(k-1)-5,-5,110,110)
        end
        noStroke()
        fill(0, 0, 0, 255)
        for k=0,5 do
            for j=0,3 do
                rect(100*k+90*math.floor(j/2),90*(j%2),10,10)
            end
        end
        fill(255, 255, 255, 255)
        ellipseMode(RADIUS)
        for k=0,5 do
            for j=0,3 do
                ellipse(100*k+10+80*math.floor(j/2),10+80*(j%2),6)
            end
        end
        fill(0, 0, 0, 255)
        ellipseMode(CENTER)
        noStroke()
        fill(255, 0, 0, 255)
        ellipse(100*(5-1)+50,50,15)
        fill(0, 0, 0, 255)
        for k=1,2 do
            ellipse(100*(k-1)+50,50,15)
        end
        for _,k in ipairs({1,2,3,4,6}) do
            fill(255, 0, 0, 255)
            ellipse(100*(k-1)+25,25,15)
            fill(0, 0, 0, 255)
            ellipse(100*(k-1)+75,75,15)
        end
        for _,k in ipairs({1,4,6}) do
            ellipse(100*(k-1)+75,25,15)
            ellipse(100*(k-1)+25,75,15)
        end
        ellipse(525,50,15)
        ellipse(575,50,15)
        setContext()
    
        scene = craft.scene()
        scene.camera.z = -15
        die = scene:entity()
        die.model = craft.model("Primitives:RoundedCube")
        local uvs = {}
        local p,u,x,y,z
        for k=1,die.model.vertexCount do
            p = vec3(die.model:position(k))
            u = vec2(die.model:uv(k))
            u.x = u.x / 6
            x = math.abs(p.x)
            y = math.abs(p.y)
            z = math.abs(p.z)
            if x > y and x > z then
                if p.x > 0 then
    
                else
                    u.x = u.x + 2/6
                end
            elseif y > z then
                if p.y > 0 then
                    u.x = u.x + 1/6
                else
                    u.x = u.x + 3/6
                end
            else
                if p.z > 0 then
                    u.x = u.x + 4/6
                else
                    u.x = u.x + 5/6
                end
            end
            table.insert(uvs,u)
        end
        die.model.uvs = uvs
        die.material = craft.material("Materials:Specular")
        die.material.map = dieimg
        die:add(Spinner)
    
    end
    
    function draw()
        background(72, 55, 55, 255)
        scene:update(DeltaTime)
        scene:draw()
        sprite(dieimg,WIDTH/2,50)
    end
    
    function touched(t)
        if t.state == ENDED then
            if t.tapCount == 2 then
                if state == 3 then
                    state = 2
                else
                    state = 3
                end
            else
                if state == 1 then
                    die:get(Spinner):setRoll()
                    state = 2
                elseif state == 2 then
                    die:get(Spinner).rolling = true
                    state = 1
                end
            end
        end
    end
    
    local sides
    Spinner = class()
    
    function Spinner:init(e)
        self.entity = e
        self.target = quat(1,0,0,0)
        self:setRotation()
        self.rolling = true
        sides = sides or {
            quat.fromToRotation(vec3(1,0,0),vec3(0,0,1)),
            quat(1,0,0,0),
            quat.fromToRotation(vec3(0,-1,0),vec3(0,0,1)),
            quat.fromToRotation(vec3(0,1,0),vec3(0,0,1)),
            quat.fromToRotation(vec3(0,0,-1),vec3(0,0,1)),
            quat.fromToRotation(vec3(-1,0,0),vec3(0,0,1))
        }
    end
    
    function Spinner:setRotation()
        self.start = self.target
        self.target = quat.random()
        self.life = self.start:sdist(self.target)
        self.time = 0
        self.rotation = self.start:make_slerp(self.target)
    end
    
    function Spinner:setRoll()
        self.start = self.entity.rotation
        self.value = math.random(1,6)
        self.target = sides[self.value]
        self.life = self.start:sdist(self.target)
        self.time = 0
        self.rotation = self.start:make_slerp(self.target)
        self.rolling = false
    end
    
    function Spinner:update(dt)
        dt = dt or DeltaTime
        self.time = self.time + dt
        local t = self.time/self.life
        t = math.min(1,math.max(0,t)) 
        self.entity.rotation = self.rotation(t)
        if t == 1 and self.rolling then
            self:setRotation()
        end
    end
    

    It uses my extension of the quat userdata which adds some extra functions such as choosing a quat at random. You can get that from github at https://github.com/loopspace/Codea-Library-Maths

  • thanks, @LoopSpace! @dave1707 i noticed your coloring dice thing is doing the uvs counter clockwise, so the texture is flipped. can't tell well with dice, pretty clear with text. reordering the calls will fix readily.

  • dave1707dave1707 Mod
    Posts: 8,458

    @LoopSpace Getting multiple errors on your above code.

  • dave1707dave1707 Mod
    Posts: 8,458

    @RonJeffries Heres the dice uvs reversed. This should do text correctly.

            table.insert(uvs1,vec2(c/6,1))
            table.insert(uvs1,vec2((c+1)/6,1))
            table.insert(uvs1,vec2((c+1)/6,0))
            table.insert(uvs1,vec2(c/6,0))
    
  • @dave1707 yes, I did similarly and posted my thingie over in the UV question I guess. I think for @LoopSpace 's thing to run you may need to fetch his quat extensions.

  • Posts: 490

    Yes, for my code then you need to get the VecExt file from the github link and include it as a tab/dependency. It adds a huge amount of extra functionality to the native vector/matrix/quat userdata. This project only uses a few bits of it, but I find it useful to put stuff like that in a separate project since I use it in just about every project that I write.

Sign In or Register to comment.