Jump to content

Software Rendering in MTA:SA Lua


The_GTA

Recommended Posts

3 hours ago, Haxardous said:

Imagine what i can do with this, good job!

Hello Haxardous!

Thank you for complimenting me. I spent a lot of work into it and just want people to have a good starting foundation. Later the performance of the implementation will be improved by choosing better data structures as well as faster algorithms (already have plans).

As a side note, I was heavily inspired by Direct3D 9's frustum definition when setting out my math formulas. So if you read their documentation you will find many parallels. Pretty sure this definition is industry standard.

Edited by The_GTA
  • Like 1
Link to comment
  • 2 weeks later...

After spending some time bugfixing and optimizing the implementation, the performance has been improved. It still is not as fast as a hardware GPU but you should understand why ;) 

To celebrate the improvements I want to show you guys how to check with 100% accuracy whether a triangle is on the screen. We basically use the same code we do for the rendering but skip the rasterization part. Take a look at this code (test_client.Lua clientside file at the end of meta.xml):

local triangle = createPlane(
    createVector(0, 0, 5),
    createVector(25, 0, 0),
    createVector(0, 0, 15)
);

local frustum_pos = createVector(0, 0, 0);
local frustum_right = createVector(0, 0, 0);
local frustum_up = createVector(0, 0, 0);
local frustum_front = createVector(0, 0, 0);

local frustum = createViewFrustum(
    frustum_pos,
    frustum_right,
    frustum_up,
    frustum_front
);

local function set_frustum_from_camera()
    local camMat = getElementMatrix(getCamera());
    local camPos = camMat[4];
    local camRight = camMat[1];
    local camFront = camMat[2];
    local camUp = camMat[3];
    local farClip = getFarClipDistance();
    
    local cam_frontX = camFront[1] * farClip;
    local cam_frontY = camFront[2] * farClip;
    local cam_frontZ = camFront[3] * farClip;
    
    local sW, sH = guiGetScreenSize();
    
    local s_ratio = sW / sH;
    
    local _, _, _, _, _, _, _, fov = getCameraMatrix();
    local fovRad = math.rad(fov/2);

    local cam_side_dist = farClip * math.tan(fovRad);
    local cam_up_dist = cam_side_dist / s_ratio;

    local cam_rightX = camRight[1] * cam_side_dist;
    local cam_rightY = camRight[2] * cam_side_dist;
    local cam_rightZ = camRight[3] * cam_side_dist;
    
    local cam_upX = camUp[1] * cam_up_dist;
    local cam_upY = camUp[2] * cam_up_dist;
    local cam_upZ = camUp[3] * cam_up_dist;
    
    frustum_pos.setX(camPos[1]);
    frustum_pos.setY(camPos[2]);
    frustum_pos.setZ(camPos[3]);
    
    frustum_right.setX(cam_rightX);
    frustum_right.setY(cam_rightY);
    frustum_right.setZ(cam_rightZ);
    
    frustum_up.setX(cam_upX);
    frustum_up.setY(cam_upY);
    frustum_up.setZ(cam_upZ);
    
    frustum_front.setX(cam_frontX);
    frustum_front.setY(cam_frontY);
    frustum_front.setZ(cam_frontZ);
end

addEventHandler("onClientRender", root,
    function()
        local triPos = triangle.getPos();
        local triU = triangle.getU();
        local triV = triangle.getV();
        
        local vert1 = {
            triPos.getX(),
            triPos.getY(),
            triPos.getZ(),
            tocolor(255, 255, 255)
        };
        
        local vert2 = {
            triPos.getX() + triU.getX(),
            triPos.getY() + triU.getY(),
            triPos.getZ() + triU.getZ(),
            tocolor(255, 255, 255)
        };
        
        local vert3 = {
            triPos.getX() + triV.getX(),
            triPos.getY() + triV.getY(),
            triPos.getZ() + triV.getZ(),
            tocolor(255, 255, 255)
        };
        
        dxDrawPrimitive3D("trianglelist", false, vert1, vert2, vert3);
        
        -- Check whether the triangle is on screen.
        set_frustum_from_camera(frustum);
        
        local inter = frustum.intersectWithTrianglePlane(triangle);
    
        dxDrawText("is intersecting: " .. tostring(not (inter == false)), 100, 300);
    end
);

The function "set_frustum_from_camera" does apply the GTA:SA camera metrics onto our frustum object, thus accurately representing the game camera. The triangle object is located at the center of the GTA:SA map (the farming area). If you teleport there and start the resource you will see a white triangle as well as the text: "is intersecting: true". If you move the camera away from the triangle then the text will change to "is intersecting: false". Thus it is checking whether the triangle is visible through the game camera.

RmYqJuV.png

The script is pretty slow at the moment so the framerate does stutter (Lua is to be partially blamed). But I have plans to improve the performance even futher, so please follow this thread :)

Edited by The_GTA
  • Like 1
Link to comment
  • 1 year later...

The_GTA This resource is beyond impressive. I found this topic just a week ago, immediately threw every other thing to study it.
I'm particularly focused right no on using rw_shared.lua to read model data.
This is a current result I've got with the standard model provided in the resource archive drawn using primitiveMaterial3D

spacer.png

The problems started when i decided to load some different models.
The ones provided with the resource load with no issues, however Any other model (including original ones from gta3.img) fail to load.
The same thing happens with clean math_3d_nonlin after typing draw_model (have replaced gf model with skyscr01_lawn.dff from original game)

the err string for this particular file is:
failed to read geometrylist: failed to read geometry #1: failed to read morph target vertex translation
The script iterates through numVertices (a value much higher than an actual number) until this exception occurs
the values from start to end don't make much sense...

x 5.8774857670961e-39 y 5.8774997800807e-39 z 1.7060598161754e-24
x 5.8774724547607e-39 y 5.8774829644992e-39 z 1.7060598161754e-24
x 0 y 0 z 5.8774752573576e-39
 

Edited by Ren_712
  • Like 1
Link to comment
2 hours ago, Ren_712 said:

The_GTA This resource is beyond impressive. I found this topic just a week ago, immediately threw every other thing to study it.
I'm particularly focused right no on using rw_shared.lua to read model data.

(...)

The problems started when i decided to load some different models.
The ones provided with the resource load with no issues, however Any other model (including original ones from gta3.img) fail to load.
The same thing happens with clean math_3d_nonlin after typing draw_model (have replaced gf model with skyscr01_lawn.dff from original game)

the err string for this particular file is:
failed to read geometrylist: failed to read geometry #1: failed to read morph target vertex translation
The script iterates through numVertices (a value much higher than an actual number) until this exception occurs
the values from start to end don't make much sense...
 

Thank you very much for your valuable feedback!

Based on the example DFF file that you have provided me (skyscr01_lawn.dff) I was able to detect an issue in the geometry chunk vertex-prelighting color reading. Instead of reading the color channels as uint8/byte, I was reading them as float xD ?‍♂️ About 20 minutes ago I have pushed a new commit to the GitHub repository which can now load the mentioned DFF file. If you find any further bugs then please post again, I will evaluate whether I want to support the DFF file and then fix any bugs.

I am very interested in the MTA-backed DFF renderer that you have created. It seems like a fun project and I like it.

Link to comment
5 minutes ago, Ren_712 said:

Man, that was fast ? I also noticed that textureInfo.texName string has a last NULL character, and probably others in rwReadTextureInfo but not sure. Will test tomorrow.

OK. I forgot to subtract a zero there, should trim off the trailing '\0' now.

  • Like 1
Link to comment
1 hour ago, Ren_712 said:

This will do great for alpha objects and allow perfect control of the rendering order. Thank You so much for fixing the parser.

You're welcome! Happy to be part of your vision. Not so sure about your alpha fix claims because I happen to be deeply into this research topic of per-pixel rendering order but it sure does help a little, maybe enough to fit your cause ? Replacing the internal GTA:SA rendering calls with MTA versions sounds fun, I hope you achieve great new creative control over MTA server content this way!

  • Like 1
Link to comment
  • 4 months later...

This job is just great! That way of applying science gives outstanding results, still wondering why do I find such interesting topics in years! 

Among other things I'm focused at the parser as Ren_712 did. The only problem found, it doesn't 'accept' larger DFFs from about 5-10 MB breaking with 'infinite running script'. 

But that is 'too little things' in front of the research made on RW and maths applied. Wish you all the best on the way of your interest! 

Link to comment
4 hours ago, maximumdrive said:

This job is just great! That way of applying science gives outstanding results, still wondering why do I find such interesting topics in years! 

Among other things I'm focused at the parser as Ren_712 did. The only problem found, it doesn't 'accept' larger DFFs from about 5-10 MB breaking with 'infinite running script'. 

But that is 'too little things' in front of the research made on RW and maths applied. Wish you all the best on the way of your interest! 

Glad to hear that you like it! In order to stop the "infinite running script" error, there is this little-known secret to use "debug.sethook(nil)" to allow unbounded execution. Use it wisely because if there really is an infinite loop then you cannot properly terminate it anymore (game hangs, server hangs, data loss, etc).

Link to comment
  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...