Java-Gaming.org Hi !
Featured games (91)
games approved by the League of Dukes
Games in Showcase (798)
Games in Android Showcase (234)
games submitted by our members
Games in WIP (865)
games currently in development
News: Read the Java Gaming Resources, or peek at the official Java tutorials
 
    Home     Help   Search   Login   Register   
Pages: [1]
  ignore  |  Print  
  LWJGL 3: Simple OpenGL 4.3 Compute Shader Ray Tracing  (Read 852 times)
0 Members and 1 Guest are viewing this topic.
Offline KaiHH

JGO Kernel


Medals: 732



« Posted 2019-09-28 22:15:26 »

I wanted to play around a little bit with Java 13 text blocks and thought it would be a good idea to _finally_ have GLSL shader source code literals embedded into Java source code to get a really single-source-file demo.
So here is a simple ray tracing example (static scene, static camera) in under 200 lines of code (Java + GLSL code) (requires JDK13+ with --enable-preview):
1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
13  
14  
15  
16  
17  
18  
19  
20  
21  
22  
23  
24  
25  
26  
27  
28  
29  
30  
31  
32  
33  
34  
35  
36  
37  
38  
39  
40  
41  
42  
43  
44  
45  
46  
47  
48  
49  
50  
51  
52  
53  
54  
55  
56  
57  
58  
59  
60  
61  
62  
63  
64  
65  
66  
67  
68  
69  
70  
71  
72  
73  
74  
75  
76  
77  
78  
79  
80  
81  
82  
83  
84  
85  
86  
87  
88  
89  
90  
91  
92  
93  
94  
95  
96  
97  
98  
99  
100  
101  
102  
103  
104  
105  
106  
107  
108  
109  
110  
111  
112  
113  
114  
115  
116  
117  
118  
119  
120  
121  
122  
123  
124  
125  
126  
127  
128  
129  
130  
131  
132  
133  
134  
135  
136  
137  
138  
139  
140  
141  
142  
143  
144  
145  
146  
147  
148  
149  
150  
151  
152  
153  
154  
155  
156  
157  
158  
159  
160  
161  
162  
163  
164  
165  
166  
167  
168  
169  
170  
171  
172  
173  
174  
175  
176  
177  
178  
179  
180  
181  
182  
183  
184  
185  
186  
187  
188  
import org.lwjgl.glfw.*;
import org.lwjgl.system.*;
import java.nio.ByteBuffer;
import static org.lwjgl.BufferUtils.createByteBuffer;
import static org.lwjgl.glfw.GLFW.*;
import static org.lwjgl.opengl.GL.createCapabilities;
import static org.lwjgl.opengl.GL43C.*;
import static org.lwjgl.opengl.GLUtil.setupDebugMessageCallback;
import static org.lwjgl.system.MemoryUtil.*;

public class Main {
  private static final int WINDOW_WIDTH = 800;
  private static final int WINDOW_HEIGHT = 800;
  private static final String QUAD_PROGRAM_VS_SOURCE = """
#version 430 core
layout(location = 0) in vec2 vertex;
out vec2 texcoord;

void main(void) {
  gl_Position = vec4(vertex, 0.0, 1.0);
  texcoord = vertex * 0.5 + vec2(0.5, 0.5);
}
"
"";
  private static final String QUAD_PROGRAM_FS_SOURCE = """
#version 430 core
uniform sampler2D tex;
in vec2 texcoord;
layout(location = 0) out vec4 color;

void main(void) {
  color = texture2D(tex, texcoord);
}
"
"";
  private static final String COMPUTE_SHADER_SOURCE = """
#version 430 core
layout(binding = 0, rgba8) uniform image2D framebufferImage;
layout(location = 0) uniform vec3 cam[5] = {
  vec3(0.0, 2.0, 5.0), // <- position
  vec3(-1.0, -1.0, -1.0), vec3(-1.0, 1.0, -1.0), // <- left corner directions
  vec3(1.0, -1.0, -1.0), vec3(1.0, 1.0, -1.0) // <- right corner directions
};
struct box {
  vec3 min, max;
};
#define NUM_BOXES 9
const box boxes[NUM_BOXES] = {
  {vec3(-5.0, -0.1, -5.0), vec3(5.0, 0.0, 5.0)},  // <- bottom
  {vec3(-5.1, 0.0, -5.0), vec3(-5.0, 5.0, 5.0)},  // <- left
  {vec3(5.0, 0.0, -5.0), vec3(5.1, 5.0, 5.0)},    // <- right
  {vec3(-5.0, 0.0, -5.1), vec3(5.0, 5.0, -5.0)},  // <- back
  {vec3(-1.0, 1.0, -1.0), vec3(1.0, 1.1, 1.0)},   // <- table top
  {vec3(-1.0, 0.0, -1.0), vec3(-0.8, 1.0, -0.8)}, // <- table foot
  {vec3(-1.0, 0.0,  0.8), vec3(-0.8, 1.0, 1.0)},  // <- table foot
  {vec3(0.8, 0.0, -1.0), vec3(1.0, 1.0, -0.8)},   // <- table foot
  {vec3(0.8, 0.0,  0.8), vec3(1.0, 1.0, 1.0)}     // <- table foot
};
struct hitinfo {
  float near;
  int i;
};
vec2 intersectBox(vec3 origin, vec3 invdir, box b) {
  vec3 tMin = (b.min - origin) * invdir;
  vec3 tMax = (b.max - origin) * invdir;
  vec3 t1 = min(tMin, tMax);
  vec3 t2 = max(tMin, tMax);
  float tNear = max(max(t1.x, t1.y), t1.z);
  float tFar = min(min(t2.x, t2.y), t2.z);
  return vec2(tNear, tFar);
}
bool intersectBoxes(vec3 origin, vec3 invdir, out hitinfo info) {
  float smallest = 1.0/0.0;
  bool found = false;
  for (int i = 0; i < NUM_BOXES; i++) {
    vec2 lambda = intersectBox(origin, invdir, boxes[i]);
    if (lambda.y >= 0.0 && lambda.x < lambda.y && lambda.x < smallest) {
      info.near = lambda.x;
      info.i = i;
      smallest = lambda.x;
      found = true;
    }
  }
  return found;
}
vec3 trace(vec3 origin, vec3 dir) {
  hitinfo hinfo;
  if (!intersectBoxes(origin, 1.0/dir, hinfo))
    return vec3(0.0); // <- nothing hit, return black
  box b = boxes[hinfo.i];
  return vec3(float(hinfo.i+1) / NUM_BOXES);
}
layout(local_size_x = 8, local_size_y = 8) in;
void main(void) {
  ivec2 px = ivec2(gl_GlobalInvocationID.xy);
  ivec2 size = imageSize(framebufferImage);
  if (any(greaterThanEqual(px, size)))
    return;
  vec2 p = (vec2(px) + vec2(0.5)) / vec2(size);
  vec3 dir = mix(mix(cam[1], cam[2], p.y), mix(cam[3], cam[4], p.y), p.x);
  imageStore(framebufferImage, px, vec4(trace(cam[0], normalize(dir)), 1.0));
}
"
"";

  public static void main(String[] args) {
    // Initialize GLFW and create window
    GLFWKeyCallback keyCallback;
    Callback debugProc;
    if (!glfwInit())
      throw new IllegalStateException("Unable to initialize GLFW");
    glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
    glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GLFW_TRUE);
    glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4);
    glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
    glfwWindowHint(GLFW_VISIBLE, GLFW_FALSE);
    glfwWindowHint(GLFW_RESIZABLE, GLFW_FALSE);
    glfwWindowHint(GLFW_OPENGL_DEBUG_CONTEXT, GLFW_TRUE);
    long window = glfwCreateWindow(WINDOW_WIDTH, WINDOW_HEIGHT, "Ray Tracing Tutorial 1", NULL, NULL);
    if (window == NULL)
      throw new AssertionError("Failed to create the GLFW window");
    glfwSetKeyCallback(window, keyCallback = new GLFWKeyCallback() {
      public void invoke(long window, int key, int scancode, int action, int mods) {
        if (action == GLFW_RELEASE && key == GLFW_KEY_ESCAPE)
          glfwSetWindowShouldClose(window, true);
      }
    });

    // Make context current and install debug message callback
    glfwMakeContextCurrent(window);
    createCapabilities();
    debugProc = setupDebugMessageCallback();

    // Create fullscreen quad VAO
    int vao = glGenVertexArrays();
    int vbo = glGenBuffers();
    glBindVertexArray(vao);
    glBindBuffer(GL_ARRAY_BUFFER, vbo);
    ByteBuffer bb = createByteBuffer(Integer.BYTES * 2 * 6);
    bb.asIntBuffer().put(new int[] { -1, -1, 1, -1, 1, 1, 1, 1, -1, 1, -1, -1, });
    glBufferData(GL_ARRAY_BUFFER, bb, GL_STATIC_DRAW);
    glEnableVertexAttribArray(0);
    glVertexAttribPointer(0, 2, GL_INT, false, 0, 0L);

    // Create framebuffer texture to render into
    int framebuffer = glGenTextures();
    glBindTexture(GL_TEXTURE_2D, framebuffer);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
    glTexStorage2D(GL_TEXTURE_2D, 1, GL_RGBA8, WINDOW_WIDTH, WINDOW_HEIGHT);
    glBindImageTexture(0, framebuffer, 0, false, 0, GL_WRITE_ONLY, GL_RGBA8);

    // Create program to render framebuffer texture as fullscreen quad
    int quadProgram = glCreateProgram();
    int quadProgramVs = glCreateShader(GL_VERTEX_SHADER);
    int quadProgramFs = glCreateShader(GL_FRAGMENT_SHADER);
    glShaderSource(quadProgramVs, QUAD_PROGRAM_VS_SOURCE);
    glShaderSource(quadProgramFs, QUAD_PROGRAM_FS_SOURCE);
    glCompileShader(quadProgramVs);
    glCompileShader(quadProgramFs);
    glAttachShader(quadProgram, quadProgramVs);
    glAttachShader(quadProgram, quadProgramFs);
    glLinkProgram(quadProgram);

    // Create ray tracing compute shader
    int computeProgram = glCreateProgram();
    int computeProgramShader = glCreateShader(GL_COMPUTE_SHADER);
    glShaderSource(computeProgramShader, COMPUTE_SHADER_SOURCE);
    glCompileShader(computeProgramShader);
    glAttachShader(computeProgram, computeProgramShader);
    glLinkProgram(computeProgram);
    // Determine number of work groups to dispatch
    int numGroupsX = (int) Math.ceil((double)WINDOW_WIDTH / 8);
    int numGroupsY = (int) Math.ceil((double)WINDOW_HEIGHT / 8);

    // Make window visible and loop until window should be closed
    glfwShowWindow(window);
    while (!glfwWindowShouldClose(window)) {
      glfwPollEvents();

      // Trace the scene
      glUseProgram(computeProgram);
      glDispatchCompute(numGroupsX, numGroupsY, 1);
      glMemoryBarrier(GL_SHADER_IMAGE_ACCESS_BARRIER_BIT);

      // Display framebuffer texture
      glUseProgram(quadProgram);
      glDrawArrays(GL_TRIANGLES, 0, 6);
      glfwSwapBuffers(window);
    }
  }
}
Offline SHC
« Reply #1 - Posted 2019-09-29 03:51:56 »

Though I like the fenced strings, I still miss the stripWithIndent method. The indent strings are removed by default in Java 13 if text blocks are used.

Anyways, I think for stuff like shader source, it is better to keep them in separate files and read them, so I can edit the shaders with an editor that supports syntax highlighting.

Offline KaiHH

JGO Kernel


Medals: 732



« Reply #2 - Posted 2019-09-29 21:00:29 »

Anyways, I think for stuff like shader source, it is better to keep them in separate files and read them, so I can edit the shaders with an editor that supports syntax highlighting.
Even better: use "language injection" in IntelliJ IDEA  Cool
Games published by our own members! Check 'em out!
Legends of Yore - The Casual Retro Roguelike
Offline princec

« JGO Spiffy Duke »


Medals: 1107
Projects: 3
Exp: 20 years


Eh? Who? What? ... Me?


« Reply #3 - Posted 2019-09-29 21:40:23 »

Nice but how does it know what language it is? Does it make a guess?

Cas Smiley

Offline PaulReeves

Junior Devvie


Medals: 3



« Reply #4 - Posted 2019-09-30 12:06:14 »

I think it is a right click and select the language to be highlighted in thing. That is what it is in CLion so I assume it is the same. It is not persisted across editor restarts.
Offline princec

« JGO Spiffy Duke »


Medals: 1107
Projects: 3
Exp: 20 years


Eh? Who? What? ... Me?


« Reply #5 - Posted 2019-09-30 12:44:16 »

What the world needs is what Eclipse has for its autoformatter stuff...

//@formatter:on/off

We could have
//@language:sql
//@language:java11
//@language:glsl1.6
which would automatically highlight multiline strings following in the specified syntax. Wouldn't that be nice.


Cas Smiley

Offline Spasi
« Reply #6 - Posted 2019-09-30 12:51:35 »

See here for options that persist. I've been using text blocks and the annotation on method parameters (e.g. @Language("TSQL") String sql) for a few months now, very happy with how seamless it is (code formatting, auto-complete, navigation, refactorings all work).
Offline PaulReeves

Junior Devvie


Medals: 3



« Reply #7 - Posted 2019-10-01 11:47:12 »

Cool on the persisting part, I had only played with it a bit and not used it a huge amount. The tooling they produce is really rather good.
Pages: [1]
  ignore  |  Print  
 
 

 
Riven (82 views)
2019-09-04 15:33:17

hadezbladez (4338 views)
2018-11-16 13:46:03

hadezbladez (1547 views)
2018-11-16 13:41:33

hadezbladez (4462 views)
2018-11-16 13:35:35

hadezbladez (872 views)
2018-11-16 13:32:03

EgonOlsen (4152 views)
2018-06-10 19:43:48

EgonOlsen (4855 views)
2018-06-10 19:43:44

EgonOlsen (2804 views)
2018-06-10 19:43:20

DesertCoockie (3708 views)
2018-05-13 18:23:11

nelsongames (3999 views)
2018-04-24 18:15:36
Java Gaming Resources
by philfrei
2019-05-14 16:15:13

Deployment and Packaging
by philfrei
2019-05-08 15:15:36

Deployment and Packaging
by philfrei
2019-05-08 15:13:34

Deployment and Packaging
by philfrei
2019-02-17 20:25:53

Deployment and Packaging
by mudlee
2018-08-22 18:09:50

Java Gaming Resources
by gouessej
2018-08-22 08:19:41

Deployment and Packaging
by gouessej
2018-08-22 08:04:08

Deployment and Packaging
by gouessej
2018-08-22 08:03:45
java-gaming.org is not responsible for the content posted by its members, including references to external websites, and other references that may or may not have a relation with our primarily gaming and game production oriented community. inquiries and complaints can be sent via email to the info‑account of the company managing the website of java‑gaming.org
Powered by MySQL Powered by PHP Powered by SMF 1.1.18 | SMF © 2013, Simple Machines | Managed by Enhanced Four Valid XHTML 1.0! Valid CSS!