Mesh Instancing Inside a 3d Shader

Questions about the LÖVE API, installing LÖVE and other support related questions go here.
Forum rules
Before you make a thread asking for help, read this.
Post Reply
User avatar
kicknbritt
Citizen
Posts: 96
Joined: Sat May 30, 2015 2:15 am
Location: Chicago, IL/Anchorage,AK

Mesh Instancing Inside a 3d Shader

Post by kicknbritt »

Hello Guys. So I am still working on a minecraft engine and I am still having crazy memory issues. There is for sure a memory leak in love.graphics.newMesh. I don't really know who to talk to about that so I am going to switch to using instancing to just render the block faces. Does anyone know how to do this with 3d objects?

I checked out the tutorial on https://love2d.org/wiki/love.graphics.drawInstanced but It seems that it only takes an x and y coordinate when I need to instance in 3d.

Also the shader I am using is using a transformation matrix and stuff so I am not sure how I can instance a mesh inside a shader like that.

Code: Select all

    SS3D.Scene.threeShader = love.graphics.newShader[[
        uniform mat4 view;
        uniform mat4 model_matrix;
        uniform mat4 model_matrix_inverse;
        uniform float ambientLight;
        uniform vec3 ambientVector;

        varying mat4 modelView;
        varying mat4 modelViewProjection;
        varying vec3 normal;
        varying vec3 vposition;

        #ifdef VERTEX
            attribute vec4 VertexNormal;

            vec4 position(mat4 transform_projection, vec4 vertex_position) {
                modelView = view * model_matrix;
                modelViewProjection = view * model_matrix * transform_projection;

                normal = vec3(model_matrix_inverse * vec4(VertexNormal));
                vposition = vec3(model_matrix * vertex_position);

                return view * model_matrix * vertex_position;
            }
        #endif

        #ifdef PIXEL
            vec4 effect(vec4 color, Image texture, vec2 texture_coords, vec2 screen_coords) {
                vec4 texturecolor = Texel(texture, texture_coords);

                // if the alpha here is zero just don't draw anything here
                // otherwise alpha values of zero will render as black pixels
                if (texturecolor.a == 0.0)
                {
                    discard;
                }

                float light = max(dot(normalize(ambientVector), normal), 0.0);
                texturecolor.rgb *= max(light, ambientLight);

                return color*texturecolor;
            }
        #endif
    ]]
"I AM THE ARBITER!!!" *Pulls out Energy sword and kills everything*
nameless tee
Prole
Posts: 15
Joined: Mon Apr 22, 2019 8:16 am

Re: Mesh Instancing Inside a 3d Shader

Post by nameless tee »

I tried just writing a reply, but describing it in English seems harder to me than actually doing it, so instead I modified the example in the wiki to render in 3D and explained the changes with comments.

Code: Select all

-- I've changed the size of the triangle to 1/8 so I don't need
-- to scale it down in the 3D shader
local vertices = {
	{0, 0,  0,0, 1.0,0.2,0.2,1.0},
	{1/8,0,  0,0, 0.2,1.0,0.2,1.0},
	{1/8,1/8, 0,0, 0.2,0.2,1.0,1.0},
}
 
local mesh = love.graphics.newMesh(vertices, "triangles", "static")

-- It's still named "instancepositions" but now it will contain
-- a 3D-Position instead of a 2D one and it will also contain an
-- additional attribute for rotation, which I added to demonstrate
-- that it is possible to have multiple per-instance attributes.
-- You will probably end up needing multiple attributes because
-- you want the faces of your cubes to have both position and orientation.
local instancepositions = {}
for y=-8,8 do
	for x = -8,8 do
		local pos = {
			-- Position. I added a random z coordinate and changed the scale
			x/8, y/8, math.random()*2-1,
			-- Random rotation
			math.random()*math.pi*2
		}
		table.insert(instancepositions, pos)
	end
end

-- The instancemesh must also know about the additional attribute.
-- Note that I changed "InstancePosition" to just "InstancePos",
-- to demonstrate that there isn't anything special about the names
-- of these attributes. You can give them almost any name you like.
local instancemesh = love.graphics.newMesh(
	{
		{"InstancePos", "float", 3},
		{"InstanceRot", "float", 1},
	},
	instancepositions, nil, "static"
)

-- Now we attach both attributes to the mesh
mesh:attachAttribute("InstancePos", instancemesh, "perinstance")
mesh:attachAttribute("InstanceRot", instancemesh, "perinstance")


local shader = love.graphics.newShader[[
// I want to make stuff move to emphasize the 3D-ish-ness of the thing,
// so I need time.
uniform float time;

attribute vec3 InstancePos;
attribute float InstanceRot;

// Projection matrix, probably not really relevant to your problem.
const mat4 proj = mat4(
	1., 0., 0., 0.,
	0., 1., 0., 0.,
	0., 0., 1., .5,
	0., 0., 0., 2.5
);

vec4 position(mat4 transform_projection, vec4 vertex_position)
{
	// This rotation matrix handles the rotation of individual instances
	mat3 iRot = mat3(
		cos(InstanceRot), 0., sin(InstanceRot),
		0., 1., 0.,
		-sin(InstanceRot), 0., cos(InstanceRot)
	);
	
	
	// I use this rotation matrix to make all instances rotate together.
	// It's not really relevant to your problem, but I wanted to have
	// this in here so I can visually check if everything is where
	// it should be in 3D.
	mat3 rot = mat3(
		cos(time), 0., sin(time),
		0., 1., 0.,
		-sin(time), 0., cos(time)
	);
	
	// Rotate the individual instance on the spot.
	vertex_position.xyz = iRot*vertex_position.xyz+InstancePos;
	
	// Apply the large-scale rotation, too. You can ignore this.
	vertex_position.xyz = rot*vertex_position.xyz;
	
	// Apply the projection matrix to give it perspective.
	return proj*vertex_position;
}
]]
 
function love.draw()
	-- Add depth test, so triangles at the front don't get drawn in the
	-- background
	love.graphics.setDepthMode("lequal", true)
	
	love.graphics.setShader(shader)
	
	-- Send time to the shader. Will be used to rotate everything.
	shader:send("time", love.timer.getTime())
	
	local instancecount = #instancepositions
	love.graphics.drawInstanced(mesh, instancecount, 0, 0)
end

Image
Attachments
3DInstancing.love
(1.48 KiB) Downloaded 129 times
User avatar
Varkas
Citizen
Posts: 83
Joined: Mon Mar 09, 2020 2:26 pm

Re: Mesh Instancing Inside a 3d Shader

Post by Varkas »

Very nice!
In soviet russia, code debugs you.
User avatar
kicknbritt
Citizen
Posts: 96
Joined: Sat May 30, 2015 2:15 am
Location: Chicago, IL/Anchorage,AK

Re: Mesh Instancing Inside a 3d Shader

Post by kicknbritt »

Dude! You are a life saver thank you! Also much appreciated on all the code descriptions and notes. Very helpful. I will be working through all this today thanks a bunch!
"I AM THE ARBITER!!!" *Pulls out Energy sword and kills everything*
Post Reply

Who is online

Users browsing this forum: Bing [Bot], Google [Bot] and 73 guests