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

Showcase your libraries, tools and other projects that help your fellow love users.
User avatar
Bigfoot71
Party member
Posts: 287
Joined: Fri Mar 11, 2022 11:07 am

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

Post by Bigfoot71 »

vico wrote: Tue Feb 07, 2023 3:03 am
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?
For that you can use the JSON library for Lua, I made you a script that will be able to load your, however not having correct UV nor normalized coordinates in your example my script is incomplete and maybe it will not work well with texutre, if you can send me a more complete example I could improve it and correct it if necessary.

Code: Select all

-- written by Le Juez Victor to load Minecraft cube models in JSON format
-- February 2023
-- MIT license

local json = require("json")

local createVertex = function (pos,uv)
    local x,y,z = unpack(pos)
    local u,v = unpack(uv)
    return {x,y,z,u,v}
end

return function (path)
    local result = {}

    -- load the file
    local contents, size = love.filesystem.read(path)
    if contents == nil then
        error("Failed to load file: " .. path)
    end

    -- parse the json data
    local data = json.decode(contents)

    for i, element in ipairs(data.elements) do

        -- extract the vertex positions
        local from = element.from
        local to = element.to
        local positions = {
            {from[1], from[2], from[3]},        -- front-bottom-left
            {to[1], from[2], from[3]},          -- front-bottom-right
            {to[1], to[2], from[3]},            -- front-top-right
            {from[1], to[2], from[3]},          -- front-top-left
            {from[1], from[2], to[3]},          -- back-bottom-left
            {to[1], from[2], to[3]},            -- back-bottom-right
            {to[1], to[2], to[3]},              -- back-top-right
            {from[1], to[2], to[3]},            -- back-top-left
        }

        -- extract the UV coordinates
        local uvs = {
            {element.faces.north.uv[1], element.faces.north.uv[2]},   -- front-bottom-left
            {element.faces.north.uv[3], element.faces.north.uv[2]},   -- front-bottom-right
            {element.faces.north.uv[3], element.faces.north.uv[4]},   -- front-top-right
            {element.faces.north.uv[1], element.faces.north.uv[4]},   -- front-top-left
            {element.faces.south.uv[3], element.faces.south.uv[2]},   -- back-bottom-right
            {element.faces.south.uv[1], element.faces.south.uv[2]},   -- back-bottom-left
            {element.faces.south.uv[1], element.faces.south.uv[4]},   -- back-top-left
            {element.faces.south.uv[3], element.faces.south.uv[4]},   -- back-top-right
        }

        -- triangulate each face
        for face, faceData in pairs(element.faces) do
            if face == "north" then
                -- front face
                table.insert(result, createVertex(positions[1],uvs[1]))
                table.insert(result, createVertex(positions[2],uvs[2]))
                table.insert(result, createVertex(positions[3],uvs[3]))
                table.insert(result, createVertex(positions[3],uvs[3]))
                table.insert(result, createVertex(positions[4],uvs[4]))
                table.insert(result, createVertex(positions[1],uvs[1]))
            elseif face == "east" then
                -- right face
                table.insert(result, createVertex(positions[2],uvs[2]))
                table.insert(result, createVertex(positions[6],uvs[6]))
                table.insert(result, createVertex(positions[7],uvs[7]))
                table.insert(result, createVertex(positions[7],uvs[7]))
                table.insert(result, createVertex(positions[3],uvs[3]))
                table.insert(result, createVertex(positions[2],uvs[2]))
            elseif face == "south" then
                -- back face
                table.insert(result, createVertex(positions[6],uvs[6]))
                table.insert(result, createVertex(positions[5],uvs[5]))
                table.insert(result, createVertex(positions[8],uvs[8]))
                table.insert(result, createVertex(positions[8],uvs[8]))
                table.insert(result, createVertex(positions[7],uvs[7]))
                table.insert(result, createVertex(positions[6],uvs[6]))
            elseif face == "west" then
                -- left face
                table.insert(result, createVertex(positions[5],uvs[5]))
                table.insert(result, createVertex(positions[1],uvs[1]))
                table.insert(result, createVertex(positions[4],uvs[4]))
                table.insert(result, createVertex(positions[4],uvs[4]))
                table.insert(result, createVertex(positions[8],uvs[8]))
                table.insert(result, createVertex(positions[5],uvs[5]))
            elseif face == "up" then
                -- top face
                table.insert(result, createVertex(positions[4],uvs[4]))
                table.insert(result, createVertex(positions[3],uvs[3]))
                table.insert(result, createVertex(positions[7],uvs[7]))
                table.insert(result, createVertex(positions[7],uvs[7]))
                table.insert(result, createVertex(positions[8],uvs[8]))
                table.insert(result, createVertex(positions[4],uvs[4]))
            elseif face == "down" then
                -- bottom face
                table.insert(result, createVertex(positions[5],uvs[5]))
                table.insert(result, createVertex(positions[6],uvs[6]))
                table.insert(result, createVertex(positions[2],uvs[2]))
                table.insert(result, createVertex(positions[2],uvs[2]))
                table.insert(result, createVertex(positions[1],uvs[1]))
                table.insert(result, createVertex(positions[5],uvs[5]))
            end
        end
    end

    return result
end
I made a repository on GitHub, I also leave you a .love archive if you want to try it directly.
Hydrogen Maniac wrote: Mon Feb 06, 2023 8:34 pm 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.
Otherwise, this problem is really strange, I don't have it either on Löve 11.3 on PC or 11.4 on Android, could it come from a badly configured parameter in Löve as well as graphics cards?
Attachments
mc-block-json-loader-g3d.love
(17.59 KiB) Downloaded 136 times
My avatar code for the curious :D V1, V2, V3.
User avatar
slime
Solid Snayke
Posts: 3129
Joined: Mon Aug 23, 2010 6:45 am
Location: Nova Scotia, Canada
Contact:

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

Post by slime »

If you want to use a depth buffer with the main screen, you need to set it up in love.conf (or love.window.setMode) - just setting t.window.depth = 24 should do it, but I haven't seen that being done in the g3d code I've looked at.
User avatar
Bigfoot71
Party member
Posts: 287
Joined: Fri Mar 11, 2022 11:07 am

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

Post by Bigfoot71 »

slime wrote: Tue Feb 07, 2023 8:25 pm If you want to use a depth buffer with the main screen, you need to set it up in love.conf (or love.window.setMode) - just setting t.window.depth = 24 should do it, but I haven't seen that being done in the g3d code I've looked at.
I thought about it too but personally I don't need to mention it in love.conf or love.window.setMode (nor on my Android devices for that matter), whereas according to the docs it's on nil by default (unless there is an error/inaccuracy), it would come not the graphics card? I say this in relation to this post from Groverburger: viewtopic.php?p=238067#p238067
My avatar code for the curious :D V1, V2, V3.
User avatar
Hydrogen Maniac
Citizen
Posts: 79
Joined: Sat Dec 19, 2015 9:59 pm

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

Post by Hydrogen Maniac »

slime wrote: Tue Feb 07, 2023 8:25 pm If you want to use a depth buffer with the main screen, you need to set it up in love.conf (or love.window.setMode) - just setting t.window.depth = 24 should do it, but I haven't seen that being done in the g3d code I've looked at.
I can confirm that adding

Code: Select all

t.window.depth = 24
to the conf file or calling

Code: Select all

love.window.setMode(love.graphics.getWidth(),love.graphics.getHeight(),{depth=24})
fixes the issue on my end :). Adding this to g3d seems like a no brainer to me.
I'm way too sober for this...
User avatar
slime
Solid Snayke
Posts: 3129
Joined: Mon Aug 23, 2010 6:45 am
Location: Nova Scotia, Canada
Contact:

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

Post by slime »

Bigfoot71 wrote: Tue Feb 07, 2023 9:24 pm I thought about it too but personally I don't need to mention it in love.conf or love.window.setMode (nor on my Android devices for that matter), whereas according to the docs it's on nil by default (unless there is an error/inaccuracy), it would come not the graphics card? I say this in relation to this post from Groverburger: viewtopic.php?p=238067#p238067
Some graphics drivers unhelpfully provide a depth buffer for the backbuffer even when it's not requested, if a stencil buffer is also present (which it is by default in love).

For love 12 I'll probably try to make things more consistent and obvious by causing Lua errors in more situations when depth testing/writes are used without having requested a depth buffer, or something.
Rigachupe
Citizen
Posts: 83
Joined: Fri Jun 18, 2021 11:21 am

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

Post by Rigachupe »

Found some bug with the g3d/shader.lua causing error on a android mobile device. I will not put it on github because it seems the version presented there is very outdated.

The problem is on line 13. Change
from : vec4 texcolor = Texel(tex, vec2(texcoord.x, 1-texcoord.y));
to : vec4 texcolor = Texel(tex, vec2(texcoord.x, 1.0-texcoord.y));

And it will work. Just a type mismatch that works on desktop windows but fails on android. Well, that's it! Have a nice day.
User avatar
zorg
Party member
Posts: 3435
Joined: Thu Dec 13, 2012 2:55 pm
Location: Absurdistan, Hungary
Contact:

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

Post by zorg »

Rigachupe wrote: Thu Feb 16, 2023 3:07 pm Found some bug with the g3d/shader.lua causing error on a android mobile device. I will not put it on github because it seems the version presented there is very outdated.
What do you mean the github version is outdated? That's the official library; where did you find a more "up-to-date" version?
Me and my stuff :3True Neutral Aspirant. Why, yes, i do indeed enjoy sarcastically correcting others when they make the most blatant of spelling mistakes. No bullying or trolling the innocent tho.
Rigachupe
Citizen
Posts: 83
Joined: Fri Jun 18, 2021 11:21 am

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

Post by Rigachupe »

When i look here in this topic i see the g3d-fps test project has more changes that what is on the github.
User avatar
Jasoco
Inner party member
Posts: 3725
Joined: Mon Jun 22, 2009 9:35 am
Location: Pennsylvania, USA
Contact:

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

Post by Jasoco »

Hydrogen Maniac wrote: Wed Feb 01, 2023 9:43 pm 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.
Yeah I've looked at Hoarder's House. It's impressive but I haven't really looked into it enough. It was difficult enough for me to do point lights. I copied that method from Flamerunner. But I stripped out some code to speed it up. Now I just want to figure out how to do spotlights. The thing is the point lights don't get stopped by walls. So I have to be creative with them. I wouldn't mind using spotlights for hanging lamps or a flashlight though. I've Googled and found code and stuff but can't really understand it. Not as simple as spherical point lights. The lighting from the lava and slime is basically just a bunch of point lights with a reddish glow. However the lighting from the sky is baked into a separate texture I use for doing lighting for rooms. It's not perfect, but it works if I work around it and know my limitations.

The hardest part is creating the editor. But it's basically just a simple Wolfenstein style editor. And I keep it simple by only having two floor and ceiling heights. (Might add some halfway settings eventually) Aside from pits and open sky of course.

Actually I guess the hardest part is enemy AI and Bump isnt really the most perfect collision system for 3D. Even if collisions are mostly 2D anyway. I basically use a DOOM style collision system with different height floors. For instance, I have stair objects that are just 4 separate blocks at different heights that you can walk up and down. Works great.

I also keep memory low by merging the floors and ceilings into single planes. But I want to do more optimization and merge walls too. Right now all the walls and ceilings and floors are printed onto large canvases. A lot of wasted space, but it works. Also lets me draw directly onto a surface for blood or bullet holes. Canvas memory isn't an issue. It's really just the memory used by the large tables full of triangles that are used for the meshes. Which is why I like optimizing and cutting down on triangles when I can. The less I use for the level geometry, the more I can use for other details.
vico wrote: Mon Feb 06, 2023 2:16 am Much amazing! Care to share your googlings?

EDIT: sorry the double post, thought the forum had post auto-merge feature enabled.
Depends on what you're trying to do. Just Google what you want to do but remember to add GLSL or shader to the search. Not all code will work though. But you can figure things out if you think deep about it. A lot of it was also looking at the code for all the projects featured in this thread.
User avatar
Hydrogen Maniac
Citizen
Posts: 79
Joined: Sat Dec 19, 2015 9:59 pm

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

Post by Hydrogen Maniac »

Jasoco wrote: Sun Feb 19, 2023 12:35 am Now I just want to figure out how to do spotlights. The thing is the point lights don't get stopped by walls. So I have to be creative with them. I wouldn't mind using spotlights for hanging lamps or a flashlight though. I've Googled and found code and stuff but can't really understand it. Not as simple as spherical point lights.
I'm not sure what most glsl tutorials will recommend but a quick and dirty solution I've used for a while is to just take the point light code and multiply the falloff by the dot product of the spotlight's direction and the direction from the light source to the fragment like so:

Code: Select all

falloff *= max(0, dot(normalize(fragPosition-light.position), light.direction));
This will work but it will also look a little off since it will illuminate in a 180° cone and the light will fade linearly towards the outer edges of the cone which looks pretty unnatural. Thankfully this is easily fixed, the former by subtracting from the dot product and the latter by raising the entire expression by a power. Since we're subtracting the cone width from the dot product we have to divide the dot product by the cone width to make sure the light doesn't dim when the spotlight gets narrower.

Code: Select all

float coneWidth = 0.5;
float fadeExponent = 3;
falloff *= pow(max(0, dot(normalize(fragPosition-light.position), light.direction)-(1-coneWidth))/coneWidth, fadeExponent);
This solution isn't perfect but I think it will work quite well for most projects. I hope this was understandable, I sometimes get myself confused when writing shaders :crazy: .
I'm way too sober for this...
Post Reply

Who is online

Users browsing this forum: Ahrefs [Bot] and 23 guests