Page 20 of 22

Re: Groverburger's 3D Engine (g3d) v1.5.2 Release

Posted: Thu Jan 26, 2023 9:38 pm
by Frankom
It's working with anim9?

Re: Groverburger's 3D Engine (g3d) v1.5.2 Release

Posted: Sun Jan 29, 2023 7:01 am
by Jasoco
It's amazing what you can do with shaders when you spend a little time Googling and experimenting.
Screenshot 2023-01-29 at 1.35.47 AM.png
Screenshot 2023-01-29 at 1.35.47 AM.png (1023.73 KiB) Viewed 12288 times
Screenshot 2023-01-29 at 1.33.44 AM.png
Screenshot 2023-01-29 at 1.33.44 AM.png (763.4 KiB) Viewed 12288 times
Screenshot 2023-01-29 at 1.32.39 AM.png
Screenshot 2023-01-29 at 1.32.39 AM.png (979.47 KiB) Viewed 12288 times
Screenshot 2023-01-29 at 1.33.22 AM.png
Screenshot 2023-01-29 at 1.33.22 AM.png (1.55 MiB) Viewed 12288 times
Screenshot 2023-01-29 at 1.36.58 AM.png
Screenshot 2023-01-29 at 1.36.58 AM.png (1.12 MiB) Viewed 12288 times
Screenshot 2023-01-29 at 1.36.23 AM.png
Screenshot 2023-01-29 at 1.36.23 AM.png (750.86 KiB) Viewed 12288 times
I do wish I could do true lighting though. With shadows and such. Right now it's pretty simplistic. A mixture of calculated point lights and pre-baked lighting. Also every texture can have an associated "bright pixel" atlas for textures that need to have parts that are always full brightness. (For example, the green lights on the doors, the fluorescent lights in the last screenshot and the soda machine facades are all bright pixels.)

Also, everything is pretty much coded tables instead of .obj files. I haven't been able to figure out how to use 3D modeling software and the ones that I like don't export the files with the proper axis "up" that g3d expects. So I find it easier to just construct everything from triangles manually. I feel that uses a lot of memory though. I had a lot of memory problems with some of my earlier experiments where I was trying to make too big of a world with way too many polygons. So I borrowed the method used by Leadhaul for building my maps and creating my sprites.

Re: Groverburger's 3D Engine (g3d) v1.5.2 Release

Posted: Sun Jan 29, 2023 6:08 pm
by Bigfoot71
I made a pull request on the g3d repo so that the objloader.lua script accepts models with non-triangulated faces, here is my version if you want to use it now:

Code: Select all

-- written by groverbuger for g3d
-- september 2021
-- MIT license

----------------------------------------------------------------------------------------------------
-- simple obj loader
----------------------------------------------------------------------------------------------------

-- give path of file
-- returns a lua table representation
return function (path, uFlip, vFlip)
    local positions, uvs, normals = {}, {}, {}
    local result = {}

    -- go line by line through the file
    for line in love.filesystem.lines(path) do
        local words = {}

        -- split the line into words
        for word in line:gmatch "([^%s]+)" do
            table.insert(words, word)
        end

        local firstWord = words[1]

        if firstWord == "v" then
            -- if the first word in this line is a "v", then this defines a vertex's position

            table.insert(positions, {tonumber(words[2]), tonumber(words[3]), tonumber(words[4])})
        elseif firstWord == "vt" then
            -- if the first word in this line is a "vt", then this defines a texture coordinate

            local u, v = tonumber(words[2]), tonumber(words[3])

            -- optionally flip these texture coordinates
            if uFlip then u = 1 - u end
            if vFlip then v = 1 - v end

            table.insert(uvs, {u, v})
        elseif firstWord == "vn" then
            -- if the first word in this line is a "vn", then this defines a vertex normal
            table.insert(normals, {tonumber(words[2]), tonumber(words[3]), tonumber(words[4])})
        elseif firstWord == "f" then

            -- if the first word in this line is a "f", then this is a face
            -- a face takes three point definitions
            -- the arguments a point definition takes are vertex, vertex texture, vertex normal in that order

            local vertices = {}
            for i = 2, #words do
                local v, vt, vn = words[i]:match "(%d*)/(%d*)/(%d*)"
                v, vt, vn = tonumber(v), tonumber(vt), tonumber(vn)
                table.insert(vertices, {
                    v and positions[v][1] or 0,
                    v and positions[v][2] or 0,
                    v and positions[v][3] or 0,
                    vt and uvs[vt][1] or 0,
                    vt and uvs[vt][2] or 0,
                    vn and normals[vn][1] or 0,
                    vn and normals[vn][2] or 0,
                    vn and normals[vn][3] or 0,
                })
            end

            -- triangulate the face if it's not already a triangle
            if #vertices > 3 then
                -- choose a central vertex
                local centralVertex = vertices[1]

                -- connect the central vertex to each of the other vertices to create triangles
                for i = 2, #vertices - 1 do
                    table.insert(result, centralVertex)
                    table.insert(result, vertices[i])
                    table.insert(result, vertices[i + 1])
                end
            else
                for i = 1, #vertices do
                    table.insert(result, vertices[i])
                end
            end

        end
    end

    return result
end
It works very well for all the models I have tested, tell me what you think ^^

Re: Groverburger's 3D Engine (g3d) v1.5.2 Release

Posted: Mon Jan 30, 2023 6:43 pm
by Rigachupe
Can you draw a 3D line in this engine? I tried it by defining a vertex array as a 3D line with two points.

This is the desired format
local vertexFormatLines={
{"VertexPosition", "float", 3},
{"VertexColor", "byte", 4},
}

local vertices={{0,0,0,1,1,1,1},{0,0,100,1,1,1,1}}
model.geometry=love.graphics.newMesh(vertexFormatLines,vertices,"lines")

Then to draw it like this:
love.graphics.draw(model.geometry)

The error blue screen shows:
Invalid mesh draw mode 'lines', expected one of the 'triangles', 'fan', 'points'.

Any idea how to do a 3D line without the need to simulate some kind of 3D triangle strip?

Re: Groverburger's 3D Engine (g3d) v1.5.2 Release

Posted: Tue Jan 31, 2023 4:16 pm
by Bigfoot71
Rigachupe wrote: Mon Jan 30, 2023 6:43 pm Can you draw a 3D line in this engine? I tried it by defining a vertex array as a 3D line with two points.

This is the desired format
local vertexFormatLines={
{"VertexPosition", "float", 3},
{"VertexColor", "byte", 4},
}

local vertices={{0,0,0,1,1,1,1},{0,0,100,1,1,1,1}}
model.geometry=love.graphics.newMesh(vertexFormatLines,vertices,"lines")

Then to draw it like this:
love.graphics.draw(model.geometry)

The error blue screen shows:
Invalid mesh draw mode 'lines', expected one of the 'triangles', 'fan', 'points'.

Any idea how to do a 3D line without the need to simulate some kind of 3D triangle strip?
By generating a cylinder? Here is a function I had some time ago:

Code: Select all

function generate_cylinder(height, radius, nb_segments)

    local vertices = {}
    local angle_step = 2 * math.pi / nb_segments
    local angle = 0

    local base_z = -height / 2
    local tip_z = height / 2

    for i = 1, nb_segments do

        local x1 = radius * math.cos(angle)
        local y1 = radius * math.sin(angle)
        local x2 = radius * math.cos(angle + angle_step)
        local y2 = radius * math.sin(angle + angle_step)

        -- Base triangle

        table.insert(vertices, {0,0,base_z})
        table.insert(vertices, {x1,y1,base_z})
        table.insert(vertices, {x2,y2,base_z})

        -- Tip triangle

        table.insert(vertices, {0,0,tip_z})
        table.insert(vertices, {x1,y1,tip_z})
        table.insert(vertices, {x2,y2,tip_z})

        -- Side triangles

        table.insert(vertices, {x1,y1,base_z})
        table.insert(vertices, {x1,y1,tip_z})
        table.insert(vertices, {x2,y2,base_z})

        table.insert(vertices, {x2,y2,tip_z})
        table.insert(vertices, {x2,y2,base_z})
        table.insert(vertices, {x1,y1,tip_z})

        angle = angle + angle_step

    end

    return vertices

end
I made a demo while also trying a plane line style.

Edit: I just added UVs and normals to the function above so I'm sharing it if it can help:

Code: Select all

function generate_cylinder(height, radius, nb_segments)

    local vertices = {}
    local angle_step = 2 * math.pi / nb_segments
    local angle = 0

    local base_z = -height / 2
    local tip_z = height / 2

    for i = 1, nb_segments do

        local x1 = radius * math.cos(angle)
        local y1 = radius * math.sin(angle)
        local x2 = radius * math.cos(angle + angle_step)
        local y2 = radius * math.sin(angle + angle_step)

        -- Base triangle

        table.insert(vertices, {0,0,base_z, 0.5,0.5, 0,0,-1})
        table.insert(vertices, {x1,y1,base_z, 0,1, 0,0,-1})
        table.insert(vertices, {x2,y2,base_z, 1,1, 0,0,-1})

        -- Tip triangle

        table.insert(vertices, {0,0,tip_z, 0.5,0.5, 0,0,1})
        table.insert(vertices, {x1,y1,tip_z, 0,0, 0,0,1})
        table.insert(vertices, {x2,y2,tip_z, 1,0, 0,0,1})

        -- Side triangles

        local edge1_x, edge1_y, edge1_z = x1 - x2, y1 - y2, base_z - tip_z
        local edge2_x, edge2_y, edge2_z = x2 - x1, y2 - y1, base_z - tip_z

        local normal_x = edge1_y * edge2_z - edge1_z * edge2_y
        local normal_y = edge1_z * edge2_x - edge1_x * edge2_z
        local normal_z = edge1_x * edge2_y - edge1_y * edge2_x

        local normal_length = math.sqrt(normal_x * normal_x + normal_y * normal_y + normal_z * normal_z)
        local nx, ny, nz = normal_x / normal_length, normal_y / normal_length, normal_z / normal_length

        table.insert(vertices, {x1,y1,base_z, 0, 0.5 - 0.5*y1/radius, nx,ny,nz})
        table.insert(vertices, {x1,y1,tip_z, 1, 0.5 - 0.5*y1/radius, nx,ny,nz})
        table.insert(vertices, {x2,y2,base_z, 0, 0.5 - 0.5*y2/radius, nx,ny,nz})

        table.insert(vertices, {x2,y2,tip_z, 1, 0.5 - 0.5*y2/radius, nx,ny,nz})
        table.insert(vertices, {x2,y2,base_z, 0, 0.5 - 0.5*y2/radius, nx,ny,nz})
        table.insert(vertices, {x1,y1,tip_z, 1, 0.5 - 0.5*y1/radius, nx,ny,nz})

        angle = angle + angle_step

    end

    return vertices

end
I also tried a slightly more original and demonstrative example.
Image

Re: Groverburger's 3D Engine (g3d) v1.5.2 Release

Posted: Wed Feb 01, 2023 9:43 pm
by Hydrogen Maniac
Jasoco wrote: Sun Jan 29, 2023 7:01 am I do wish I could do true lighting though. With shadows and such. Right now it's pretty simplistic. A mixture of calculated point lights and pre-baked lighting. Also every texture can have an associated "bright pixel" atlas for textures that need to have parts that are always full brightness. (For example, the green lights on the doors, the fluorescent lights in the last screenshot and the soda machine facades are all bright pixels.)

Also, everything is pretty much coded tables instead of .obj files. I haven't been able to figure out how to use 3D modeling software and the ones that I like don't export the files with the proper axis "up" that g3d expects. So I find it easier to just construct everything from triangles manually. I feel that uses a lot of memory though. I had a lot of memory problems with some of my earlier experiments where I was trying to make too big of a world with way too many polygons. So I borrowed the method used by Leadhaul for building my maps and creating my sprites.
This looks great :awesome: ! I really like how you handled the light coming off of lava and the sky.

If you want to give implementing shadows a shot without losing your sanity I recommend looking at the source code of Hoarder's Horrible House Of Stuff. I've had the same issue with modelling software not using the same up vector as g3d but solved it by modifying the objloader to read the y axis as the z axis and vice versa.

Re: Groverburger's 3D Engine (g3d) v1.5.2 Release

Posted: Mon Feb 06, 2023 2:16 am
by vico
Jasoco wrote: Sun Jan 29, 2023 7:01 am It's amazing what you can do with shaders when you spend a little time Googling and experimenting.

Screenshot 2023-01-29 at 1.35.47 AM.png
Screenshot 2023-01-29 at 1.33.44 AM.png
Screenshot 2023-01-29 at 1.32.39 AM.png
Screenshot 2023-01-29 at 1.33.22 AM.png
Screenshot 2023-01-29 at 1.36.58 AM.png
Screenshot 2023-01-29 at 1.36.23 AM.png

I do wish I could do true lighting though. With shadows and such. Right now it's pretty simplistic. A mixture of calculated point lights and pre-baked lighting. Also every texture can have an associated "bright pixel" atlas for textures that need to have parts that are always full brightness. (For example, the green lights on the doors, the fluorescent lights in the last screenshot and the soda machine facades are all bright pixels.)

Also, everything is pretty much coded tables instead of .obj files. I haven't been able to figure out how to use 3D modeling software and the ones that I like don't export the files with the proper axis "up" that g3d expects. So I find it easier to just construct everything from triangles manually. I feel that uses a lot of memory though. I had a lot of memory problems with some of my earlier experiments where I was trying to make too big of a world with way too many polygons. So I borrowed the method used by Leadhaul for building my maps and creating my sprites.
Much amazing! Care to share your googlings?

EDIT: sorry the double post, thought the forum had post auto-merge feature enabled.

Re: Groverburger's 3D Engine (g3d) v1.5.2 Release

Posted: Mon Feb 06, 2023 2:23 am
by vico
Okay. I'm trying to resume starting to make a basic voxel demo myself (to learn more about how to use g3d).

I managed to create a cube using lua tables (still dont understand much what each part of the vert table represents) and at same time put a hello world to see how 2d elements would interact with the 3d enviroment (mostly for maybe create an UI on top of that):

Code: Select all

function love.conf(t)
    t.window.width = 848
    t.window.height = 480
end

Code: Select all

-- Codado por Vico
-- Primeira edição: 12/01/2023
-- À definir a licença

-- Biblioteca g3d
local g3d = require "g3d"

-- Modelo de Cubo
local cube_verts = {
	-- top
	{0,1,1, 0,0},
	{0,0,1, 0,1},
	{1,1,1, 1,0},
	
	{0,0,1, 0,1},
	{1,0,1, 1,1},
	{1,1,1, 1,0},

	-- bottom
	{0,0,0, 1,0},
	{0,1,0, 1,1},
	{1,1,0, 0,1},

	{1,0,0, 0,0},
	{0,0,0, 1,0},
	{1,1,0, 0,1},

	-- side 1
	{0,0,1, 0,0},
	{0,0,0, 0,1},
	{1,0,1, 1,0},

	{0,0,0, 0,1},
	{1,0,0, 1,1},
	{1,0,1, 1,0},

	-- side 2
	{0,1,0, 1,1},
	{0,1,1, 1,0},
	{1,1,1, 0,0},

	{1,1,0, 0,1},
	{0,1,0, 1,1},
	{1,1,1, 0,0},

	-- side 3
	{0,0,0, 1,1},
	{0,0,1, 1,0},
	{0,1,1, 0,0},

	{0,1,0, 0,1},
	{0,0,0, 1,1},
	{0,1,1, 0,0},

	-- side 4
	{1,0,1, 0,0},
	{1,0,0, 0,1},
	{1,1,1, 1,0},

	{1,0,0, 0,1},
	{1,1,0, 1,1},
	{1,1,1, 1,0},
};

-- Modelo 3D
local dirt = g3d.newModel(cube_verts, "assets/textures/blocks/dirt.png");

local timer = 0;

-- debug
function love.draw()
    love.graphics.print("Hello World", 400, 300)
	dirt:draw();
end

function love.update(dt)
	timer = timer + dt;
	g3d.camera.firstPersonMovement(dt);
    if love.keyboard.isDown "escape" then
        love.event.push "quit"
    end
end

function love.mousemoved(x,y, dx,dy)
    g3d.camera.firstPersonLook(dx,dy);
end
But seems like the cube is being "weirdly" rendered (inside-out), like the issue i reported on g3d_voxel, and the 2d test is rendered behind the cube:
Image

Re: Groverburger's 3D Engine (g3d) v1.5.2 Release

Posted: Mon Feb 06, 2023 8:34 pm
by Hydrogen Maniac
vico wrote: Mon Feb 06, 2023 2:23 am But seems like the cube is being "weirdly" rendered (inside-out), like the issue i reported on g3d_voxel, and the 2d test is rendered behind the cube:
Rendering the scene to a canvas seems to solve it. I still have no idea why this is the case but the below code should work as intended.

Code: Select all

-- Codado por Vico
-- Primeira edição: 12/01/2023
-- À definir a licença

-- Biblioteca g3d
local g3d = require "g3d"

-- Modelo de Cubo
local cube_verts = {
	-- top
	{0,1,1, 0,0},
	{0,0,1, 0,1},
	{1,1,1, 1,0},
	
	{0,0,1, 0,1},
	{1,0,1, 1,1},
	{1,1,1, 1,0},

	-- bottom
	{0,0,0, 1,0},
	{0,1,0, 1,1},
	{1,1,0, 0,1},

	{1,0,0, 0,0},
	{0,0,0, 1,0},
	{1,1,0, 0,1},

	-- side 1
	{0,0,1, 0,0},
	{0,0,0, 0,1},
	{1,0,1, 1,0},

	{0,0,0, 0,1},
	{1,0,0, 1,1},
	{1,0,1, 1,0},

	-- side 2
	{0,1,0, 1,1},
	{0,1,1, 1,0},
	{1,1,1, 0,0},

	{1,1,0, 0,1},
	{0,1,0, 1,1},
	{1,1,1, 0,0},

	-- side 3
	{0,0,0, 1,1},
	{0,0,1, 1,0},
	{0,1,1, 0,0},

	{0,1,0, 0,1},
	{0,0,0, 1,1},
	{0,1,1, 0,0},

	-- side 4
	{1,0,1, 0,0},
	{1,0,0, 0,1},
	{1,1,1, 1,0},

	{1,0,0, 0,1},
	{1,1,0, 1,1},
	{1,1,1, 1,0},
};

-- Modelo 3D
local dirt = g3d.newModel(cube_verts, "assets/textures/blocks/dirt.png");

local timer = 0;

-- debug
local canvas = love.graphics.newCanvas(love.graphics.getDimensions())
function love.draw()
    love.graphics.setCanvas({canvas,depth=true})
    love.graphics.clear()
    love.graphics.print("Hello World", 400, 300)
	dirt:draw();

    love.graphics.setCanvas()
    love.graphics.draw(canvas)
end

function love.update(dt)
	timer = timer + dt;
	g3d.camera.firstPersonMovement(dt);
    if love.keyboard.isDown "escape" then
        love.event.push "quit"
    end
end

function love.mousemoved(x,y, dx,dy)
    g3d.camera.firstPersonLook(dx,dy);
end
Untitled.png
Untitled.png (20.06 KiB) Viewed 11932 times

vico wrote: Mon Feb 06, 2023 2:23 am (still dont understand much what each part of the vert table represents)
I threw this together in paint, maybe it will help you understand how the models are built. :)
Verts.png
Verts.png (24.43 KiB) Viewed 11932 times

Re: Groverburger's 3D Engine (g3d) v1.5.2 Release

Posted: Tue Feb 07, 2023 3:03 am
by vico
Hydrogen Maniac wrote: Mon Feb 06, 2023 8:34 pm I threw this together in paint, maybe it will help you understand how the models are built. :)
Verts.png
Thank you so much for this explanation. It really helped me to visualize how it works.

I just have another question: how could i store the model in a text-based format like json? I really dont want to use .obj because i want to allow easy editing of the models (maybe for future modding purposes).
I tried to export a simple cube in JSON model in Blockbench and it spilled the following code:

Code: Select all

{
	"credit": "Made with Blockbench",
	"elements": [
		{
			"from": [1, 1, 1],
			"to": [2, 2, 2],
			"color": 5,
			"faces": {
				"north": {"uv": [0, 0, 1, 1], "texture": "#missing"},
				"east": {"uv": [0, 0, 1, 1], "texture": "#missing"},
				"south": {"uv": [0, 0, 1, 1], "texture": "#missing"},
				"west": {"uv": [0, 0, 1, 1], "texture": "#missing"},
				"up": {"uv": [0, 0, 1, 1], "texture": "#missing"},
				"down": {"uv": [0, 0, 1, 1], "texture": "#missing"}
			}
		}
	]
}
Is that information enough to render a cube in g3d? Or i need to use another standard or make one from scratch?