diff options
-rw-r--r-- | modules/csg/csg_shape.cpp | 66 |
1 files changed, 35 insertions, 31 deletions
diff --git a/modules/csg/csg_shape.cpp b/modules/csg/csg_shape.cpp index 73c1ba554c..b47fa35f1a 100644 --- a/modules/csg/csg_shape.cpp +++ b/modules/csg/csg_shape.cpp @@ -923,36 +923,40 @@ CSGBrush *CSGSphere3D::_build_brush() { Ref<Material> *materialsw = materials.ptrw(); bool *invertw = invert.ptrw(); - const double lat_step = 1.0 / rings; - const double lon_step = 1.0 / radial_segments; + // We want to follow an order that's convenient for UVs. + // For latitude step we start at the top and move down like in an image. + const double latitude_step = -Math_PI / rings; + const double longitude_step = Math_TAU / radial_segments; int face = 0; - for (int i = 1; i <= rings; i++) { - double lat0 = Math_PI * (0.5 - (i - 1) * lat_step); - double c0 = Math::cos(lat0); - double s0 = Math::sin(lat0); - double v0 = double(i - 1) / rings; - - double lat1 = Math_PI * (0.5 - i * lat_step); - double c1 = Math::cos(lat1); - double s1 = Math::sin(lat1); - double v1 = double(i) / rings; - - for (int j = 1; j <= radial_segments; j++) { - double lng0 = Math_TAU * (0.5 - (j - 1) * lon_step); - double x0 = Math::cos(lng0); - double y0 = Math::sin(lng0); - double u0 = double(j - 1) / radial_segments; - - double lng1 = Math_TAU * (0.5 - j * lon_step); - double x1 = Math::cos(lng1); - double y1 = Math::sin(lng1); - double u1 = double(j) / radial_segments; + for (int i = 0; i < rings; i++) { + double latitude0 = latitude_step * i + Math_TAU / 4; + double cos0 = Math::cos(latitude0); + double sin0 = Math::sin(latitude0); + double v0 = double(i) / rings; + + double latitude1 = latitude_step * (i + 1) + Math_TAU / 4; + double cos1 = Math::cos(latitude1); + double sin1 = Math::sin(latitude1); + double v1 = double(i + 1) / rings; + + for (int j = 0; j < radial_segments; j++) { + double longitude0 = longitude_step * j; + // We give sin to X and cos to Z on purpose. + // This allows UVs to be CCW on +X so it maps to images well. + double x0 = Math::sin(longitude0); + double z0 = Math::cos(longitude0); + double u0 = double(j) / radial_segments; + + double longitude1 = longitude_step * (j + 1); + double x1 = Math::sin(longitude1); + double z1 = Math::cos(longitude1); + double u1 = double(j + 1) / radial_segments; Vector3 v[4] = { - Vector3(x0 * c0, s0, y0 * c0) * radius, - Vector3(x1 * c0, s0, y1 * c0) * radius, - Vector3(x1 * c1, s1, y1 * c1) * radius, - Vector3(x0 * c1, s1, y0 * c1) * radius, + Vector3(x0 * cos0, sin0, z0 * cos0) * radius, + Vector3(x1 * cos0, sin0, z1 * cos0) * radius, + Vector3(x1 * cos1, sin1, z1 * cos1) * radius, + Vector3(x0 * cos1, sin1, z0 * cos1) * radius, }; Vector2 u[4] = { @@ -962,8 +966,8 @@ CSGBrush *CSGSphere3D::_build_brush() { Vector2(u0, v1), }; - if (i < rings) { - //face 1 + // Draw the first face, but skip this at the north pole (i == 0). + if (i > 0) { facesw[face * 3 + 0] = v[0]; facesw[face * 3 + 1] = v[1]; facesw[face * 3 + 2] = v[2]; @@ -979,8 +983,8 @@ CSGBrush *CSGSphere3D::_build_brush() { face++; } - if (i > 1) { - //face 2 + // Draw the second face, but skip this at the south pole (i == rings - 1). + if (i < rings - 1) { facesw[face * 3 + 0] = v[2]; facesw[face * 3 + 1] = v[3]; facesw[face * 3 + 2] = v[0]; |