smcameron / space-nerds-in-space

Multi-player spaceship bridge simulator game. Captain your starship through adventures with your friends. See https://smcameron.github.io/space-nerds-in-space
GNU General Public License v2.0
728 stars 73 forks source link

Texture the turret #251

Open MCMic opened 4 years ago

MCMic commented 4 years ago

This is something which I think really gives the game an «unfinished» feeling, because the turret is rendered on the weapons screen at all time and it looks like a bug that it’s not textured.

Maybe a simple material texture applied on the whole object would be enough for an improvement. I remember at some point I compiled links to candidate textures from OGA but I can’t find the issue/message.

smcameron commented 4 years ago

It needs uv unwrapping.

On Sun, Feb 23, 2020, 1:10 PM MCMic notifications@github.com wrote:

This is something which I think really gives the game an «unfinished» feeling, because the turret is rendered on the weapons screen at all time and it looks like a bug that it’s not textured.

Maybe a simple material texture applied on the whole object would be enough for an improvement. I remember at some point I compiled links to candidate textures from OGA but I can’t find the issue/message.

— You are receiving this because you are subscribed to this thread. Reply to this email directly, view it on GitHub https://github.com/smcameron/space-nerds-in-space/issues/251?email_source=notifications&email_token=AAAF22FBH33BRSMMEWRK4UTREK3YLA5CNFSM4KZ4UR22YY3PNVWWK3TUL52HS4DFUVEXG43VMWVGG33NNVSW45C7NFSM4IPSNABQ, or unsubscribe https://github.com/notifications/unsubscribe-auth/AAAF22AGCXF3A7AT7JYWCZDREK3YLANCNFSM4KZ4UR2Q .

MCMic commented 4 years ago

@smcameron Is it laser_turret or spaceship_turret? I think I did the wrong one…

MCMic commented 4 years ago

Screenshot_20200223_222640

Not sure it’s much better xD

The low-polly is actually bugging me now. The reaction to light is all wrong (but I did use random values for reflexions and stuff, so it’s expected).

Also, you can see in the bottom left corner the model is hitting the camera, is it like that already or is it a result of my tests? I had to rotate the model in blender after importing so maybe it’s upside down, if there is an up and a down to this thing?

smcameron commented 4 years ago

Bottom left is hitting the camera, probably it's the near clipping plane. There is a trade-off with the near-clipping plane distance and depth buffer precision. You can't have the near clipping plane be too close to the camera without sacrificing precision in the depth buffer at greater distances, so it's a compromise. There are some mitigation strategies, one of which we're using, which is to use two pass rendering with two depth buffers, one for nearby objects and one for far objects. Another way is logarithmic depth buffers, but this is likely a fairly difficult change. Anyway, it's likely the near clipping plane, it's the 2nd param of camera_set_parameters(), currently the value is NEAR_CAMERA_PLANE 1.666. You could experiment with that, but I think you cannot have a near-clipping plane distance of zero, and you might find z-fighting occurring at greater distances if you reduce it too much. You could make it tweakable.

The model is in openscad, you can open it in that, then it looks like this:

spaceship-turret

You can change the openscad file like this:

diff --git a/share/snis/models/spaceship_turret.scad b/share/snis/models/spaceship_turret.scad
index 316b164..26eac2c 100644
--- a/share/snis/models/spaceship_turret.scad
+++ b/share/snis/models/spaceship_turret.scad
@@ -1,20 +1,22 @@

+f_n=64;
+
 module gunbarrel()
 {
        translate([0,0,2]) {
                translate([0,0,-2.5])
-                       cylinder(0.5,0.25,0.25,center=true,$fn=20);
-               cylinder(4.5,0.25,0.13,center=true,$fn=20);
+                       cylinder(0.5,0.25,0.25,center=true,$fn=f_n);
+               cylinder(4.5,0.25,0.13,center=true,$fn=f_n);
                translate(v = [0, 0, 2.4])
-                       cylinder(1.0,0.20,0.20,center=true,$fn=20);
+                       cylinder(1.0,0.20,0.20,center=true,$fn=f_n);
        }
 }

 module mount()
 {
        translate([0,0,0.25])
-               cylinder(1,0.3,0.75,$fn=20);
-       sphere(0.4,center=true,$fn=20);
+               cylinder(1,0.3,0.75,$fn=f_n);
+       sphere(0.4,center=true,$fn=f_n);
 }

 union() {
@@ -30,5 +32,5 @@ union() {
                        mount();
        }

-       cylinder(1.5,0.8,0.8,center=true,$fn=20);
+       cylinder(1.5,0.8,0.8,center=true,$fn=f_n);
 }

And that will get you a higher poly model (increasing the value of f_n will get you still higher poly):

spaceship_turret2

As for the lighting, I dunno. I think normal mapping some detail greebles of some sort would be the most bang for the buck as opposed to a texture (which is just a paint job), but creating a good normal map is hard. I made a greeble normal map maker thing, but the normal maps it makes aren't especially good nor are they made specifically for particular objects: https://github.com/smcameron/groovygreebler

As always, the reason there are plain models in this game is that creating uv-unwraps, texture art and normal maps is hard to do well. Plus it eats memory of course.

smcameron commented 4 years ago

You could potentially widen the distance between the gun barrels a little bit to push them off the edges of the screen and fix the near-z-plane clipping....

This might do:

diff --git a/share/snis/models/spaceship_turret.scad b/share/snis/models/spaceship_turret.scad
index 316b164..daceca2 100644
--- a/share/snis/models/spaceship_turret.scad
+++ b/share/snis/models/spaceship_turret.scad
@@ -18,12 +18,12 @@ module mount()
 }

 union() {
-       translate([0,0,-1.4]) {
+       translate([0,0,-1.5]) {
                rotate([0,90,0])
                        gunbarrel();
                mount();
        }
-       translate([0,0,1.4]) {
+       translate([0,0,1.5]) {
                rotate([0,90,0])
                        gunbarrel();
                rotate([180,0,0])
diff --git a/snis_server.c b/snis_server.c
index 04fcb5b..bc748a0 100644
--- a/snis_server.c
+++ b/snis_server.c
@@ -9820,8 +9820,8 @@ default_move:

 static void turret_fire(struct snis_entity *o)
 {
-       union vec3 pos_right = { { 40.0, 0.0, 20.0 } };
-       union vec3 pos_left = { { 40.0, 0.0, -20.0 } };
+       union vec3 pos_right = { { 40.0, 0.0, 21.42 } };
+       union vec3 pos_left = { { 40.0, 0.0, -21.42 } };
        union vec3 vel = { { 1.0, 0.0, 0.0 } };

        quat_rot_vec_self(&vel, &o->orientation);

The change to snis_server is to change where the laser bolts appear to make them match the new positions of the gun barrels.

smcameron commented 4 years ago

Eh, I don't think that patch is right, turret_fire() is not for the player ship turret, it's for the turrets in DEMOLISHER.LUA

smcameron commented 4 years ago

Should be like this:

diff --git a/share/snis/models/spaceship_turret.scad b/share/snis/models/spaceship_turret.scad
index 316b164..daceca2 100644
--- a/share/snis/models/spaceship_turret.scad
+++ b/share/snis/models/spaceship_turret.scad
@@ -18,12 +18,12 @@ module mount()
 }

 union() {
-       translate([0,0,-1.4]) {
+       translate([0,0,-1.5]) {
                rotate([0,90,0])
                        gunbarrel();
                mount();
        }
-       translate([0,0,1.4]) {
+       translate([0,0,1.5]) {
                rotate([0,90,0])
                        gunbarrel();
                rotate([180,0,0])
diff --git a/snis_server.c b/snis_server.c
index 04fcb5b..dcb23c3 100644
--- a/snis_server.c
+++ b/snis_server.c
@@ -21509,8 +21509,8 @@ static int process_request_manual_laser(struct game_client *c)
        struct snis_entity *ship = &go[c->ship_index];
        union vec3 forwardvec = { { LASER_VELOCITY, 0.0f, 0.0f } };
        union vec3 turret_pos = { { -4.0f * SHIP_MESH_SCALE, 5.45 * SHIP_MESH_SCALE, 0.0f } };
-       union vec3 barrel_r_offset = { { 4.0f * SHIP_MESH_SCALE, 0.0f, 1.4f * SHIP_MESH_SCALE } };
-       union vec3 barrel_l_offset = { { 4.0f * SHIP_MESH_SCALE, 0.0f, -1.4f * SHIP_MESH_SCALE } };
+       union vec3 barrel_r_offset = { { 4.0f * SHIP_MESH_SCALE, 0.0f, 1.5f * SHIP_MESH_SCALE } };
+       union vec3 barrel_l_offset = { { 4.0f * SHIP_MESH_SCALE, 0.0f, -1.5f * SHIP_MESH_SCALE } };
        union vec3 velocity;
        union quat orientation;
smcameron commented 4 years ago

Even with f_n = 64, you can still see the shading of the polygons (which surprises me, because I thought the smoothing would kick in.)

Screenshot_2020-02-23_18-19-53

smcameron commented 4 years ago

The old model had 868 vertices and 1732 face, the $fn=64 model has 4568 vertices and 9132 faces, which seems like a lot for what it is.

smcameron commented 4 years ago

Also put the new model stl file up on spacenerdsinspace.com so "make update-assets" will get it.

This might still have problems with very wide aspect ratio screens though.

I'll think about the higher poly model a bit more.

smcameron commented 4 years ago

I would also say that before texturing the model, improving the model before texturing is worth while. The model as it stands is nothing special. Also, OpenSCAD, while ok for this kind of simple, untextured model, is not known for producing meshes that are easy to UV unwrap. Its priorities are skewed a little more towards accuracy (within the bounds of floating point numbers) and away from producing simple meshes, so you get all kinds of weird things happening in the mesh where surfaces intersect and generally a lot more vertices than you'd find in a more custom, human-designed mesh. You might have noticed this if you already uv-unwrapped this model, although this one was fairly simple so maybe not too bad. And there tend to be a lot of intersecting surfaces in an OpenSCAD mesh given that it's a CSG based modelling tool, so a lot of weirdness. And once you do uv-unwrap and texture a model, which usually involves cleaning up the mesh with blender, meshlab, etc., you kind of "freeze" the model, in that you can no longer change it via OpenSCAD, but have to have moved to blender or similar, and then I'm kind of stuck with however it came out, since I'm not much good at blender or anything other than OpenSCAD. So I'm a little reluctant to "freeze" a model that's just not anything special to begin with.

smcameron commented 4 years ago

Maybe something like this? (still programmer art, but maybe a bit better):

spaceship_turret3

spaceship_turret3_ingame

MCMic commented 4 years ago

Maybe a design a bit like this one would avoid the cylinder problem: https://opengameart.org/content/turret-reviwed

(What I mean is design the barrels to not be cylindric anyway so that it’s less shocking that they have faces)

smcameron commented 4 years ago

Let me see if I can tweak the phong shading to make those faces go away.

smcameron commented 4 years ago

Hmm, I think maybe there's a bug somewhere in the vertex normal calculations causing these artifacts. Not really sure.

smcameron commented 4 years ago

Ok, I figured out why I was getting that weird lighting. It's because of the fact that there is no "right" way to calculate vertex normals, because it's inherently a compromise to approximate continuous surface normals by interpolation, and the chosen value of vertex normals is arrived at by sort of averaging the normals of adjacent triangles with some weighting by triangle size and by the angle of each triangle sharing a vertex. This doesn't always come out looking right. But knowing this, you can sometimes tweak the mesh to avoid problems if they appear. See #254 for an example.

smcameron commented 4 years ago

Tweaked the model to prevent the vertex normals of the round part of the barrel from being unduly and badly influenced by adjacent triangle normals.

Also updated spacenerdsinspace.com with this new model so "make update-assets" will pick it up.

turret3

MCMic commented 4 years ago

@smcameron The turret is vibrating when I look around with it, not sure if this is new or intended.

MCMic commented 4 years ago

Looks like a rounding problem maybe

smcameron commented 4 years ago

I've noticed that too. I don't know what causes it. Also noticed the lens-flare movement isn't smooth and not sure why that is either (most noticeable if you're moving fast, via UTILITY/PLAYER SPEED BOOST on demon screen.)

MCMic commented 4 years ago

@smcameron The turret is vibrating when I look around with it, not sure if this is new or intended.

This is also happeninng with joystick, not specific to mouse control. It does not happen when turret is parallel to the ship and you only move left/right.

MCMic commented 4 years ago

fine = 2 * (timer - last_time > 5);

@smcameron This looks weird to me, is this mix of arithmetic and comparison on purpose?

MCMic commented 4 years ago

What does adjust_weapons_azimuth_angle do? What is the difference between adjusted_cam_orientation and camera_orientation?

The camera is not flickering, only the turret, so I guess the problem is somewhere in show_weapons_camera_view.

MCMic commented 4 years ago

If I remove the 3 lines with view_offset, the camera is right between the barrels, but no more fickering. Not sure if this is progress…

MCMic commented 4 years ago

Removing only quat_rot_vec_self(&view_offset, &adjusted_cam_orientation); removes the flickering, but changes the view depending on where you look.

smcameron commented 4 years ago

@MCMic

fine = 2 * (timer - last_time > 5);

@smcameron This looks weird to me, is this mix of arithmetic and comparison on purpose?

Yes. if (timer - last_time > 5) it means it's been a little while since they hit the key, so fine will == 2. If they hit keys in quick succession, and fine will be 0.

Then fine (either 0 or 2) will be added to the constants PITCH_BACK, or PITCH_FORWARD, or YAW_LEFT, or YAW_RIGHT.

If you look in snis_packet.h, you'll see:

#define YAW_LEFT 0
#define YAW_RIGHT 1
#define YAW_LEFT_FINE 2
#define YAW_RIGHT_FINE 3
#define PITCH_FORWARD 0
#define PITCH_BACK 1
#define PITCH_FORWARD_FINE 2
#define PITCH_BACK_FINE 3
#define ROLL_LEFT 0
#define ROLL_RIGHT 1
#define ROLL_LEFT_FINE 2
#define ROLL_RIGHT_FINE 3

Notice that the "_FINE" versions of those values differ from the corresponding non-"_FINE" versions by exactly 2.

So it's selecting (or not) the _FINE values based on whether the keypress is very soon after the last one, or it's been a little while. If it's been a little while, then it uses the fine version (small change), if it's in quick succession, it uses the non-fine version (coarse adjustment).

This way, if you just tap the keys slowly, you get slow movement, but if you press faster, it moves faster.

Is it all too clever for its own good? Yeah, sure. What was I thinking? I dunno. That code has been in there a long time, so I don't really remember. It's in commit 8392bfa5 from 2013.

What does adjust_weapons_azimuth_angle do? What is the difference between adjusted_cam_orientation and camera_orientation?

Normally weapons_azimuth angle is zero, so nearly nothing. It's a recent for the weapons widescreen view. https://www.youtube.com/watch?v=NEFGWxXMHJM This is not the problem, because it normally doesn't do anything (other than unhide the gauges on weapons.) adjusted_cam_orientation is making the camera look left or right if you have extra screens for a widescreen view. If you don't set weapons_azimuth_angle (so it is zero), then there is no difference between adjusted_cam_orientation and camera_orientation.

Removing only quat_rot_vec_self(&view_offset, &adjusted_cam_orientation); removes the flickering, but changes the view depending on where you look.

So view_offset is moving the camera relative to the turret. If I change this:

diff --git a/snis_client.c b/snis_client.c
index 59aa6fe..de74385 100644
--- a/snis_client.c
+++ b/snis_client.c
@@ -9069,7 +9069,8 @@ static void show_weapons_camera_view(GtkWidget *w)
        quat_rot_vec_self(&turret_pos, &o->orientation);
        vec3_add_c_self(&turret_pos, cx, cy, cz);

-       union vec3 view_offset = { {0, 0.75 * SHIP_MESH_SCALE, 0} };
+       // union vec3 view_offset = { {0, 0.75 * SHIP_MESH_SCALE, 0} };
+       union vec3 view_offset = { {0, 0, 0} };
        quat_rot_vec_self(&view_offset, &adjusted_cam_orientation);

        union vec3 cam_pos = turret_pos;

The jittering goes away, which is interesting, because it means the problem is with view_offset. What view offset is doing is moving the camera a little bit "up" relative to the turret (that is to say, if the turret is turned forward, then tilted straight up, then "up" relative to the turret is "aft", and if the turret is turned 90 degrees left, then straight up, then "up" relative to the turret is "right". Hope that makes sense.

So to explain this:

        union vec3 view_offset = { {0, 0.75 * SHIP_MESH_SCALE, 0} };
        quat_rot_vec_self(&view_offset, &adjusted_cam_orientation);

        union vec3 cam_pos = turret_pos;
        vec3_add_self(&cam_pos, &view_offset);
  1. view_offset starts out as a vector of length 0.75 * SHIP_MESH_SCALE pointing up. Some fraction of the size of the ship, arrived at empirically, I'm pretty sure, by trying different values until finding 0.75 looked good. You can change 0.75 and get a feel for what it does. Putting in 5.75 will put the camera way above the turret. Putting in negative values should put your camera below the turret.

  2. quat_rot_vec_self(&view_offset, &adjusted_cam_orientation); This rotates the "up" vector into the orientation of the turret, so that it is "up" relative to the turret's orientation, whatever that might be.

  3. vec3_add_self(&cam_pos, &view_offset); This moves the cam position "up" relative to the turret.

Hope that makes sense.

It is not immediately clear to me why this would make things jitter. I would say that it would have to be a problem with camera_orientation (and thus adjusted_cam_orientation as well), but then it would seem like it ought to jitter even if view_offset is { 0, 0, 0}, yet it does not in that case. Mysterious.

smcameron commented 4 years ago

Ok, I think it is due to floating point imprecision as you move far from zero. If you go to SCIENCE, and set a waypoint for (0, 0, 0), then travel to that location by warp drive, when you arrive, the weapons will no longer jitter.

It's because by default, you start off with your ship in a position that is not very close to (0, 0, 0), so the distance between successive floating point numbers is starting to get big enough to notice in calculations probably somewhere in the renderer. At critical points in the renderer we convert to doubles, but not everywhere.

It might help if the center of the solarsystem were (0, 0, 0), but it isn't. If you look on the demon screen, 0, 0, 0 is in the center of the lower left edge of the cube formed by all the little green axes.

I forgot, we had already tracked this issue down to floating point imprecision before, a long time ago, probably in 2013 or 2014.

smcameron commented 4 years ago

Actually, now that I think of it, it's not in the renderer. It might be that view_offset is a very small vector compared to cam_pos, so when you add them together, the addition loses some of the precision of view_offset.

smcameron commented 4 years ago

Moving the ship to (0, 0, 0) also appears to "cure" the jitteriness of the lens flare as well.

smcameron commented 4 years ago

Moved the solarsystem center to (0, 0, 0) and updated all the lua scripts to account for this.

This improves the turret jitteriness a little bit, but not a lot.

smcameron commented 1 year ago

This is an interesting article about using doubles rather than floats for translations to avoid jitteriness when far from the origin without having a floating origin (means, it might even work for multi-player.) https://godotengine.org/article/emulating-double-precision-gpu-render-large-worlds

Has some limitations though, so not sure it will really work or gain that much for our purposes. This appears to be the commit that article is talking about:

https://github.com/godotengine/godot/commit/27a3014f5052ae40f89684a5559c17fbebe7aa8d

And here is a paper: https://andrewthall.org/papers/df64_qf128.pdf