Skip to content

Commit 9773418

Browse files
authored
Fix water artifact when looking at water on the horizon/with low incidence angle (#935)
* Change all access to ray.n to use getter/setter so we can keep track of the geometry normal and the shading normal at the same time * Take the real geometry normal into account when computing ray direction for reflection or refraction to not go through the geometry * Make the code work even if the face faces the other direction. Copy the vector in setN rather keeping a reference on it (caused issue when the vector was reused by the caller of setN) * Oops bad rebase (more usage of setN) * Add function to set and orient ray.n and use it everywhere to save on an allocation (and simplify the code) * Rename normal related methods and add a bit of javadoc
1 parent 6dd5293 commit 9773418

102 files changed

Lines changed: 367 additions & 327 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

chunky/src/java/se/llbit/chunky/block/AttachedStem.java

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -69,8 +69,7 @@ public AttachedStem(String name, String facing) {
6969
ray.color.y *= Stem.stemColor[7][1];
7070
ray.color.z *= Stem.stemColor[7][2];
7171
ray.t = ray.tNext;
72-
ray.n.set(quad.n);
73-
ray.n.scale(-QuickMath.signum(ray.d.dot(quad.n)));
72+
ray.orientNormal(quad.n);
7473
hit = true;
7574
}
7675
}
@@ -84,8 +83,7 @@ public AttachedStem(String name, String facing) {
8483
ray.color.y *= Stem.stemColor[7][1];
8584
ray.color.z *= Stem.stemColor[7][2];
8685
ray.t = ray.tNext;
87-
ray.n.set(quad.n);
88-
ray.n.scale(-QuickMath.signum(ray.d.dot(quad.n)));
86+
ray.orientNormal(quad.n);
8987
hit = true;
9088
}
9189
}

chunky/src/java/se/llbit/chunky/block/Conduit.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ public Conduit() {
5555
float[] color = texture.getColor(ray.u, ray.v);
5656
if (color[3] > Ray.EPSILON) {
5757
ray.color.set(color);
58-
ray.n.set(quad.n);
58+
ray.setNormal(quad.n);
5959
ray.t = ray.tNext;
6060
hit = true;
6161
}

chunky/src/java/se/llbit/chunky/block/GrassBlock.java

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
import se.llbit.chunky.resources.Texture;
55
import se.llbit.math.AABB;
66
import se.llbit.math.Ray;
7+
import se.llbit.math.Vector3;
78

89
public class GrassBlock extends MinecraftBlock {
910
private final static AABB aabb = new AABB(0, 1, 0, 1, 0, 1);
@@ -16,13 +17,14 @@ public GrassBlock() {
1617
@Override public boolean intersect(Ray ray, Scene scene) {
1718
ray.t = Double.POSITIVE_INFINITY;
1819
if (aabb.intersect(ray)) {
19-
if (ray.n.y == -1) {
20+
Vector3 n = ray.getNormal();
21+
if (n.y == -1) {
2022
// Bottom face.
2123
Texture.dirt.getColor(ray);
2224
ray.t = ray.tNext;
2325
} else {
2426
float[] color;
25-
if (ray.n.y > 0) {
27+
if (n.y > 0) {
2628
color = Texture.grassTop.getColor(ray.u, ray.v);
2729
} else {
2830
color = Texture.grassSide.getColor(ray.u, ray.v);

chunky/src/java/se/llbit/chunky/block/Lava.java

Lines changed: 11 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -58,8 +58,7 @@ public boolean isFullBlock() {
5858

5959
boolean hit = false;
6060
if (bottom.intersect(ray)) {
61-
ray.n.set(bottom.n);
62-
ray.n.scale(-QuickMath.signum(ray.d.dot(bottom.n)));
61+
ray.orientNormal(bottom.n);
6362
ray.t = ray.tNext;
6463
hit = true;
6564
}
@@ -70,24 +69,21 @@ public boolean isFullBlock() {
7069
int c3 = (0xF & (data >> CORNER_3)) % 8;
7170
Triangle triangle = Water.t012[c0][c1][c2];
7271
if (triangle.intersect(ray)) {
73-
ray.n.set(triangle.n);
74-
ray.n.scale(QuickMath.signum(-ray.d.dot(triangle.n)));
72+
ray.orientNormal(triangle.n);
7573
ray.t = ray.tNext;
7674
hit = true;
7775
}
7876
triangle = Water.t230[c2][c3][c0];
7977
if (triangle.intersect(ray)) {
80-
ray.n.set(triangle.n);
81-
ray.n.scale(QuickMath.signum(-ray.d.dot(triangle.n)));
78+
ray.orientNormal(triangle.n);
8279
ray.t = ray.tNext;
8380
ray.u = 1 - ray.u;
8481
ray.v = 1 - ray.v;
8582
hit = true;
8683
}
8784
triangle = Water.westt[c0][c3];
8885
if (triangle.intersect(ray)) {
89-
ray.n.set(triangle.n);
90-
ray.n.scale(QuickMath.signum(-ray.d.dot(triangle.n)));
86+
ray.orientNormal(triangle.n);
9187
ray.t = ray.tNext;
9288
double y = ray.t * ray.d.y + ray.o.y;
9389
double z = ray.t * ray.d.z + ray.o.z;
@@ -99,8 +95,7 @@ public boolean isFullBlock() {
9995
}
10096
triangle = Water.westb[c0];
10197
if (triangle.intersect(ray)) {
102-
ray.n.set(triangle.n);
103-
ray.n.scale(QuickMath.signum(-ray.d.dot(triangle.n)));
98+
ray.orientNormal(triangle.n);
10499
ray.t = ray.tNext;
105100
double y = ray.t * ray.d.y + ray.o.y;
106101
double z = ray.t * ray.d.z + ray.o.z;
@@ -112,8 +107,7 @@ public boolean isFullBlock() {
112107
}
113108
triangle = Water.eastt[c1][c2];
114109
if (triangle.intersect(ray)) {
115-
ray.n.set(triangle.n);
116-
ray.n.scale(QuickMath.signum(-ray.d.dot(triangle.n)));
110+
ray.orientNormal(triangle.n);
117111
ray.t = ray.tNext;
118112
double y = ray.t * ray.d.y + ray.o.y;
119113
double z = ray.t * ray.d.z + ray.o.z;
@@ -125,8 +119,7 @@ public boolean isFullBlock() {
125119
}
126120
triangle = Water.eastb[c1];
127121
if (triangle.intersect(ray)) {
128-
ray.n.set(triangle.n);
129-
ray.n.scale(QuickMath.signum(-ray.d.dot(triangle.n)));
122+
ray.orientNormal(triangle.n);
130123
ray.t = ray.tNext;
131124
double y = ray.t * ray.d.y + ray.o.y;
132125
double z = ray.t * ray.d.z + ray.o.z;
@@ -138,8 +131,7 @@ public boolean isFullBlock() {
138131
}
139132
triangle = Water.southt[c0][c1];
140133
if (triangle.intersect(ray)) {
141-
ray.n.set(triangle.n);
142-
ray.n.scale(QuickMath.signum(-ray.d.dot(triangle.n)));
134+
ray.orientNormal(triangle.n);
143135
ray.t = ray.tNext;
144136
double x = ray.t * ray.d.x + ray.o.x;
145137
double y = ray.t * ray.d.y + ray.o.y;
@@ -151,8 +143,7 @@ public boolean isFullBlock() {
151143
}
152144
triangle = Water.southb[c1];
153145
if (triangle.intersect(ray)) {
154-
ray.n.set(triangle.n);
155-
ray.n.scale(QuickMath.signum(-ray.d.dot(triangle.n)));
146+
ray.orientNormal(triangle.n);
156147
ray.t = ray.tNext;
157148
double x = ray.t * ray.d.x + ray.o.x;
158149
double y = ray.t * ray.d.y + ray.o.y;
@@ -164,8 +155,7 @@ public boolean isFullBlock() {
164155
}
165156
triangle = Water.northt[c2][c3];
166157
if (triangle.intersect(ray)) {
167-
ray.n.set(triangle.n);
168-
ray.n.scale(QuickMath.signum(-ray.d.dot(triangle.n)));
158+
ray.orientNormal(triangle.n);
169159
ray.t = ray.tNext;
170160
double x = ray.t * ray.d.x + ray.o.x;
171161
double y = ray.t * ray.d.y + ray.o.y;
@@ -177,8 +167,7 @@ public boolean isFullBlock() {
177167
}
178168
triangle = Water.northb[c2];
179169
if (triangle.intersect(ray)) {
180-
ray.n.set(triangle.n);
181-
ray.n.scale(QuickMath.signum(-ray.d.dot(triangle.n)));
170+
ray.orientNormal(triangle.n);
182171
ray.t = ray.tNext;
183172
double x = ray.t * ray.d.x + ray.o.x;
184173
double y = ray.t * ray.d.y + ray.o.y;

chunky/src/java/se/llbit/chunky/block/Log.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,7 @@ public Log(String name, Texture side, Texture top, String axis) {
8181
ray.u = (1 - uv_x) * ray.u + uv_x * ray.v;
8282
ray.v = uv_x * u + (1 - uv_x) * ray.v;
8383
texture[textureIndex[direction][i]].getColor(ray);
84-
ray.n.set(side.n);
84+
ray.setNormal(side.n);
8585
ray.t = ray.tNext;
8686
hit = true;
8787
}

chunky/src/java/se/llbit/chunky/block/NetherPortal.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ public NetherPortal(String axis) {
4949
return false;
5050
}
5151
texture.getColor(ray);
52-
ray.n.set(quad[axis].n);
52+
ray.setNormal(quad[axis].n);
5353
ray.t = ray.tNext;
5454
ray.distance += ray.t;
5555
ray.o.scaleAdd(ray.t, ray.d);

chunky/src/java/se/llbit/chunky/block/OrientedTexturedBlock.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,7 @@ public boolean intersect(Ray ray, Scene scene) {
105105
if (side.intersect(ray)) {
106106
rotateUV(ray, i);
107107
texture[textureOrientationMap[facing][i]].getColor(ray);
108-
ray.n.set(side.n);
108+
ray.setNormal(side.n);
109109
ray.t = ray.tNext;
110110
hit = true;
111111
}

chunky/src/java/se/llbit/chunky/block/SeaPickle.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -730,7 +730,7 @@ public boolean intersect(Ray ray, Scene scene) {
730730
if (color[3] > Ray.EPSILON) {
731731
ray.color.set(color);
732732
texture.getColor(ray);
733-
ray.n.set(quad.n);
733+
ray.setNormal(quad.n);
734734
ray.t = ray.tNext;
735735
hit = true;
736736
}
@@ -742,7 +742,7 @@ public boolean intersect(Ray ray, Scene scene) {
742742
float[] color = texture.getColor(ray.u, ray.v);
743743
if (color[3] > Ray.EPSILON) {
744744
ray.color.set(color);
745-
ray.n.set(quad.n);
745+
ray.setNormal(quad.n);
746746
ray.t = ray.tNext;
747747
hit = true;
748748
}

chunky/src/java/se/llbit/chunky/block/Slab.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ public Slab(String name, Texture texture, String type) {
5050
@Override public boolean intersect(Ray ray, Scene scene) {
5151
ray.t = Double.POSITIVE_INFINITY;
5252
if (aabb[half].intersect(ray)) {
53-
if (ray.n.y != 0) {
53+
if (ray.getNormal().y != 0) {
5454
topTexture.getColor(ray);
5555
} else {
5656
sideTexture.getColor(ray);

chunky/src/java/se/llbit/chunky/block/SnowCovered.java

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import se.llbit.chunky.renderer.scene.Scene;
44
import se.llbit.chunky.resources.Texture;
55
import se.llbit.math.Ray;
6+
import se.llbit.math.Vector3;
67

78
public class SnowCovered extends MinecraftBlock {
89
private final Block block;
@@ -17,9 +18,10 @@ public SnowCovered(Block block) {
1718
ray.t = Double.POSITIVE_INFINITY;
1819
boolean hit = block.intersect(ray, scene);
1920
if (hit) {
20-
if (ray.n.y == 0) {
21+
Vector3 n = ray.getNormal();
22+
if (n.y == 0) {
2123
Texture.snowSide.getColor(ray);
22-
} else if (ray.n.y > 0) {
24+
} else if (n.y > 0) {
2325
Texture.snowBlock.getColor(ray);
2426
}
2527
}

0 commit comments

Comments
 (0)