Skip to content

Commit

Permalink
Planet: Add "planet_keep_scale" option to make nodes in the player's …
Browse files Browse the repository at this point in the history
…proximity always look the same size
  • Loading branch information
Jeija committed May 18, 2016
1 parent 8f6ef37 commit 55de24a
Show file tree
Hide file tree
Showing 6 changed files with 117 additions and 9 deletions.
30 changes: 28 additions & 2 deletions client/shaders/default_shader/opengl_vertex.glsl
Original file line number Diff line number Diff line change
Expand Up @@ -59,22 +59,48 @@ void main(void)
vec3 camPos = viewModel[3].xyz;

// Step 1: Transform normal coordinates into coordinates as if they were on a sphere
float radius = PLANET_RADIUS * BS * 16 + pos.y;
float xangle = (pos.x - camPos.x) / (PLANET_RADIUS * BS * 16);
float zangle = (pos.z - camPos.z) / (PLANET_RADIUS * BS * 16);
float distangle = pow(xangle * xangle + zangle * zangle, 0.5);

#ifdef PLANET_KEEP_SCALE
/*
* The width of nodes increases with increasing height, which means
* that nodes need to be scaled in their height if we want to make it
* so that the nodes always look like they're normally shaped.
* With the intercept theorem we get width(x) = (r + camPos.y + x) / r,
* with r = PLANET_RADIUS * BS * MAP_BLOCKSIZE
* and x being the block's visual (not physical!) height above the camera.
* In order to completely and accurately scale all the nodes, we need
* to solve the differential equation x'(p) = q = (r + camPos.y + x(p)) / r
* with p being the physical height of the node above the camera. Obviously
* the visual height is zero if the physical height is zero, so x(0) = 0.
* We get the solution x(p) = (exp(p / r - 1))*(r + camPos.y)
* If we set p = h = pos.y - camPos.y (distance from camera y to vertex y)
* we get the visual height of the vertex above the camera which is
* x(h) = (exp(h / r - 1)) * (r + camPos.y) and because the camera is obviously
* at height rcam = r + camPos.y (since y=0 is at radius of planet), for the
* total radius of the vertex we get radius = rcam + x(h) = (camPos.y + r) * exp(h / r)
*/
float r = PLANET_RADIUS * BS * 16;
float h = pos.y - camPos.y;
float radius = (camPos.y + r) * exp(h / r);
#else
float radius = PLANET_RADIUS * BS * 16 + pos.y;
#endif

// Step 2: Transform back from spherical coordinates to cartesian system with
// the center of the planet in the origin of the coordinate system.
float planet_x = sin(xangle) * radius;
float planet_z = sin(zangle) * radius;
float planet_y = cos(distangle) * radius;

// Step 3: Translate coordinates so that they are relative to the camera, not the planet center
// The planet center is *always* position PLANET_RADIUS underneath the player
// The planet center is *always* positioned underneath the player
pos.y = planet_y - (PLANET_RADIUS * BS * 16);
pos.x = camPos.x + planet_x;
pos.z = camPos.z + planet_z;

#endif

gl_Position = mWorldViewProj * pos;
Expand Down
30 changes: 28 additions & 2 deletions client/shaders/nodes_shader/opengl_vertex.glsl
Original file line number Diff line number Diff line change
Expand Up @@ -118,22 +118,48 @@ float disp_z;
vec3 camPos = viewModel[3].xyz;

// Step 1: Transform normal coordinates into coordinates as if they were on a sphere
float radius = PLANET_RADIUS * BS * 16 + pos.y;
float xangle = (pos.x - camPos.x) / (PLANET_RADIUS * BS * 16);
float zangle = (pos.z - camPos.z) / (PLANET_RADIUS * BS * 16);
float distangle = pow(xangle * xangle + zangle * zangle, 0.5);

#ifdef PLANET_KEEP_SCALE
/*
* The width of nodes increases with increasing height, which means
* that nodes need to be scaled in their height if we want to make it
* so that the nodes always look like they're normally shaped.
* With the intercept theorem we get width(x) = (r + camPos.y + x) / r,
* with r = PLANET_RADIUS * BS * MAP_BLOCKSIZE
* and x being the block's visual (not physical!) height above the camera.
* In order to completely and accurately scale all the nodes, we need
* to solve the differential equation x'(p) = q = (r + camPos.y + x(p)) / r
* with p being the physical height of the node above the camera. Obviously
* the visual height is zero if the physical height is zero, so x(0) = 0.
* We get the solution x(p) = (exp(p / r - 1))*(r + camPos.y)
* If we set p = h = pos.y - camPos.y (distance from camera y to vertex y)
* we get the visual height of the vertex above the camera which is
* x(h) = (exp(h / r - 1)) * (r + camPos.y) and because the camera is obviously
* at height rcam = r + camPos.y (since y=0 is at radius of planet), for the
* total radius of the vertex we get radius = rcam + x(h) = (camPos.y + r) * exp(h / r)
*/
float r = PLANET_RADIUS * BS * 16;
float h = pos.y - camPos.y;
float radius = (camPos.y + r) * exp(h / r);
#else
float radius = PLANET_RADIUS * BS * 16 + pos.y;
#endif

// Step 2: Transform back from spherical coordinates to cartesian system with
// the center of the planet in the origin of the coordinate system.
float planet_x = sin(xangle) * radius;
float planet_z = sin(zangle) * radius;
float planet_y = cos(distangle) * radius;

// Step 3: Translate coordinates so that they are relative to the camera, not the planet center
// The planet center is *always* position PLANET_RADIUS underneath the player
// The planet center is *always* positioned underneath the player
pos.y = planet_y - (PLANET_RADIUS * BS * 16);
pos.x = camPos.x + planet_x;
pos.z = camPos.z + planet_z;

#endif

#if (MATERIAL_TYPE == TILE_MATERIAL_LIQUID_TRANSPARENT || MATERIAL_TYPE == TILE_MATERIAL_LIQUID_OPAQUE) && ENABLE_WAVING_WATER
Expand Down
30 changes: 28 additions & 2 deletions client/shaders/selection_shader/opengl_vertex.glsl
Original file line number Diff line number Diff line change
Expand Up @@ -59,22 +59,48 @@ void main(void)
vec3 camPos = viewModel[3].xyz;

// Step 1: Transform normal coordinates into coordinates as if they were on a sphere
float radius = PLANET_RADIUS * BS * 16 + pos.y;
float xangle = (pos.x - camPos.x) / (PLANET_RADIUS * BS * 16);
float zangle = (pos.z - camPos.z) / (PLANET_RADIUS * BS * 16);
float distangle = pow(xangle * xangle + zangle * zangle, 0.5);

#ifdef PLANET_KEEP_SCALE
/*
* The width of nodes increases with increasing height, which means
* that nodes need to be scaled in their height if we want to make it
* so that the nodes always look like they're normally shaped.
* With the intercept theorem we get width(x) = (r + camPos.y + x) / r,
* with r = PLANET_RADIUS * BS * MAP_BLOCKSIZE
* and x being the block's visual (not physical!) height above the camera.
* In order to completely and accurately scale all the nodes, we need
* to solve the differential equation x'(p) = q = (r + camPos.y + x(p)) / r
* with p being the physical height of the node above the camera. Obviously
* the visual height is zero if the physical height is zero, so x(0) = 0.
* We get the solution x(p) = (exp(p / r - 1))*(r + camPos.y)
* If we set p = h = pos.y - camPos.y (distance from camera y to vertex y)
* we get the visual height of the vertex above the camera which is
* x(h) = (exp(h / r - 1)) * (r + camPos.y) and because the camera is obviously
* at height rcam = r + camPos.y (since y=0 is at radius of planet), for the
* total radius of the vertex we get radius = rcam + x(h) = (camPos.y + r) * exp(h / r)
*/
float r = PLANET_RADIUS * BS * 16;
float h = pos.y - camPos.y;
float radius = (camPos.y + r) * exp(h / r);
#else
float radius = PLANET_RADIUS * BS * 16 + pos.y;
#endif

// Step 2: Transform back from spherical coordinates to cartesian system with
// the center of the planet in the origin of the coordinate system.
float planet_x = sin(xangle) * radius;
float planet_z = sin(zangle) * radius;
float planet_y = cos(distangle) * radius;

// Step 3: Translate coordinates so that they are relative to the camera, not the planet center
// The planet center is *always* position PLANET_RADIUS underneath the player
// The planet center is *always* positioned underneath the player
pos.y = planet_y - (PLANET_RADIUS * BS * 16);
pos.x = camPos.x + planet_x;
pos.z = camPos.z + planet_z;

#endif

gl_Position = mWorldViewProj * pos;
Expand Down
30 changes: 28 additions & 2 deletions client/shaders/water_surface_shader/opengl_vertex.glsl
Original file line number Diff line number Diff line change
Expand Up @@ -88,22 +88,48 @@ void main(void)
vec3 camPos = viewModel[3].xyz;

// Step 1: Transform normal coordinates into coordinates as if they were on a sphere
float radius = PLANET_RADIUS * BS * 16 + pos.y;
float xangle = (pos.x - camPos.x) / (PLANET_RADIUS * BS * 16);
float zangle = (pos.z - camPos.z) / (PLANET_RADIUS * BS * 16);
float distangle = pow(xangle * xangle + zangle * zangle, 0.5);

#ifdef PLANET_KEEP_SCALE
/*
* The width of nodes increases with increasing height, which means
* that nodes need to be scaled in their height if we want to make it
* so that the nodes always look like they're normally shaped.
* With the intercept theorem we get width(x) = (r + camPos.y + x) / r,
* with r = PLANET_RADIUS * BS * MAP_BLOCKSIZE
* and x being the block's visual (not physical!) height above the camera.
* In order to completely and accurately scale all the nodes, we need
* to solve the differential equation x'(p) = q = (r + camPos.y + x(p)) / r
* with p being the physical height of the node above the camera. Obviously
* the visual height is zero if the physical height is zero, so x(0) = 0.
* We get the solution x(p) = (exp(p / r - 1))*(r + camPos.y)
* If we set p = h = pos.y - camPos.y (distance from camera y to vertex y)
* we get the visual height of the vertex above the camera which is
* x(h) = (exp(h / r - 1)) * (r + camPos.y) and because the camera is obviously
* at height rcam = r + camPos.y (since y=0 is at radius of planet), for the
* total radius of the vertex we get radius = rcam + x(h) = (camPos.y + r) * exp(h / r)
*/
float r = PLANET_RADIUS * BS * 16;
float h = pos.y - camPos.y;
float radius = (camPos.y + r) * exp(h / r);
#else
float radius = PLANET_RADIUS * BS * 16 + pos.y;
#endif

// Step 2: Transform back from spherical coordinates to cartesian system with
// the center of the planet in the origin of the coordinate system.
float planet_x = sin(xangle) * radius;
float planet_z = sin(zangle) * radius;
float planet_y = cos(distangle) * radius;

// Step 3: Translate coordinates so that they are relative to the camera, not the planet center
// The planet center is *always* position PLANET_RADIUS underneath the player
// The planet center is *always* positioned underneath the player
pos.y = planet_y - (PLANET_RADIUS * BS * 16);
pos.x = camPos.x + planet_x;
pos.z = camPos.z + planet_z;

#endif

#if (MATERIAL_TYPE == TILE_MATERIAL_LIQUID_TRANSPARENT || MATERIAL_TYPE == TILE_MATERIAL_LIQUID_OPAQUE) && ENABLE_WAVING_WATER
Expand Down
3 changes: 2 additions & 1 deletion src/defaultsettings.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -320,9 +320,10 @@ void set_default_settings(Settings *settings)
settings->setDefault("chunksize", "5");
settings->setDefault("mg_flags", "dungeons");

// planet
// Planet
settings->setDefault("planet_enable", "false");
settings->setDefault("planet_radius", "30");
settings->setDefault("planet_keep_scale", "true");

// IPv6
settings->setDefault("enable_ipv6", "true");
Expand Down
3 changes: 3 additions & 0 deletions src/shader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -770,6 +770,9 @@ ShaderInfo generate_shader(std::string name, u8 material_type, u8 drawtype,
if (g_settings->getBool("planet_enable"))
shaders_header += "#define ENABLE_PLANET\n";

if (g_settings->getBool("planet_keep_scale"))
shaders_header += "#define PLANET_KEEP_SCALE\n";

shaders_header += "#define PLANET_RADIUS " + to_string(g_settings->getU16("planet_radius")) + "\n";

// Call addHighLevelShaderMaterial() or addShaderMaterial()
Expand Down

0 comments on commit 55de24a

Please sign in to comment.