diff --git a/res/org/lwjgl/demo/opengl/shader/raymarching.fs.glsl b/res/org/lwjgl/demo/opengl/shader/raymarching.fs.glsl index 7064dc6e..534b36a6 100644 --- a/res/org/lwjgl/demo/opengl/shader/raymarching.fs.glsl +++ b/res/org/lwjgl/demo/opengl/shader/raymarching.fs.glsl @@ -11,25 +11,31 @@ layout (depth_less) out float gl_FragDepth; #endif uniform sampler3D tex; +uniform vec3 size; uniform mat4 mvp; in vec3 o; in vec3 d; -vec3 rayMarch(vec3 o, vec3 d, vec3 ts) { +vec3 rayMarch(vec3 o, vec3 d, vec3 n, vec3 size) { + vec3 ts = vec3(textureSize(tex, 0)); + float ti = 0.0; vec3 p = floor(o), di = vec3(1.0) / d, s = sign(d), t = abs((p + max(s, vec3(0.0)) - o) * di); - int N = int(ts.x + ts.y + ts.z); // <- maximum can only be manhattan distance + int N = int(size.x + size.y + size.z); // <- maximum can only be manhattan distance vec3 c; int i; for (i = 0; i < N; i++) { if (texture(tex, (p+vec3(0.5))/ts).r > 0.0) { - vec4 cp = mvp * vec4((o+d*t)/ts-vec3(0.5), 1.0); + vec4 cp = mvp * vec4((o+d*ti)/size-vec3(0.5), 1.0); gl_FragDepth = cp.z / cp.w; - return abs(c); + return n; } c = step(t.xyz, t.yzx)*step(t.xyz, t.zxy); - t += di * s * c; - p += s * c; + vec3 ds = s*c; + ti = min(t.x, min(t.y, t.z)); + n = -ds; + t += di * ds; + p += ds; if (any(lessThan(p, vec3(0.0))) || any(greaterThanEqual(p, ts))) { break; } @@ -40,6 +46,7 @@ vec3 rayMarch(vec3 o, vec3 d, vec3 ts) { void main(void) { vec3 ts = vec3(textureSize(tex, 0)); vec3 di = 1.0/d, t = min((vec3(-0.5)-o)*di, (vec3(0.5)-o)*di); + vec3 s = sign(d), n = -s*step(t.yzx, t.xyz)*step(t.zxy, t.xyz); vec3 p = o + d * max(max(max(t.x, t.y), t.z), 0.0); - fragColor = vec4(rayMarch((p+vec3(0.5))*ts, d*ts, ts), 1.0); + fragColor = vec4(rayMarch((p+vec3(0.5))*size, d*size, n, size), 1.0); } diff --git a/src/org/lwjgl/demo/opengl/shader/RayMarchingVolumeTexture.java b/src/org/lwjgl/demo/opengl/shader/RayMarchingVolumeTexture.java index 172b98be..c2dcdfc7 100644 --- a/src/org/lwjgl/demo/opengl/shader/RayMarchingVolumeTexture.java +++ b/src/org/lwjgl/demo/opengl/shader/RayMarchingVolumeTexture.java @@ -20,7 +20,6 @@ import org.joml.Matrix4f; import org.joml.Vector3f; -import org.joml.Vector3i; import org.lwjgl.BufferUtils; import org.lwjgl.demo.util.MagicaVoxelLoader; import org.lwjgl.glfw.*; @@ -40,6 +39,7 @@ public class RayMarchingVolumeTexture { private static class Volume { int x, y, z; int w, h, d; + int tw, th, td; int tex; byte[] field; } @@ -49,7 +49,7 @@ private static class Volume { private int height = 768; private int program; - private int mvpUniform, invModelUniform, camPositionUniform; + private int mvpUniform, invModelUniform, camPositionUniform, sizeUniform; private GLFWErrorCallback errCallback; private Callback debugProc; @@ -155,7 +155,6 @@ else if (action == GLFW_RELEASE) } glfwMakeContextCurrent(window); glfwSwapInterval(1); - glfwShowWindow(window); GL.createCapabilities(); debugProc = GLUtil.setupDebugMessageCallback(); glClearColor(0.1f, 0.15f, 0.23f, 1.0f); @@ -166,6 +165,7 @@ else if (action == GLFW_RELEASE) volumes.add(create3dVolume("org/lwjgl/demo/models/mikelovesrobots_mmmm/scene_house5.vox", 0, 0, 0)); volumes.add(create3dVolume("org/lwjgl/demo/models/mikelovesrobots_mmmm/scene_house6.vox", 140, 0, 0)); createBoxVao(); + glfwShowWindow(window); } private void createBoxVao() { int vao = glGenVertexArrays(); @@ -188,22 +188,32 @@ private void createBoxVao() { private static int idx(int x, int y, int z, int width, int height) { return x + width * (y + z * height); } + private static int nextPowerOfTwo(int v) { + v--; + v |= v >> 1; + v |= v >> 2; + v |= v >> 4; + v |= v >> 8; + return (v | v >> 16) + 1; + } private Volume create3dVolume(String resource, int x, int y, int z) throws IOException { int texture = glGenTextures(); glBindTexture(GL_TEXTURE_3D, texture); - Vector3i dims = new Vector3i(); Volume v = new Volume(); + v.x = x; + v.y = y; + v.z = z; try (InputStream is = Objects.requireNonNull(getSystemResourceAsStream(resource))) { BufferedInputStream bis = new BufferedInputStream(is); new MagicaVoxelLoader().read(bis, new MagicaVoxelLoader.Callback() { public void voxel(int x, int y, int z, byte c) { - v.field[idx(x, z, dims.z - 1 - y, dims.x, dims.y)] = c; + v.field[idx(x, z, v.td - 1 - y, v.tw, v.th)] = c; } public void size(int x, int y, int z) { - dims.x = x; - dims.y = z; - dims.z = y; - v.field = new byte[x * y * z]; + v.tw = nextPowerOfTwo(x); + v.th = nextPowerOfTwo(z); + v.td = nextPowerOfTwo(y); + v.field = new byte[v.tw * v.th * v.td]; v.w = x; v.h = z; v.d = y; @@ -216,16 +226,14 @@ public void paletteMaterial(int i, MagicaVoxelLoader.Material mat) { bb.put(v.field); bb.flip(); glPixelStorei(GL_UNPACK_ALIGNMENT, 1); - glTexImage3D(GL_TEXTURE_3D, 0, GL_R8, v.w, v.h, v.d, 0, GL_RED, GL_UNSIGNED_BYTE, bb); + glTexImage3D(GL_TEXTURE_3D, 0, GL_R8, v.tw, v.th, v.td, 0, GL_RED, GL_UNSIGNED_BYTE, bb); glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + glGenerateMipmap(GL_TEXTURE_3D); v.tex = texture; - v.x = x; - v.y = y; - v.z = z; return v; } private void createProgram() throws IOException { @@ -248,6 +256,7 @@ private void createProgram() throws IOException { mvpUniform = glGetUniformLocation(program, "mvp"); invModelUniform = glGetUniformLocation(program, "invModel"); camPositionUniform = glGetUniformLocation(program, "camPosition"); + sizeUniform = glGetUniformLocation(program, "size"); int texUniform = glGetUniformLocation(program, "tex"); glUniform1i(texUniform, 0); glUseProgram(0); @@ -259,6 +268,7 @@ private void renderVolume(Volume v) { glUniformMatrix4fv(mvpUniform, false, mvpMatrix.get(matrixBuffer)); modelMatrix.invert(invModelMatrix); glUniformMatrix4fv(invModelUniform, false, invModelMatrix.get(matrixBuffer)); + glUniform3f(sizeUniform, v.w, v.h, v.d); glDrawElements(GL_TRIANGLE_STRIP, 14, GL_UNSIGNED_SHORT, 0L); } private void loop() {