OpenGL ES SDK for Android ARM Developer Center
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
ocean.cpp
Go to the documentation of this file.
1 /* Copyright (c) 2015-2017, ARM Limited and Contributors
2  *
3  * SPDX-License-Identifier: MIT
4  *
5  * Permission is hereby granted, free of charge,
6  * to any person obtaining a copy of this software and associated documentation files (the "Software"),
7  * to deal in the Software without restriction, including without limitation the rights to
8  * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
9  * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
10  *
11  * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
12  *
13  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
14  * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
16  * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
17  * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
19  */
20 
21 #include <complex>
22 #include <cstdio>
23 #include <cmath>
24 #include <random>
25 
26 #include "fftwater.hpp"
27 #include "scattering.hpp"
28 #include "GLFFT/glfft.hpp"
29 #include "mesh.hpp"
30 #include "common.hpp"
31 
32 #define GLES_VERSION 3
33 #include "Timer.h"
34 #include "Text.h"
35 #include <jni.h>
36 
37 using namespace std;
38 using namespace GLFFT;
39 
40 // Number of samples in heightmap
41 #define SIZE_X 256
42 #define SIZE_Z 256
43 
44 // The size in world space for a heightmap block.
45 #define DIST_X 200.0f
46 #define DIST_Z 200.0f
47 
48 // The high-frequency normal map is sampled for much finer waves.
49 // Make this non-integer so it does not contribute to making the heightmap tiling more apparent.
50 #define NORMALMAP_FREQ_MOD 7.3f
51 #define AMPLITUDE 1.0f
52 
53 // Stormy
54 #define WIND_SPEED_X +26.0f
55 #define WIND_SPEED_Z -22.0f
56 
57 static FFTWater *water;
59 static Mesh *mesh[2];
60 
65 
66 static vec3 cam_pos = vec3(0.0f, 15.0f, 0.0f);
67 static float cam_rot_y = -0.6f, cam_rot_x = -0.1f;
68 static vec3 cam_dir;
69 
70 // Used for frustum culling in mesh.cpp.
71 static void compute_frustum(vec4 *planes, const mat4 &mvp)
72 {
73  // Frustum planes are in world space.
74  mat4 inv = mat_inverse(mvp);
75  // Get world-space coordinates for clip-space bounds.
76  vec4 lbn = inv * vec4(-1, -1, -1, 1);
77  vec4 ltn = inv * vec4(-1, 1, -1, 1);
78  vec4 lbf = inv * vec4(-1, -1, 1, 1);
79  vec4 rbn = inv * vec4( 1, -1, -1, 1);
80  vec4 rtn = inv * vec4( 1, 1, -1, 1);
81  vec4 rbf = inv * vec4( 1, -1, 1, 1);
82  vec4 rtf = inv * vec4( 1, 1, 1, 1);
83 
84  // Divide by w.
85  vec3 lbn_pos = vec_project(lbn);
86  vec3 ltn_pos = vec_project(ltn);
87  vec3 lbf_pos = vec_project(lbf);
88  vec3 rbn_pos = vec_project(rbn);
89  vec3 rtn_pos = vec_project(rtn);
90  vec3 rbf_pos = vec_project(rbf);
91  vec3 rtf_pos = vec_project(rtf);
92 
93  // Get plane normals for all sides of frustum.
94  vec3 left_normal = vec_normalize(vec_cross(lbf_pos - lbn_pos, ltn_pos - lbn_pos));
95  vec3 right_normal = vec_normalize(vec_cross(rtn_pos - rbn_pos, rbf_pos - rbn_pos));
96  vec3 top_normal = vec_normalize(vec_cross(ltn_pos - rtn_pos, rtf_pos - rtn_pos));
97  vec3 bottom_normal = vec_normalize(vec_cross(rbf_pos - rbn_pos, lbn_pos - rbn_pos));
98  vec3 near_normal = vec_normalize(vec_cross(ltn_pos - lbn_pos, rbn_pos - lbn_pos));
99  vec3 far_normal = vec_normalize(vec_cross(rtf_pos - rbf_pos, lbf_pos - rbf_pos));
100 
101  // Plane equations compactly represent a plane in 3D space.
102  // We want a way to compute the distance to the plane while preserving the sign to know which side we're on.
103  // Let:
104  // O: an arbitrary point on the plane
105  // N: the normal vector for the plane, pointing in the direction
106  // we want to be "positive".
107  // X: Position we want to check.
108  //
109  // Distance D to the plane can now be expressed as a simple operation:
110  // D = dot((X - O), N) = dot(X, N) - dot(O, N)
111  //
112  // We can reduce this to one dot product by assuming that X is four-dimensional (4th component = 1.0).
113  // The normal can be extended to four dimensions as well:
114  // X' = vec4(X, 1.0)
115  // N' = vec4(N, -dot(O, N))
116  //
117  // The expression now reduces to: D = dot(X', N')
118  planes[0] = vec4(near_normal, -vec_dot(near_normal, lbn_pos)); // Near
119  planes[1] = vec4(far_normal, -vec_dot(far_normal, lbf_pos)); // Far
120  planes[2] = vec4(left_normal, -vec_dot(left_normal, lbn_pos)); // Left
121  planes[3] = vec4(right_normal, -vec_dot(right_normal, rbn_pos)); // Right
122  planes[4] = vec4(top_normal, -vec_dot(top_normal, ltn_pos)); // Top
123  planes[5] = vec4(bottom_normal, -vec_dot(bottom_normal, lbn_pos)); // Bottom
124 }
125 
126 // Create a VAO for a simple quad.
127 static void init_vao()
128 {
129  GL_CHECK(glGenVertexArrays(1, &vao_quad));
130  GL_CHECK(glBindVertexArray(vao_quad));
131  GL_CHECK(glGenBuffers(1, &vbo_quad));
132  GL_CHECK(glBindBuffer(GL_ARRAY_BUFFER, vbo_quad));
133 
134  static const int8_t quad[] = {
135  -1, -1,
136  1, -1,
137  -1, 1,
138  1, 1,
139  };
140  GL_CHECK(glBufferData(GL_ARRAY_BUFFER, sizeof(quad), quad, GL_STATIC_DRAW));
141  GL_CHECK(glEnableVertexAttribArray(0));
142  GL_CHECK(glVertexAttribPointer(0, 2, GL_BYTE, GL_FALSE, 0, 0));
143  GL_CHECK(glBindVertexArray(0));
144 }
145 
146 static void app_init()
147 {
148  init_vao();
149 
150  mesh[0] = new MorphedGeoMipMapMesh;
151  if (common_has_extension("GL_EXT_tessellation_shader"))
152  {
153  mesh[1] = new TessellatedMesh;
154  }
155 
157  prog_quad = common_compile_shader_from_file("quad.vs", "quad.fs");
158  prog_skydome = common_compile_shader_from_file("skydome.vs", "skydome.fs");
159 
160  // Generate a simple skydome.
161  scatter = new Scattering;
162  vec3 light_dir = vec_normalize(vec3(100.0f, 20.0f, 100.0f));
163  scatter->generate(64, light_dir);
164 }
165 
166 // Move the camera while looking at the sun for a nice scene.
167 static void app_update(float delta_time)
168 {
169  vec3 base_cam_dir = vec3(0.0f, 0.0f, -1.0f);
170 
171  vec3 cam_dir_movement = vec_rotateY(base_cam_dir, PI * 2.0f * cam_rot_y);
172  const vec3 cam_dir_right = vec_rotateY(base_cam_dir, PI * (2.0f * cam_rot_y - 0.5f));
173  cam_pos += vec3(delta_time * 20.0f) * cam_dir_movement;
174  cam_pos += vec3(delta_time * 20.0f) * cam_dir_right;
175 
176  cam_dir = vec_rotateX(base_cam_dir, PI * cam_rot_x);
177  cam_dir = vec_rotateY(cam_dir, PI * 2.0f * cam_rot_y);
178 }
179 
180 static void app_render(unsigned width, unsigned height, float total_time, unsigned mesh_index)
181 {
182  // Update the water textures with FFT.
183  water->update(total_time);
184 
185  auto proj = mat_perspective_fov(60.0f, float(width) / height, 1.0f, 2000.0f);
186  auto view = mat_look_at(cam_pos, cam_pos + cam_dir, vec3(0.0f, 1.0f, 0.0f));
187  auto view_no_translate = mat_look_at(vec3(0.0f), cam_dir, vec3(0.0f, 1.0f, 0.0f));
188 
189  // Clear
190  GL_CHECK(glViewport(0, 0, width, height));
191  GL_CHECK(glClearColor(0.0f, 0.0f, 0.0f, 0.0f));
192  GL_CHECK(glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT));
193 
194  GL_CHECK(glEnable(GL_DEPTH_TEST));
195  GL_CHECK(glDepthFunc(GL_LEQUAL));
196  GL_CHECK(glEnable(GL_CULL_FACE));
197 
198  // Render water
199  Mesh::RenderInfo info;
200  info.mvp = proj * view;
201  info.fft_size = uvec2(SIZE_X, SIZE_Z);
202  info.tile_extent = vec2(DIST_X, DIST_Z);
205  info.cam_pos = cam_pos;
208  info.normal = water->get_normal();
209  info.skydome = scatter->get_texture();
210  info.vp_width = width;
211  info.vp_height = height;
212  compute_frustum(info.frustum, info.mvp);
213 
214  mesh[mesh_index]->render(info);
215 
216  // Render skydome
217  GL_CHECK(glUseProgram(prog_skydome));
218  GL_CHECK(glActiveTexture(GL_TEXTURE0));
219  GL_CHECK(glBindTexture(GL_TEXTURE_CUBE_MAP, scatter->get_texture()));
220  GL_CHECK(glUniformMatrix4fv(0, 1, GL_FALSE, value_ptr(mat_inverse(proj * view_no_translate))));
221  GL_CHECK(glBindVertexArray(vao_quad));
222  GL_CHECK(glDrawArrays(GL_TRIANGLE_STRIP, 0, 4));
223 
224  GL_CHECK(glBindVertexArray(0));
225 }
226 
227 static void app_term()
228 {
229  GL_CHECK(glDeleteBuffers(1, &vbo_quad));
230  GL_CHECK(glDeleteVertexArrays(1, &vao_quad));
231 
232  delete water;
233  water = nullptr;
234  delete scatter;
235  scatter = nullptr;
236  delete mesh[0];
237  delete mesh[1];
238  mesh[0] = nullptr;
239  mesh[1] = nullptr;
240 }
241 
242 extern "C"
243 {
244  static float total_time;
245  static Timer timer;
246  static unsigned phase = 0;
247  static float method_timer = 0.0f;
248  static unsigned surface_width, surface_height;
249  static Text *text;
250 
251  static void render_text(Text &text, const char *method, float current_time)
252  {
253  char method_string[128];
254 
255  // Enable alpha blending.
256  GL_CHECK(glEnable(GL_BLEND));
257  GL_CHECK(glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA));
258 
259  text.clear();
260  text.addString(20, surface_height - 20, "Heightmap Method:", 255, 255, 255, 255);
261  sprintf(method_string, "%s (%4.1f / 10.0 s)", method, current_time);
262  text.addString(20, surface_height - 40, method_string, 255, 255, 255, 255);
263 
264  text.draw();
265  GL_CHECK(glDisable(GL_BLEND));
266  }
267 
269  (JNIEnv *, jclass, jint width, jint height)
270  {
271  common_set_basedir("/data/data/com.arm.malideveloper.openglessdk.ocean/files/");
272 
273  try
274  {
275  app_init();
276  }
277  catch (const exception &e)
278  {
279  LOGE("%s\n", e.what());
280  }
281 
282  delete text;
283  text = new Text("/data/data/com.arm.malideveloper.openglessdk.ocean/files/", width, height);
284 
285  total_time = 0.0f;
286  method_timer = 0.0f;
287  phase = 0;
288  surface_width = width;
289  surface_height = height;
290 
291  timer.reset();
292  }
293 
295  (JNIEnv *, jclass)
296  {
297  float delta_time = timer.getInterval();
298  total_time += delta_time;
299  method_timer += delta_time;
300 
301  app_update(delta_time);
302  app_render(surface_width, surface_height, total_time, phase);
303 
304  static const char *methods[] = {
305  "Continuous LOD Morphing Geo-MipMap",
306  "Tessellation",
307  };
308 
309  render_text(*text, methods[phase], method_timer);
310 
311  if (method_timer > 10.0f)
312  {
313  method_timer = 0.0f;
314  phase = 1 - phase;
315  }
316 
317  // Fallback incase we don't support tessellation.
318  if (!mesh[phase])
319  {
320  phase = 0;
321  }
322 
323  // We don't need depth nor stencil, so just discard them and avoid the extra bandwidth.
324  const GLenum attachments[] = { GL_DEPTH, GL_STENCIL };
325  GL_CHECK(glInvalidateFramebuffer(GL_FRAMEBUFFER, 2, attachments));
326  }
327 
329  (JNIEnv *, jclass)
330  {
331  app_term();
332  delete text;
333  text = nullptr;
334  }
335 }
336 
337 double app_get_time()
338 {
339  return timer.getTime();
340 }
341 
vec2 tile_extent
Definition: mesh.hpp:43
static void app_init()
Definition: ocean.cpp:146
vec3 vec_rotateX(const vec3 &v, float radians)
Definition: vector_math.h:404
static vec3 cam_pos
Definition: ocean.cpp:66
static Text * text
Definition: ocean.cpp:249
#define WIND_SPEED_X
Definition: ocean.cpp:54
float getTime()
Returns the time passed since object creation or since reset() was last called.
Definition: Timer.cpp:109
unsigned vp_width
Definition: mesh.hpp:64
static GLuint prog_quad
Definition: ocean.cpp:61
GLuint height_displacement
Definition: mesh.hpp:52
Functions for drawing text in OpenGL ES.
Definition: Text.h:44
Definition: matrix.h:51
float vec_dot(const T &a, const T &b)
Definition: vector_math.h:289
mat4 mat_look_at(const vec3 &eye, const vec3 &center, const vec3 &up)
Definition: vector_math.h:358
GLint GLsizei GLsizei height
Definition: gl2ext.h:179
Definition: matrix.h:28
float current_time
vec3 vec_cross(const vec3 &a, const vec3 &b)
Definition: vector_math.h:280
GLuint get_normal() const
Definition: fftwater.hpp:108
GLuint common_compile_shader_from_file(const char *vs_source, const char *fs_source)
Definition: common.cpp:241
static FFTWater * water
Definition: ocean.cpp:57
const T::data_type * value_ptr(const T &vec)
Definition: vector_math.h:35
void generate(unsigned size, vec3 sun_dir)
Definition: scattering.cpp:42
static unsigned surface_width
Definition: ocean.cpp:248
Provides a platform independent high resolution timer.
Definition: Timer.h:37
void clear(void)
Removes the current string from the class.
Definition: Text.cpp:142
JNIEXPORT void JNICALL Java_com_arm_malideveloper_openglessdk_ocean_Ocean_step(JNIEnv *, jclass)
Definition: ocean.cpp:295
static Timer timer
Definition: ocean.cpp:245
Definition: matrix.h:75
GLuint normal
Definition: mesh.hpp:58
static Scattering * scatter
Definition: ocean.cpp:58
#define PI
Definition: matrix.h:24
#define WIND_SPEED_Z
Definition: ocean.cpp:55
void common_set_basedir(const char *basedir)
Definition: common.cpp:332
static GLuint prog_skydome
Definition: ocean.cpp:62
static void init_vao()
Definition: ocean.cpp:127
#define DIST_X
Definition: ocean.cpp:45
static unsigned phase
Definition: ocean.cpp:246
static float method_timer
Definition: ocean.cpp:247
Matrix mvp
Definition: Native.cpp:1068
vec3 cam_pos
Definition: mesh.hpp:49
void reset()
Resets the timer to 0.0f.
Definition: Timer.cpp:100
unsigned displacement_downsample
Definition: mesh.hpp:68
Mesh quad
Definition: app.cpp:40
static float total_time
Definition: ocean.cpp:244
static vec3 cam_dir
Definition: ocean.cpp:68
static void compute_frustum(vec4 *planes, const mat4 &mvp)
Definition: ocean.cpp:71
GLfloat GLfloat f
Definition: gl2ext.h:2707
GLuint gradient_jacobian
Definition: mesh.hpp:55
static unsigned surface_height
Definition: ocean.cpp:248
virtual void render(const RenderInfo &info)=0
void addString(int xPosition, int yPosition, const char *string, int red, int green, int blue, int alpha)
Add a std::string to be drawn to the screen.
Definition: Text.cpp:157
static void app_render(unsigned width, unsigned height, float total_time, unsigned mesh_index)
Definition: ocean.cpp:180
GLsizei const GLenum * attachments
Definition: gl2ext.h:1116
unsigned get_displacement_downsample() const
Definition: fftwater.hpp:109
static void app_term()
Definition: ocean.cpp:227
bool common_has_extension(const char *ext)
Definition: common.hpp:57
#define GL_CHECK(x)
Definition: AstcTextures.h:59
GLuint get_texture() const
Definition: scattering.hpp:36
GLuint skydome
Definition: mesh.hpp:61
mat4 mat_perspective_fov(float fovy, float aspect, float zn, float zf)
Definition: vector_math.h:419
#define SIZE_Z
Definition: ocean.cpp:42
static GLuint vao_quad
Definition: ocean.cpp:63
float getInterval()
Returns the time passed since getInterval() was last called.
Definition: Timer.cpp:117
static float cam_rot_x
Definition: ocean.cpp:67
static GLuint vbo_quad
Definition: ocean.cpp:64
vec2 normal_scale
Definition: mesh.hpp:46
vec3 vec_rotateY(const vec3 &v, float radians)
Definition: vector_math.h:409
GLuint get_gradient_jacobian() const
Definition: fftwater.hpp:107
Definition: matrix.h:104
#define NORMALMAP_FREQ_MOD
Definition: ocean.cpp:50
GLuint get_height_displacement() const
Definition: fftwater.hpp:106
mat4 mat_inverse(const mat4 &a)
Definition: vector_math.h:430
unsigned vp_height
Definition: mesh.hpp:65
#define SIZE_X
Definition: ocean.cpp:41
T vec_normalize(const T &vec)
Definition: vector_math.h:304
#define LOGE(...)
Definition: AstcTextures.h:30
static float cam_rot_y
Definition: ocean.cpp:67
JNIEXPORT void JNICALL Java_com_arm_malideveloper_openglessdk_ocean_Ocean_uninit(JNIEnv *, jclass)
Definition: ocean.cpp:329
GLint GLsizei width
Definition: gl2ext.h:179
JNIEXPORT void JNICALL Java_com_arm_malideveloper_openglessdk_ocean_Ocean_init(JNIEnv *, jclass, jint width, jint height)
Definition: ocean.cpp:269
typedef GLenum(GL_APIENTRYP PFNGLGETGRAPHICSRESETSTATUSKHRPROC)(void)
detail::ivec2< uint32_t > uvec2
Definition: vector_math.h:90
#define AMPLITUDE
Definition: ocean.cpp:51
static Mesh * mesh[2]
Definition: ocean.cpp:59
static void app_update(float delta_time)
Definition: ocean.cpp:167
#define DIST_Z
Definition: ocean.cpp:46
vec3 vec_project(const vec4 &vec)
Definition: vector_math.h:333
void draw(void)
Draw the text to the screen.
Definition: Text.cpp:265
typedef GLuint(GL_APIENTRYP PFNGLGETDEBUGMESSAGELOGKHRPROC)(GLuint count
vec4 frustum[6]
Definition: mesh.hpp:37
void update(float time)
Definition: fftwater.cpp:226
double app_get_time()
Definition: ocean.cpp:337
static void render_text(Text &text, const char *method, float current_time)
Definition: ocean.cpp:251
uvec2 fft_size
Definition: mesh.hpp:40