Compare commits
No commits in common. "010b41d3526c33ebc7866ee84d9bcc3470c96b74" and "085afd2a664f44cdef746ea556b55564460c25fa" have entirely different histories.
010b41d352
...
085afd2a66
27 changed files with 237 additions and 177 deletions
2
.gitignore
vendored
2
.gitignore
vendored
|
@ -1,2 +1,2 @@
|
||||||
cmake-build-*/
|
cmake-build-*/
|
||||||
.idea/
|
.idea/workspace.xml
|
||||||
|
|
1
.idea/.name
generated
Normal file
1
.idea/.name
generated
Normal file
|
@ -0,0 +1 @@
|
||||||
|
perlin-shadows
|
13
.idea/codeStyles/Project.xml
generated
Normal file
13
.idea/codeStyles/Project.xml
generated
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
<component name="ProjectCodeStyleConfiguration">
|
||||||
|
<code_scheme name="Project" version="173">
|
||||||
|
<clangFormatSettings>
|
||||||
|
<option name="ENABLED" value="true" />
|
||||||
|
</clangFormatSettings>
|
||||||
|
<editorconfig>
|
||||||
|
<option name="ENABLED" value="false" />
|
||||||
|
</editorconfig>
|
||||||
|
<codeStyleSettings language="Glsl">
|
||||||
|
<option name="SPACE_BEFORE_COLON" value="false" />
|
||||||
|
</codeStyleSettings>
|
||||||
|
</code_scheme>
|
||||||
|
</component>
|
5
.idea/codeStyles/codeStyleConfig.xml
generated
Normal file
5
.idea/codeStyles/codeStyleConfig.xml
generated
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
<component name="ProjectCodeStyleConfiguration">
|
||||||
|
<state>
|
||||||
|
<option name="USE_PER_PROJECT_SETTINGS" value="true" />
|
||||||
|
</state>
|
||||||
|
</component>
|
2
.idea/f.iml
generated
Normal file
2
.idea/f.iml
generated
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<module classpath="CMake" type="CPP_MODULE" version="4" />
|
14
.idea/inspectionProfiles/Project_Default.xml
generated
Normal file
14
.idea/inspectionProfiles/Project_Default.xml
generated
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
<component name="InspectionProjectProfileManager">
|
||||||
|
<profile version="1.0">
|
||||||
|
<option name="myName" value="Project Default" />
|
||||||
|
<inspection_tool class="PyPep8NamingInspection" enabled="true" level="WEAK WARNING" enabled_by_default="true">
|
||||||
|
<option name="ignoredErrors">
|
||||||
|
<list>
|
||||||
|
<option value="N802" />
|
||||||
|
<option value="N803" />
|
||||||
|
<option value="N806" />
|
||||||
|
</list>
|
||||||
|
</option>
|
||||||
|
</inspection_tool>
|
||||||
|
</profile>
|
||||||
|
</component>
|
4
.idea/misc.xml
generated
Normal file
4
.idea/misc.xml
generated
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="CMakeWorkspace" PROJECT_DIR="$PROJECT_DIR$" />
|
||||||
|
</project>
|
8
.idea/modules.xml
generated
Normal file
8
.idea/modules.xml
generated
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="ProjectModuleManager">
|
||||||
|
<modules>
|
||||||
|
<module fileurl="file://$PROJECT_DIR$/.idea/f.iml" filepath="$PROJECT_DIR$/.idea/f.iml" />
|
||||||
|
</modules>
|
||||||
|
</component>
|
||||||
|
</project>
|
6
.idea/vcs.xml
generated
Normal file
6
.idea/vcs.xml
generated
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="VcsDirectoryMappings">
|
||||||
|
<mapping directory="" vcs="Git" />
|
||||||
|
</component>
|
||||||
|
</project>
|
|
@ -26,14 +26,3 @@ add_executable(perlin-shadows
|
||||||
src/renderable.cpp
|
src/renderable.cpp
|
||||||
src/renderable.h
|
src/renderable.h
|
||||||
)
|
)
|
||||||
|
|
||||||
file(READ src/phong.vert PHONG_VERT)
|
|
||||||
file(READ src/phong.frag PHONG_FRAG)
|
|
||||||
configure_file(src/renderer.in.cpp src/renderer.cpp @ONLY)
|
|
||||||
|
|
||||||
file(READ src/shadow.vert SHADOW_VERT)
|
|
||||||
file(READ src/shadow.frag SHADOW_FRAG)
|
|
||||||
file(READ src/shadow.geom SHADOW_GEOM)
|
|
||||||
configure_file(src/point_light.in.h src/point_light.h @ONLY)
|
|
||||||
|
|
||||||
target_include_directories(perlin-shadows PUBLIC "${CMAKE_CURRENT_BINARY_DIR}/src")
|
|
|
@ -2,6 +2,13 @@
|
||||||
|
|
||||||
Generates several tiles of grids containing Perlin noise, and then renders them with shadows.
|
Generates several tiles of grids containing Perlin noise, and then renders them with shadows.
|
||||||
|
|
||||||
|
## Running
|
||||||
|
|
||||||
|
The shader files (`src/*.{frag,vert,geom}`) are referenced within the code by assuming they are located in the current
|
||||||
|
working directory.
|
||||||
|
It is therefore necessary to set the CWD when running the program to the `src/` directory, or copy/symlink the files to
|
||||||
|
whatever your actual CWD is.
|
||||||
|
|
||||||
## Control
|
## Control
|
||||||
|
|
||||||
Sample from console output:
|
Sample from console output:
|
||||||
|
|
|
@ -5,9 +5,9 @@
|
||||||
|
|
||||||
using namespace std;
|
using namespace std;
|
||||||
|
|
||||||
void Camera::LoadMatrices(const Shader *shader) const {
|
void Camera::LoadMatrices(Shader *shader) const {
|
||||||
const auto viewMatrix =
|
const auto viewMatrix =
|
||||||
lookAt(position_, position_ + look_vector(), up_vector());
|
glm::lookAt(position_, position_ + look_vector(), up_vector());
|
||||||
if (!shader->CopyDataToUniform(viewMatrix, "view")) {
|
if (!shader->CopyDataToUniform(viewMatrix, "view")) {
|
||||||
cerr << "View matrix not in shader" << endl;
|
cerr << "View matrix not in shader" << endl;
|
||||||
}
|
}
|
||||||
|
@ -22,7 +22,5 @@ void Camera::LoadMatrices(const Shader *shader) const {
|
||||||
cerr << "Camera position not in shader" << endl;
|
cerr << "Camera position not in shader" << endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!shader->CopyDataToUniform(kFarPlane, "farPlane")) {
|
shader->CopyDataToUniform(kFarPlane, "farPlane");
|
||||||
cerr << "Far plane not in shader" << endl;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
27
src/camera.h
27
src/camera.h
|
@ -1,5 +1,6 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <glm/ext/matrix_transform.hpp>
|
||||||
#include <glm/gtc/constants.hpp>
|
#include <glm/gtc/constants.hpp>
|
||||||
#define GLM_ENABLE_EXPERIMENTAL
|
#define GLM_ENABLE_EXPERIMENTAL
|
||||||
#include <glm/gtx/rotate_vector.hpp>
|
#include <glm/gtx/rotate_vector.hpp>
|
||||||
|
@ -13,29 +14,33 @@ class Camera {
|
||||||
set_aspect(width, height);
|
set_aspect(width, height);
|
||||||
}
|
}
|
||||||
|
|
||||||
void LoadMatrices(const Shader *shader) const;
|
void LoadMatrices(Shader *shader) const;
|
||||||
|
|
||||||
void RelativeRotate(const glm::vec3 amount) { rotation_ += amount; }
|
inline void RelativeRotate(const glm::vec3 amount) { rotation_ += amount; }
|
||||||
void RelativeMove(const glm::vec3 amount) {
|
inline void RelativeMove(const glm::vec3 amount) {
|
||||||
position_ += amount.x * look_vector() + amount.y * normal_vector() +
|
position_ += amount.x * look_vector() + amount.y * normal_vector() +
|
||||||
amount.z * up_vector();
|
amount.z * up_vector();
|
||||||
}
|
}
|
||||||
void AbsoluteMove(const glm::vec3 amount) { position_ += amount; }
|
inline void AbsoluteMove(const glm::vec3 amount) { position_ += amount; }
|
||||||
|
|
||||||
void set_aspect(const int width, const int height) {
|
inline void set_aspect(const int width, const int height) {
|
||||||
aspect_ = static_cast<float>(width) / static_cast<float>(height);
|
aspect_ = static_cast<float>(width) / static_cast<float>(height);
|
||||||
}
|
}
|
||||||
|
|
||||||
const glm::vec3 &getPosition() const { return position_; }
|
inline const glm::vec3 &getPosition() const { return position_; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
glm::vec3 look_vector() const {
|
inline glm::vec3 look_vector() const {
|
||||||
return rotateZ(rotateY(glm::vec3(1., 0., 0.), rotation_.y), rotation_.z);
|
return glm::rotateZ(glm::rotateY(glm::vec3(1., 0., 0.), rotation_.y),
|
||||||
|
rotation_.z);
|
||||||
}
|
}
|
||||||
glm::vec3 up_vector() const {
|
inline glm::vec3 up_vector() const {
|
||||||
return rotateZ(rotateY(glm::vec3(0., 0., 1.), rotation_.y), rotation_.z);
|
return glm::rotateZ(glm::rotateY(glm::vec3(0., 0., 1.), rotation_.y),
|
||||||
|
rotation_.z);
|
||||||
|
}
|
||||||
|
inline glm::vec3 normal_vector() const {
|
||||||
|
return glm::cross(up_vector(), look_vector());
|
||||||
}
|
}
|
||||||
glm::vec3 normal_vector() const { return cross(up_vector(), look_vector()); }
|
|
||||||
|
|
||||||
glm::vec3 position_{kGeographyShort / 2,
|
glm::vec3 position_{kGeographyShort / 2,
|
||||||
kGeographyLong *kGeographyCountLong / 2,
|
kGeographyLong *kGeographyCountLong / 2,
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
|
|
||||||
using namespace std;
|
using namespace std;
|
||||||
|
|
||||||
int main(const int argc, char *argv[]) {
|
int main(int argc, char *argv[]) {
|
||||||
try {
|
try {
|
||||||
Renderer(argc, argv);
|
Renderer(argc, argv);
|
||||||
} catch (const runtime_error &error) {
|
} catch (const runtime_error &error) {
|
||||||
|
|
|
@ -9,10 +9,9 @@
|
||||||
|
|
||||||
using namespace std;
|
using namespace std;
|
||||||
|
|
||||||
Geography::Geography(const int x, const int y)
|
Geography::Geography(int x, int y) : Renderable(true), x_(x), y_(y) {
|
||||||
: Renderable(true), x_(x), y_(y) {
|
|
||||||
Randomize(false);
|
Randomize(false);
|
||||||
model_ = translate(
|
model_ = glm::translate(
|
||||||
glm::identity<glm::mat4>(),
|
glm::identity<glm::mat4>(),
|
||||||
glm::vec3(x * (kGeographyShort - 1), y * (kGeographyLong - 1), 0));
|
glm::vec3(x * (kGeographyShort - 1), y * (kGeographyLong - 1), 0));
|
||||||
}
|
}
|
||||||
|
@ -21,19 +20,19 @@ Geography::~Geography() { CleanUp(); }
|
||||||
|
|
||||||
// Sums Perlin noise on a variety of factors, then stores the result in results
|
// Sums Perlin noise on a variety of factors, then stores the result in results
|
||||||
// Note: Frees factors
|
// Note: Frees factors
|
||||||
void CalculatePerlinNoise(queue<Grid *> *results, const int x, const int y,
|
void CalculatePerlinNoise(queue<Grid *> *results, int x, int y,
|
||||||
vector<size_t> *factors) {
|
vector<size_t> *factors) {
|
||||||
const auto grid = new Grid();
|
auto grid = new Grid();
|
||||||
for (const auto factor : *factors) {
|
for (const auto factor : *factors) {
|
||||||
const auto noise = Grid::PerlinNoise(x, y, kDetail >> factor);
|
const auto noise = Grid::PerlinNoise(x, y, kDetail >> factor);
|
||||||
*grid += *noise / static_cast<float>(1 << factor);
|
(*grid) += (*noise) / static_cast<float>(1 << factor);
|
||||||
delete noise;
|
delete noise;
|
||||||
}
|
}
|
||||||
results->push(grid);
|
results->push(grid);
|
||||||
delete factors;
|
delete factors;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Geography::Randomize(const bool load) {
|
void Geography::Randomize(bool load) {
|
||||||
if (load) {
|
if (load) {
|
||||||
CleanUp();
|
CleanUp();
|
||||||
}
|
}
|
||||||
|
@ -44,7 +43,7 @@ void Geography::Randomize(const bool load) {
|
||||||
// Set up one thread for each noise scale
|
// Set up one thread for each noise scale
|
||||||
for (size_t i = 0; i < kMaxThreads; ++i) {
|
for (size_t i = 0; i < kMaxThreads; ++i) {
|
||||||
auto factors = new vector<size_t>();
|
auto factors = new vector<size_t>();
|
||||||
for (size_t factor = 0; kDetail >> factor > kMinDetail;
|
for (size_t factor = 0; (kDetail >> factor) > kMinDetail;
|
||||||
factor += kMaxThreads) {
|
factor += kMaxThreads) {
|
||||||
factors->push_back(factor + i);
|
factors->push_back(factor + i);
|
||||||
}
|
}
|
||||||
|
@ -59,7 +58,7 @@ void Geography::Randomize(const bool load) {
|
||||||
|
|
||||||
// Add up all noise levels
|
// Add up all noise levels
|
||||||
while (!results.empty()) {
|
while (!results.empty()) {
|
||||||
const auto grid = results.front();
|
auto grid = results.front();
|
||||||
height_ += *grid;
|
height_ += *grid;
|
||||||
delete grid;
|
delete grid;
|
||||||
results.pop();
|
results.pop();
|
||||||
|
|
|
@ -1,17 +1,19 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <GL/glew.h>
|
||||||
|
|
||||||
#include "grid.h"
|
#include "grid.h"
|
||||||
#include "renderable.h"
|
#include "renderable.h"
|
||||||
|
|
||||||
class Geography final : public Renderable {
|
class Geography : public Renderable {
|
||||||
public:
|
public:
|
||||||
Geography(int x, int y);
|
Geography(int x, int y);
|
||||||
~Geography() override;
|
~Geography();
|
||||||
|
|
||||||
void Randomize(bool);
|
void Randomize(bool);
|
||||||
|
|
||||||
float min() const { return height_.min(); }
|
inline float min() const { return height_.min(); }
|
||||||
float max() const { return height_.max(); }
|
inline float max() const { return height_.max(); }
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void SetData() override;
|
void SetData() override;
|
||||||
|
|
48
src/grid.cpp
48
src/grid.cpp
|
@ -20,7 +20,7 @@ Grid Grid::operator+(const Grid &other) const {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Grid::operator+=(const Grid &other) const {
|
void Grid::operator+=(const Grid &other) {
|
||||||
for (size_t i = 0; i < data_->size(); ++i) {
|
for (size_t i = 0; i < data_->size(); ++i) {
|
||||||
(*data_)[i] += (*other.data_)[i];
|
(*data_)[i] += (*other.data_)[i];
|
||||||
}
|
}
|
||||||
|
@ -30,7 +30,7 @@ Grid Grid::operator-() const { return operator*(-1); }
|
||||||
|
|
||||||
Grid Grid::operator-(const Grid &other) const { return operator+(-other); }
|
Grid Grid::operator-(const Grid &other) const { return operator+(-other); }
|
||||||
|
|
||||||
void Grid::operator-=(const Grid &other) const { operator+=(-other); }
|
void Grid::operator-=(const Grid &other) { operator+=(-other); }
|
||||||
|
|
||||||
Grid Grid::operator*(const float val) const {
|
Grid Grid::operator*(const float val) const {
|
||||||
Grid result;
|
Grid result;
|
||||||
|
@ -40,7 +40,7 @@ Grid Grid::operator*(const float val) const {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Grid::operator*=(const float val) const {
|
void Grid::operator*=(const float val) {
|
||||||
for (size_t i = 0; i < data_->size(); ++i) {
|
for (size_t i = 0; i < data_->size(); ++i) {
|
||||||
(*data_)[i] *= val;
|
(*data_)[i] *= val;
|
||||||
}
|
}
|
||||||
|
@ -48,7 +48,7 @@ void Grid::operator*=(const float val) const {
|
||||||
|
|
||||||
Grid Grid::operator/(const float val) const { return operator*(1 / val); }
|
Grid Grid::operator/(const float val) const { return operator*(1 / val); }
|
||||||
|
|
||||||
void Grid::operator/=(const float val) const { operator*=(1 / val); }
|
void Grid::operator/=(const float val) { operator*=(1 / val); }
|
||||||
|
|
||||||
glm::vec3 Grid::normal_at(const size_t x, const size_t y,
|
glm::vec3 Grid::normal_at(const size_t x, const size_t y,
|
||||||
const float amplification) const {
|
const float amplification) const {
|
||||||
|
@ -63,37 +63,36 @@ glm::vec3 Grid::normal_at(const size_t x, const size_t y,
|
||||||
const auto y_diff =
|
const auto y_diff =
|
||||||
glm::vec3(0, static_cast<float>(high_y - low_y),
|
glm::vec3(0, static_cast<float>(high_y - low_y),
|
||||||
amplification * (get(x, high_y) - get(x, low_y)));
|
amplification * (get(x, high_y) - get(x, low_y)));
|
||||||
return normalize(cross(x_diff, y_diff));
|
return glm::normalize(glm::cross(x_diff, y_diff));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Implementation based on: https://en.wikipedia.org/wiki/Perlin_noise
|
// Implementation based on: https://en.wikipedia.org/wiki/Perlin_noise
|
||||||
// Assumes that kGeographyShort and kGeographyLong are equal to 2^n (doesn't
|
// Assumes that kGeographyShort and kGeographyLong are equal to 2^n (doesn't
|
||||||
// have to be the same n)
|
// have to be the same n)
|
||||||
Grid *Grid::PerlinNoise(const int globalX, const int globalY,
|
Grid *Grid::PerlinNoise(int globalX, int globalY, std::size_t detail) {
|
||||||
const std::size_t detail) {
|
auto grid = new Grid();
|
||||||
const auto grid = new Grid();
|
|
||||||
|
|
||||||
// Store the vectors at grid corners as just angles, they're all normalised
|
// Store the vectors at grid corners as just angles, they're all normalised
|
||||||
const size_t major_width = kGeographyShort / detail + 1;
|
const size_t major_width = (kGeographyShort / detail) + 1;
|
||||||
const size_t major_length = kGeographyLong / detail + 1;
|
const size_t major_length = (kGeographyLong / detail) + 1;
|
||||||
const size_t grid_nodes = major_width * major_length;
|
const size_t grid_nodes = major_width * major_length;
|
||||||
vector<float> sin_major_angles(grid_nodes);
|
vector<float> sin_major_angles(grid_nodes);
|
||||||
vector<float> cos_major_angles(grid_nodes);
|
vector<float> cos_major_angles(grid_nodes);
|
||||||
|
|
||||||
const auto worldIndexX = (major_width - 1) * globalX;
|
auto worldIndexX = (major_width - 1) * globalX;
|
||||||
const auto worldIndexY = ((major_width - 1) * kGeographyCountShort + 1) *
|
auto worldIndexY = ((major_width - 1) * kGeographyCountShort + 1) *
|
||||||
(major_length - 1) * globalY;
|
(major_length - 1) * globalY;
|
||||||
const auto worldIndex = worldIndexX + worldIndexY;
|
auto worldIndex = worldIndexX + worldIndexY;
|
||||||
const mt19937::result_type gridBaseSeed = base_random_ * detail + worldIndex;
|
mt19937::result_type gridBaseSeed = base_random_ * detail + worldIndex;
|
||||||
|
|
||||||
// Randomly generates corner vector angles [0, 2pi)
|
// Randomly generates corner vector angles [0, 2pi)
|
||||||
for (size_t x = 0; x < major_width; ++x) {
|
for (size_t x = 0; x < major_width; ++x) {
|
||||||
for (size_t y = 0; y < major_width; ++y) {
|
for (size_t y = 0; y < major_width; ++y) {
|
||||||
const auto relativeWorldIndex =
|
auto relativeWorldIndex =
|
||||||
x + ((major_width - 1) * kGeographyCountShort + 1) * y;
|
x + ((major_width - 1) * kGeographyCountShort + 1) * y;
|
||||||
grid->AngleSeed(gridBaseSeed + relativeWorldIndex);
|
grid->AngleSeed(gridBaseSeed + relativeWorldIndex);
|
||||||
const auto angle = grid->RandomAngle();
|
auto angle = grid->RandomAngle();
|
||||||
const auto i = x + major_width * y;
|
auto i = x + major_width * y;
|
||||||
sin_major_angles[i] = sin(angle);
|
sin_major_angles[i] = sin(angle);
|
||||||
cos_major_angles[i] = cos(angle);
|
cos_major_angles[i] = cos(angle);
|
||||||
}
|
}
|
||||||
|
@ -120,8 +119,7 @@ Grid *Grid::PerlinNoise(const int globalX, const int globalY,
|
||||||
// Lambda to determine the dot product of the offset vector of the current
|
// Lambda to determine the dot product of the offset vector of the current
|
||||||
// point with one of the four grid vectors around the current point
|
// point with one of the four grid vectors around the current point
|
||||||
const auto dot_major = [=, &cos_major_angles, &sin_major_angles](
|
const auto dot_major = [=, &cos_major_angles, &sin_major_angles](
|
||||||
const bool high_x,
|
bool high_x, bool high_y) -> float {
|
||||||
const bool high_y) -> float {
|
|
||||||
const auto major_x = lower_major_x + (high_x ? 1 : 0);
|
const auto major_x = lower_major_x + (high_x ? 1 : 0);
|
||||||
const auto major_y = lower_major_y + (high_y ? 1 : 0);
|
const auto major_y = lower_major_y + (high_y ? 1 : 0);
|
||||||
const auto sin_major_angle =
|
const auto sin_major_angle =
|
||||||
|
@ -149,12 +147,12 @@ Grid *Grid::PerlinNoise(const int globalX, const int globalY,
|
||||||
}
|
}
|
||||||
|
|
||||||
array<Vertex, kTotalVertices> *Grid::vertices() const {
|
array<Vertex, kTotalVertices> *Grid::vertices() const {
|
||||||
const auto vertices = new array<Vertex, kTotalVertices>();
|
auto vertices = new array<Vertex, kTotalVertices>();
|
||||||
for (size_t x = 0; x < kGeographyShort; ++x) {
|
for (size_t x = 0; x < kGeographyShort; ++x) {
|
||||||
for (size_t y = 0; y < kGeographyLong; ++y) {
|
for (size_t y = 0; y < kGeographyLong; ++y) {
|
||||||
const auto ind = index(x, y);
|
auto ind = index(x, y);
|
||||||
const glm::vec3 position = {x, y, (*data_)[ind]};
|
glm::vec3 position = {x, y, (*data_)[ind]};
|
||||||
const glm::vec3 normal = normal_at(x, y);
|
glm::vec3 normal = normal_at(x, y);
|
||||||
(*vertices)[ind] = {position, normal};
|
(*vertices)[ind] = {position, normal};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -162,10 +160,10 @@ array<Vertex, kTotalVertices> *Grid::vertices() const {
|
||||||
}
|
}
|
||||||
|
|
||||||
array<unsigned int, kTotalIndices> *Grid::indices() {
|
array<unsigned int, kTotalIndices> *Grid::indices() {
|
||||||
const auto indices = new array<unsigned int, kTotalIndices>();
|
auto indices = new array<unsigned int, kTotalIndices>();
|
||||||
for (size_t x = 0; x < kGeographyShort - 1; ++x) {
|
for (size_t x = 0; x < kGeographyShort - 1; ++x) {
|
||||||
for (size_t y = 0; y < kGeographyLong - 1; ++y) {
|
for (size_t y = 0; y < kGeographyLong - 1; ++y) {
|
||||||
const auto indexInd = (x + y * (kGeographyShort - 1)) * 6;
|
auto indexInd = (x + y * (kGeographyShort - 1)) * 6;
|
||||||
(*indices)[indexInd] = static_cast<int>(index(x, y));
|
(*indices)[indexInd] = static_cast<int>(index(x, y));
|
||||||
(*indices)[indexInd + 1] = static_cast<int>(index(x, y + 1));
|
(*indices)[indexInd + 1] = static_cast<int>(index(x, y + 1));
|
||||||
(*indices)[indexInd + 2] = static_cast<int>(index(x + 1, y));
|
(*indices)[indexInd + 2] = static_cast<int>(index(x + 1, y));
|
||||||
|
|
27
src/grid.h
27
src/grid.h
|
@ -9,6 +9,7 @@
|
||||||
#include <random>
|
#include <random>
|
||||||
|
|
||||||
#include "constants.h"
|
#include "constants.h"
|
||||||
|
#include "noise_math.h"
|
||||||
#include "shader.h"
|
#include "shader.h"
|
||||||
|
|
||||||
constexpr std::size_t index(const std::size_t x, const std::size_t y) {
|
constexpr std::size_t index(const std::size_t x, const std::size_t y) {
|
||||||
|
@ -17,22 +18,22 @@ constexpr std::size_t index(const std::size_t x, const std::size_t y) {
|
||||||
|
|
||||||
class Grid {
|
class Grid {
|
||||||
public:
|
public:
|
||||||
float get(const std::size_t x, const std::size_t y) const {
|
inline float get(const std::size_t x, const std::size_t y) const {
|
||||||
return (*data_)[index(x, y)];
|
return (*data_)[index(x, y)];
|
||||||
}
|
}
|
||||||
void set(const std::size_t x, const std::size_t y, const float value) const {
|
inline void set(const std::size_t x, const std::size_t y, float value) {
|
||||||
(*data_)[index(x, y)] = value;
|
(*data_)[index(x, y)] = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
Grid operator+(const Grid &) const;
|
Grid operator+(const Grid &) const;
|
||||||
void operator+=(const Grid &) const;
|
void operator+=(const Grid &);
|
||||||
Grid operator-() const;
|
Grid operator-() const;
|
||||||
Grid operator-(const Grid &) const;
|
Grid operator-(const Grid &) const;
|
||||||
void operator-=(const Grid &) const;
|
void operator-=(const Grid &);
|
||||||
Grid operator*(float) const;
|
Grid operator*(float) const;
|
||||||
void operator*=(float) const;
|
void operator*=(float);
|
||||||
Grid operator/(float) const;
|
Grid operator/(float) const;
|
||||||
void operator/=(float) const;
|
void operator/=(float);
|
||||||
|
|
||||||
glm::vec3 normal_at(std::size_t, std::size_t, float = 1.) const;
|
glm::vec3 normal_at(std::size_t, std::size_t, float = 1.) const;
|
||||||
|
|
||||||
|
@ -40,10 +41,14 @@ class Grid {
|
||||||
|
|
||||||
std::array<Vertex, kTotalVertices> *vertices() const;
|
std::array<Vertex, kTotalVertices> *vertices() const;
|
||||||
static std::array<unsigned int, kTotalIndices> *indices();
|
static std::array<unsigned int, kTotalIndices> *indices();
|
||||||
static void RandomizeBase() { base_random_ = device_() << 4; }
|
static inline void RandomizeBase() { base_random_ = device_() << 4; }
|
||||||
|
|
||||||
float min() const { return *std::min_element(data_->begin(), data_->end()); }
|
inline float min() const {
|
||||||
float max() const { return *std::max_element(data_->begin(), data_->end()); }
|
return *std::min_element(data_->begin(), data_->end());
|
||||||
|
}
|
||||||
|
inline float max() const {
|
||||||
|
return *std::max_element(data_->begin(), data_->end());
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::unique_ptr<std::array<float, kGeographyShort * kGeographyLong>> data_{
|
std::unique_ptr<std::array<float, kGeographyShort * kGeographyLong>> data_{
|
||||||
|
@ -54,6 +59,6 @@ class Grid {
|
||||||
std::uniform_real_distribution<float> dist_{0, glm::two_pi<float>()};
|
std::uniform_real_distribution<float> dist_{0, glm::two_pi<float>()};
|
||||||
static std::mt19937::result_type base_random_;
|
static std::mt19937::result_type base_random_;
|
||||||
|
|
||||||
float RandomAngle() { return dist_(engine_); }
|
inline float RandomAngle() { return dist_(engine_); }
|
||||||
void AngleSeed(const std::mt19937::result_type seed) { engine_.seed(seed); }
|
inline void AngleSeed(std::mt19937::result_type seed) { engine_.seed(seed); }
|
||||||
};
|
};
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
// Based on Ken Perlin's smoother step function:
|
// Based on Ken Perlin's smoother step function:
|
||||||
// https://en.wikipedia.org/wiki/Smoothstep#Variations Returns value in range
|
// https://en.wikipedia.org/wiki/Smoothstep#Variations Returns value in range
|
||||||
// [0, 1]
|
// [0, 1]
|
||||||
constexpr float SmootherStep(const float x) {
|
inline constexpr float SmootherStep(const float x) {
|
||||||
if (x < 0) {
|
if (x < 0) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -17,7 +17,7 @@ constexpr float SmootherStep(const float x) {
|
||||||
// Interpolates between two doubles
|
// Interpolates between two doubles
|
||||||
// If x <= 0 returns bound_0, if x >= 1 returns bound_1,
|
// If x <= 0 returns bound_0, if x >= 1 returns bound_1,
|
||||||
// otherwise smoothly transitions between the two
|
// otherwise smoothly transitions between the two
|
||||||
constexpr float Interpolate(const float x, const float bound_0,
|
inline constexpr float Interpolate(const float x, const float bound_0,
|
||||||
const float bound_1) {
|
const float bound_1) {
|
||||||
return bound_0 + SmootherStep(x) * (bound_1 - bound_0);
|
return bound_0 + SmootherStep(x) * (bound_1 - bound_0);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
#include "point_light.h"
|
#include "point_light.h"
|
||||||
|
|
||||||
#include <array>
|
|
||||||
#include <glm/ext/matrix_clip_space.hpp>
|
#include <glm/ext/matrix_clip_space.hpp>
|
||||||
#include <glm/ext/matrix_transform.hpp>
|
#include <glm/ext/matrix_transform.hpp>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
@ -48,7 +47,7 @@ PointLight::~PointLight() {
|
||||||
glDeleteFramebuffers(1, &fbo_);
|
glDeleteFramebuffers(1, &fbo_);
|
||||||
}
|
}
|
||||||
|
|
||||||
void PointLight::LoadData(const Shader *shader) const {
|
void PointLight::LoadData(Shader *shader) const {
|
||||||
if (!shader->CopyDataToUniform(ambient_, "pointLight.ambient")) {
|
if (!shader->CopyDataToUniform(ambient_, "pointLight.ambient")) {
|
||||||
cerr << "Point light ambient not loaded to shader" << endl;
|
cerr << "Point light ambient not loaded to shader" << endl;
|
||||||
}
|
}
|
||||||
|
@ -72,44 +71,37 @@ void PointLight::GenerateCubeMaps(
|
||||||
// https://learnopengl.com/Advanced-Lighting/Shadows/Point-Shadows
|
// https://learnopengl.com/Advanced-Lighting/Shadows/Point-Shadows
|
||||||
// By Joey de Vries (https://twitter.com/JoeyDeVriez)
|
// By Joey de Vries (https://twitter.com/JoeyDeVriez)
|
||||||
// CC BY 4.0 (https://creativecommons.org/licenses/by/4.0/legalcode)
|
// CC BY 4.0 (https://creativecommons.org/licenses/by/4.0/legalcode)
|
||||||
const auto shadowProj =
|
auto shadowProj =
|
||||||
glm::perspective(glm::pi<float>() / 2, 1.0f, kNearPlane, kFarPlane);
|
glm::perspective(glm::pi<float>() / 2, 1.0f, kNearPlane, kFarPlane);
|
||||||
|
|
||||||
auto shadowTransforms = array<glm::mat4, 6>();
|
auto shadowTransforms = array<glm::mat4, 6>();
|
||||||
shadowTransforms[0] =
|
shadowTransforms[0] =
|
||||||
shadowProj *
|
shadowProj * glm::lookAt(pos_, pos_ + glm::vec3(1.0, 0.0, 0.0),
|
||||||
lookAt(pos_, pos_ + glm::vec3(1.0, 0.0, 0.0), glm::vec3(0.0, -1.0, 0.0));
|
glm::vec3(0.0, -1.0, 0.0));
|
||||||
shadowTransforms[1] =
|
shadowTransforms[1] =
|
||||||
shadowProj *
|
shadowProj * glm::lookAt(pos_, pos_ + glm::vec3(-1.0, 0.0, 0.0),
|
||||||
lookAt(pos_, pos_ + glm::vec3(-1.0, 0.0, 0.0), glm::vec3(0.0, -1.0, 0.0));
|
glm::vec3(0.0, -1.0, 0.0));
|
||||||
shadowTransforms[2] =
|
shadowTransforms[2] =
|
||||||
shadowProj *
|
shadowProj * glm::lookAt(pos_, pos_ + glm::vec3(0.0, 1.0, 0.0),
|
||||||
lookAt(pos_, pos_ + glm::vec3(0.0, 1.0, 0.0), glm::vec3(0.0, 0.0, 1.0));
|
glm::vec3(0.0, 0.0, 1.0));
|
||||||
shadowTransforms[3] =
|
shadowTransforms[3] =
|
||||||
shadowProj *
|
shadowProj * glm::lookAt(pos_, pos_ + glm::vec3(0.0, -1.0, 0.0),
|
||||||
lookAt(pos_, pos_ + glm::vec3(0.0, -1.0, 0.0), glm::vec3(0.0, 0.0, -1.0));
|
glm::vec3(0.0, 0.0, -1.0));
|
||||||
shadowTransforms[4] =
|
shadowTransforms[4] =
|
||||||
shadowProj *
|
shadowProj * glm::lookAt(pos_, pos_ + glm::vec3(0.0, 0.0, 1.0),
|
||||||
lookAt(pos_, pos_ + glm::vec3(0.0, 0.0, 1.0), glm::vec3(0.0, -1.0, 0.0));
|
glm::vec3(0.0, -1.0, 0.0));
|
||||||
shadowTransforms[5] =
|
shadowTransforms[5] =
|
||||||
shadowProj *
|
shadowProj * glm::lookAt(pos_, pos_ + glm::vec3(0.0, 0.0, -1.0),
|
||||||
lookAt(pos_, pos_ + glm::vec3(0.0, 0.0, -1.0), glm::vec3(0.0, -1.0, 0.0));
|
glm::vec3(0.0, -1.0, 0.0));
|
||||||
|
|
||||||
glViewport(0, 0, kShadowMapSize, kShadowMapSize);
|
glViewport(0, 0, kShadowMapSize, kShadowMapSize);
|
||||||
glBindFramebuffer(GL_FRAMEBUFFER, fbo_);
|
glBindFramebuffer(GL_FRAMEBUFFER, fbo_);
|
||||||
glClear(GL_DEPTH_BUFFER_BIT);
|
glClear(GL_DEPTH_BUFFER_BIT);
|
||||||
glUseProgram(shadow_.id());
|
glUseProgram(shadow_.id());
|
||||||
|
|
||||||
if (!shadow_.CopyDataToUniform(6, shadowTransforms.data(),
|
shadow_.CopyDataToUniform(6, shadowTransforms.data(), "shadowMatrices");
|
||||||
"shadowMatrices")) {
|
shadow_.CopyDataToUniform(pos_, "lightPos");
|
||||||
cerr << "Shadow matrix not in shader" << endl;
|
shadow_.CopyDataToUniform(kFarPlane, "farPlane");
|
||||||
}
|
|
||||||
if (!shadow_.CopyDataToUniform(pos_, "lightPos")) {
|
|
||||||
cerr << "Light position not in shader" << endl;
|
|
||||||
}
|
|
||||||
if (!shadow_.CopyDataToUniform(kFarPlane, "farPlane")) {
|
|
||||||
cerr << "Far plane not in shader" << endl;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (const auto renderable : renderables) {
|
for (const auto renderable : renderables) {
|
||||||
renderable->Render(&shadow_);
|
renderable->Render(&shadow_);
|
||||||
|
|
|
@ -8,21 +8,21 @@
|
||||||
#include "renderable.h"
|
#include "renderable.h"
|
||||||
#include "shader.h"
|
#include "shader.h"
|
||||||
|
|
||||||
class PointLight final : public Renderable {
|
class PointLight : public Renderable {
|
||||||
public:
|
public:
|
||||||
explicit PointLight(const glm::vec3 &);
|
explicit PointLight(const glm::vec3 &);
|
||||||
~PointLight() override;
|
~PointLight();
|
||||||
|
|
||||||
void LoadData(const Shader *) const;
|
void LoadData(Shader *) const;
|
||||||
void GenerateCubeMaps(const std::vector<Renderable *> &) const;
|
void GenerateCubeMaps(const std::vector<Renderable *> &) const;
|
||||||
|
|
||||||
GLuint getDepthTexture() const { return depth_; }
|
inline GLuint getDepthTexture() const { return depth_; }
|
||||||
void setPosition(const glm::vec3 &pos) {
|
inline void setPosition(const glm::vec3 &pos) {
|
||||||
pos_ = pos;
|
pos_ = pos;
|
||||||
CleanUp();
|
CleanUp();
|
||||||
InitGeom();
|
InitGeom();
|
||||||
}
|
}
|
||||||
void setColors(const glm::vec3 &color) {
|
inline void setColors(const glm::vec3 &color) {
|
||||||
diffuse_ = color;
|
diffuse_ = color;
|
||||||
specular_ = color;
|
specular_ = color;
|
||||||
ambient_ = color / 5.0f;
|
ambient_ = color / 5.0f;
|
||||||
|
@ -37,7 +37,7 @@ class PointLight final : public Renderable {
|
||||||
float specularPower_{20};
|
float specularPower_{20};
|
||||||
glm::vec3 pos_;
|
glm::vec3 pos_;
|
||||||
|
|
||||||
Shader shadow_{R"(@SHADOW_VERT@)", R"(@SHADOW_FRAG@)", R"(@SHADOW_GEOM@)"};
|
Shader shadow_{"shadow.vert", "shadow.frag", "shadow.geom"};
|
||||||
GLuint fbo_{0};
|
GLuint fbo_{0};
|
||||||
GLuint depth_{0};
|
GLuint depth_{0};
|
||||||
};
|
};
|
|
@ -4,8 +4,7 @@
|
||||||
|
|
||||||
using namespace std;
|
using namespace std;
|
||||||
|
|
||||||
Renderable::Renderable(const bool drawTriangles)
|
Renderable::Renderable(bool drawTriangles) : drawTriangles_(drawTriangles) {}
|
||||||
: drawTriangles_(drawTriangles) {}
|
|
||||||
|
|
||||||
Renderable::~Renderable() { CleanUp(); }
|
Renderable::~Renderable() { CleanUp(); }
|
||||||
|
|
||||||
|
@ -31,7 +30,7 @@ void Renderable::InitGeom() {
|
||||||
|
|
||||||
void Renderable::Render(const Shader *const shader) const {
|
void Renderable::Render(const Shader *const shader) const {
|
||||||
if (!shader->CopyDataToUniform(model_, "model")) {
|
if (!shader->CopyDataToUniform(model_, "model")) {
|
||||||
cerr << "Model matrix not in shader" << endl;
|
// cerr << "Model matrix not in shader" << endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
glBindBuffer(GL_ARRAY_BUFFER, vbo_);
|
glBindBuffer(GL_ARRAY_BUFFER, vbo_);
|
||||||
|
@ -40,21 +39,19 @@ void Renderable::Render(const Shader *const shader) const {
|
||||||
GLuint attribLoc = glGetAttribLocation(shader->id(), "vtxPos");
|
GLuint attribLoc = glGetAttribLocation(shader->id(), "vtxPos");
|
||||||
if (attribLoc != -1) {
|
if (attribLoc != -1) {
|
||||||
glEnableVertexAttribArray(attribLoc);
|
glEnableVertexAttribArray(attribLoc);
|
||||||
glVertexAttribPointer(
|
glVertexAttribPointer(attribLoc, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex),
|
||||||
attribLoc, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex),
|
(void *)offsetof(Vertex, position));
|
||||||
// ReSharper disable once CppZeroValuedExpressionUsedAsNullPointer
|
|
||||||
reinterpret_cast<void *>(offsetof(Vertex, position)));
|
|
||||||
} else {
|
} else {
|
||||||
cerr << "Not loading vtxPos" << endl;
|
// cerr << "Not loading vtxPos" << endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
attribLoc = glGetAttribLocation(shader->id(), "vtxNormal");
|
attribLoc = glGetAttribLocation(shader->id(), "vtxNormal");
|
||||||
if (attribLoc != -1) {
|
if (attribLoc != -1) {
|
||||||
glEnableVertexAttribArray(attribLoc);
|
glEnableVertexAttribArray(attribLoc);
|
||||||
glVertexAttribPointer(attribLoc, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex),
|
glVertexAttribPointer(attribLoc, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex),
|
||||||
reinterpret_cast<void *>(offsetof(Vertex, normal)));
|
(void *)offsetof(Vertex, normal));
|
||||||
} else {
|
} else {
|
||||||
cerr << "Not loading vtxNormal" << endl;
|
// cerr << "Not loading vtxNormal" << endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (drawTriangles_) {
|
if (drawTriangles_) {
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
|
|
||||||
#include <GL/glew.h>
|
#include <GL/glew.h>
|
||||||
|
|
||||||
|
#include <array>
|
||||||
#include <glm/ext/matrix_transform.hpp>
|
#include <glm/ext/matrix_transform.hpp>
|
||||||
#include <glm/glm.hpp>
|
#include <glm/glm.hpp>
|
||||||
|
|
||||||
|
@ -10,7 +11,7 @@
|
||||||
class Renderable {
|
class Renderable {
|
||||||
public:
|
public:
|
||||||
explicit Renderable(bool);
|
explicit Renderable(bool);
|
||||||
virtual ~Renderable();
|
~Renderable();
|
||||||
|
|
||||||
void InitGeom();
|
void InitGeom();
|
||||||
void Render(const Shader *) const;
|
void Render(const Shader *) const;
|
||||||
|
|
|
@ -7,8 +7,6 @@
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
|
|
||||||
#include "constants.h"
|
#include "constants.h"
|
||||||
#include "geography.h"
|
|
||||||
#include "grid.h"
|
|
||||||
|
|
||||||
using namespace std;
|
using namespace std;
|
||||||
|
|
||||||
|
@ -43,7 +41,7 @@ Renderer::Renderer(int argc, char *argv[]) {
|
||||||
glutPassiveMotionFunc(PassiveMotionCB);
|
glutPassiveMotionFunc(PassiveMotionCB);
|
||||||
CheckGLError();
|
CheckGLError();
|
||||||
|
|
||||||
const GLenum res = glewInit();
|
GLenum res = glewInit();
|
||||||
if (res != GLEW_OK) {
|
if (res != GLEW_OK) {
|
||||||
cerr << "Error in glewInit()";
|
cerr << "Error in glewInit()";
|
||||||
throw runtime_error(
|
throw runtime_error(
|
||||||
|
@ -51,26 +49,21 @@ Renderer::Renderer(int argc, char *argv[]) {
|
||||||
}
|
}
|
||||||
CheckGLError();
|
CheckGLError();
|
||||||
|
|
||||||
shader_ = new Shader(R"(
|
shader_ = new Shader("phong.vert", "phong.frag");
|
||||||
@PHONG_VERT@
|
|
||||||
)",
|
|
||||||
R"(
|
|
||||||
@PHONG_FRAG@
|
|
||||||
)");
|
|
||||||
light_ = new PointLight({kGeographyShort * kGeographyCountShort / 2,
|
light_ = new PointLight({kGeographyShort * kGeographyCountShort / 2,
|
||||||
kGeographyLong * kGeographyCountLong / 2,
|
kGeographyLong * kGeographyCountLong / 2,
|
||||||
kHeightMultiplier * kGeographyCountShort / 2});
|
kHeightMultiplier * kGeographyCountShort / 2});
|
||||||
|
|
||||||
using std::chrono::duration_cast;
|
using std::chrono::duration_cast;
|
||||||
using std::chrono::milliseconds;
|
using std::chrono::milliseconds;
|
||||||
const auto start_time = chrono::high_resolution_clock::now();
|
auto start_time = chrono::high_resolution_clock::now();
|
||||||
for (auto x = 0; x < kGeographyCountShort; ++x) {
|
for (auto x = 0; x < kGeographyCountShort; ++x) {
|
||||||
for (auto y = 0; y < kGeographyCountLong; ++y) {
|
for (auto y = 0; y < kGeographyCountLong; ++y) {
|
||||||
objects_.push_back(new Geography(x, y));
|
objects_.push_back(new Geography(x, y));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto end_time = chrono::high_resolution_clock::now();
|
auto end_time = chrono::high_resolution_clock::now();
|
||||||
cout << "Generation time: "
|
cout << "Generation time: "
|
||||||
<< duration_cast<milliseconds>(end_time - start_time).count() << "ms\n";
|
<< duration_cast<milliseconds>(end_time - start_time).count() << "ms\n";
|
||||||
cout << " vertices: "
|
cout << " vertices: "
|
||||||
|
@ -125,11 +118,11 @@ void Renderer::Display() const {
|
||||||
for (const auto object : objects_) {
|
for (const auto object : objects_) {
|
||||||
const auto geo = dynamic_cast<Geography *>(object);
|
const auto geo = dynamic_cast<Geography *>(object);
|
||||||
if (geo != nullptr) {
|
if (geo != nullptr) {
|
||||||
const float min = geo->min();
|
float min = geo->min();
|
||||||
if (min < minHeight) {
|
if (min < minHeight) {
|
||||||
minHeight = min;
|
minHeight = min;
|
||||||
}
|
}
|
||||||
const float max = geo->max();
|
float max = geo->max();
|
||||||
if (max > maxHeight) {
|
if (max > maxHeight) {
|
||||||
maxHeight = max;
|
maxHeight = max;
|
||||||
}
|
}
|
||||||
|
@ -144,7 +137,7 @@ void Renderer::Display() const {
|
||||||
|
|
||||||
glActiveTexture(GL_TEXTURE0);
|
glActiveTexture(GL_TEXTURE0);
|
||||||
glBindTexture(GL_TEXTURE_CUBE_MAP, light_->getDepthTexture());
|
glBindTexture(GL_TEXTURE_CUBE_MAP, light_->getDepthTexture());
|
||||||
const auto depthMap = glGetUniformLocation(shader_->id(), "depthMap");
|
auto depthMap = glGetUniformLocation(shader_->id(), "depthMap");
|
||||||
glUniform1i(depthMap, 0);
|
glUniform1i(depthMap, 0);
|
||||||
|
|
||||||
light_->Render(shader_);
|
light_->Render(shader_);
|
||||||
|
@ -262,7 +255,7 @@ void Renderer::HandleMovementKey(const unsigned char key, const bool down) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Renderer::Tick(const int ticks) {
|
void Renderer::Tick(int ticks) {
|
||||||
bool doneSomething = false;
|
bool doneSomething = false;
|
||||||
if (last_mouse_x_ < 0 || last_mouse_x_ > viewport_width_ ||
|
if (last_mouse_x_ < 0 || last_mouse_x_ > viewport_width_ ||
|
||||||
last_mouse_y_ < 0 || last_mouse_y_ > viewport_height_) {
|
last_mouse_y_ < 0 || last_mouse_y_ > viewport_height_) {
|
||||||
|
@ -297,11 +290,11 @@ void Renderer::Tick(const int ticks) {
|
||||||
doneSomething = true;
|
doneSomething = true;
|
||||||
shadowsChanged_ = true;
|
shadowsChanged_ = true;
|
||||||
} else if (simulating_) {
|
} else if (simulating_) {
|
||||||
const auto lightAngle =
|
auto lightAngle =
|
||||||
fmod(static_cast<float>(ticks) * glm::two_pi<float>() / (kFPS * 20),
|
fmod(static_cast<float>(ticks) * glm::two_pi<float>() / (kFPS * 20),
|
||||||
glm::pi<float>() * 5 / 4) -
|
glm::pi<float>() * 5 / 4) -
|
||||||
glm::pi<float>() * 5 / 8;
|
glm::pi<float>() * 5 / 8;
|
||||||
const auto lightRotation =
|
auto lightRotation =
|
||||||
glm::vec3(0, glm::sin(lightAngle), glm::cos(lightAngle) / 2) *
|
glm::vec3(0, glm::sin(lightAngle), glm::cos(lightAngle) / 2) *
|
||||||
static_cast<float>(kGeographyLong * kGeographyCountLong);
|
static_cast<float>(kGeographyLong * kGeographyCountLong);
|
||||||
light_->setPosition(lightRotation +
|
light_->setPosition(lightRotation +
|
||||||
|
@ -342,8 +335,9 @@ void Renderer::PassiveMotionCB(const int w, const int h) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void Renderer::TimerCB(const int ticks) {
|
void Renderer::TimerCB(const int ticks) {
|
||||||
const auto tickIncrement = window->simulating_ ? 1 : 0;
|
auto tickIncrement = window->simulating_ ? 1 : 0;
|
||||||
glutTimerFunc(1000 / kFPS, TimerCB, ticks + tickIncrement);
|
glutTimerFunc(static_cast<unsigned int>(1000 / kFPS), TimerCB,
|
||||||
|
ticks + tickIncrement);
|
||||||
window->Tick(ticks);
|
window->Tick(ticks);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -353,7 +347,7 @@ void Renderer::CheckGLError() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Renderer::PrintOpenGLError(const GLenum errorCode) {
|
void Renderer::PrintOpenGLError(GLenum errorCode) {
|
||||||
switch (errorCode) {
|
switch (errorCode) {
|
||||||
case GL_INVALID_VALUE:
|
case GL_INVALID_VALUE:
|
||||||
cerr << "GL_INVALID_VALUE" << endl;
|
cerr << "GL_INVALID_VALUE" << endl;
|
|
@ -3,7 +3,9 @@
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include "camera.h"
|
#include "camera.h"
|
||||||
#include "point_light.in.h"
|
#include "constants.h"
|
||||||
|
#include "geography.h"
|
||||||
|
#include "point_light.h"
|
||||||
#include "shader.h"
|
#include "shader.h"
|
||||||
|
|
||||||
constexpr auto kInitialWidth = 1280;
|
constexpr auto kInitialWidth = 1280;
|
||||||
|
|
|
@ -8,12 +8,11 @@
|
||||||
|
|
||||||
using namespace std;
|
using namespace std;
|
||||||
|
|
||||||
Shader::Shader(const string &vertexShader, const string &fragmentShader,
|
Shader::Shader(const string &vertexShaderFile, const string &fragmentShaderFile,
|
||||||
const string &geometryShader) {
|
const string &geometryShaderFile) {
|
||||||
const auto vertexShaderId = CompileShader(vertexShader, GL_VERTEX_SHADER);
|
auto vertexShaderId = CompileShader(vertexShaderFile, GL_VERTEX_SHADER);
|
||||||
const auto fragmentShaderId =
|
auto fragmentShaderId = CompileShader(fragmentShaderFile, GL_FRAGMENT_SHADER);
|
||||||
CompileShader(fragmentShader, GL_FRAGMENT_SHADER);
|
GLuint geometryShaderId;
|
||||||
GLuint geometryShaderId{0};
|
|
||||||
|
|
||||||
id_ = glCreateProgram();
|
id_ = glCreateProgram();
|
||||||
|
|
||||||
|
@ -22,8 +21,8 @@ Shader::Shader(const string &vertexShader, const string &fragmentShader,
|
||||||
glAttachShader(id_, fragmentShaderId);
|
glAttachShader(id_, fragmentShaderId);
|
||||||
CheckGLError("Error in attaching the fragment shader");
|
CheckGLError("Error in attaching the fragment shader");
|
||||||
|
|
||||||
if (!geometryShader.empty()) {
|
if (!geometryShaderFile.empty()) {
|
||||||
geometryShaderId = CompileShader(geometryShader, GL_GEOMETRY_SHADER);
|
geometryShaderId = CompileShader(geometryShaderFile, GL_GEOMETRY_SHADER);
|
||||||
glAttachShader(id_, geometryShaderId);
|
glAttachShader(id_, geometryShaderId);
|
||||||
CheckGLError("Error in attaching the geometry shader");
|
CheckGLError("Error in attaching the geometry shader");
|
||||||
}
|
}
|
||||||
|
@ -34,7 +33,7 @@ Shader::Shader(const string &vertexShader, const string &fragmentShader,
|
||||||
|
|
||||||
glDeleteShader(vertexShaderId);
|
glDeleteShader(vertexShaderId);
|
||||||
glDeleteShader(fragmentShaderId);
|
glDeleteShader(fragmentShaderId);
|
||||||
if (geometryShaderId != 0) {
|
if (!geometryShaderFile.empty()) {
|
||||||
glDeleteShader(geometryShaderId);
|
glDeleteShader(geometryShaderId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -46,7 +45,7 @@ Shader::~Shader() { glDeleteProgram(id_); }
|
||||||
|
|
||||||
bool Shader::CopyDataToUniform(const glm::mat4 &data,
|
bool Shader::CopyDataToUniform(const glm::mat4 &data,
|
||||||
const string &name) const {
|
const string &name) const {
|
||||||
const auto location = glGetUniformLocation(id_, name.c_str());
|
auto location = glGetUniformLocation(id_, name.c_str());
|
||||||
if (location == -1) {
|
if (location == -1) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -55,9 +54,8 @@ bool Shader::CopyDataToUniform(const glm::mat4 &data,
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Shader::CopyDataToUniform(const int count, const glm::mat4 *data,
|
bool Shader::CopyDataToUniform(int count, const glm::mat4 *data, const std::string &name) const {
|
||||||
const std::string &name) const {
|
auto location = glGetUniformLocation(id_, name.c_str());
|
||||||
const auto location = glGetUniformLocation(id_, name.c_str());
|
|
||||||
if (location == -1) {
|
if (location == -1) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -68,7 +66,7 @@ bool Shader::CopyDataToUniform(const int count, const glm::mat4 *data,
|
||||||
|
|
||||||
bool Shader::CopyDataToUniform(const glm::vec4 &data,
|
bool Shader::CopyDataToUniform(const glm::vec4 &data,
|
||||||
const string &name) const {
|
const string &name) const {
|
||||||
const auto location = glGetUniformLocation(id_, name.c_str());
|
auto location = glGetUniformLocation(id_, name.c_str());
|
||||||
if (location == -1) {
|
if (location == -1) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -78,7 +76,7 @@ bool Shader::CopyDataToUniform(const glm::vec4 &data,
|
||||||
|
|
||||||
bool Shader::CopyDataToUniform(const glm::vec3 &data,
|
bool Shader::CopyDataToUniform(const glm::vec3 &data,
|
||||||
const string &name) const {
|
const string &name) const {
|
||||||
const auto location = glGetUniformLocation(id_, name.c_str());
|
auto location = glGetUniformLocation(id_, name.c_str());
|
||||||
if (location == -1) {
|
if (location == -1) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -86,8 +84,8 @@ bool Shader::CopyDataToUniform(const glm::vec3 &data,
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Shader::CopyDataToUniform(const float data, const string &name) const {
|
bool Shader::CopyDataToUniform(float data, const string &name) const {
|
||||||
const auto location = glGetUniformLocation(id_, name.c_str());
|
auto location = glGetUniformLocation(id_, name.c_str());
|
||||||
if (location == -1) {
|
if (location == -1) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -95,8 +93,8 @@ bool Shader::CopyDataToUniform(const float data, const string &name) const {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Shader::CopyDataToUniform(const int data, const string &name) const {
|
bool Shader::CopyDataToUniform(int data, const string &name) const {
|
||||||
const auto location = glGetUniformLocation(id_, name.c_str());
|
auto location = glGetUniformLocation(id_, name.c_str());
|
||||||
if (location == -1) {
|
if (location == -1) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -104,24 +102,42 @@ bool Shader::CopyDataToUniform(const int data, const string &name) const {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Shader::CopyDataToUniform(const bool data, const string &name) const {
|
bool Shader::CopyDataToUniform(bool data, const string &name) const {
|
||||||
const auto location = glGetUniformLocation(id_, name.c_str());
|
auto location = glGetUniformLocation(id_, name.c_str());
|
||||||
if (location == -1) {
|
if (location == -1) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
const int actualData = data;
|
int actualData = static_cast<int>(data);
|
||||||
glUniform1iv(location, 1, &actualData);
|
glUniform1iv(location, 1, &actualData);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
GLuint Shader::CompileShader(const std::string &shaderSource,
|
string Shader::ReadFile(const string &filename) {
|
||||||
const GLenum shaderType) {
|
string data, line;
|
||||||
const GLuint id = glCreateShader(shaderType);
|
ifstream file;
|
||||||
const auto shaderC_str = shaderSource.c_str();
|
file.open(filename, std::ios::binary);
|
||||||
|
if (file.is_open()) {
|
||||||
|
while (getline(file, line)) {
|
||||||
|
data += line + '\n';
|
||||||
|
}
|
||||||
|
if (data.empty()) {
|
||||||
|
data.pop_back();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
throw runtime_error("Could not open " + filename);
|
||||||
|
}
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
GLuint Shader::CompileShader(const std::string &filename,
|
||||||
|
const GLenum shader_type) {
|
||||||
|
const GLuint id = glCreateShader(shader_type);
|
||||||
|
auto shaderString = ReadFile(filename);
|
||||||
|
auto shaderC_str = shaderString.c_str();
|
||||||
glShaderSource(id, 1, &shaderC_str, nullptr);
|
glShaderSource(id, 1, &shaderC_str, nullptr);
|
||||||
glCompileShader(id);
|
glCompileShader(id);
|
||||||
CheckShaderivError(id, GL_COMPILE_STATUS,
|
CheckShaderivError(id, GL_COMPILE_STATUS,
|
||||||
"Error when compiling shader file:\n" + shaderSource);
|
"Error when creating shader file " + filename);
|
||||||
return id;
|
return id;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -158,7 +174,7 @@ void Shader::PrintStatus() const {
|
||||||
glGetProgramiv(id_, GL_ACTIVE_ATTRIBUTE_MAX_LENGTH, &bufSize);
|
glGetProgramiv(id_, GL_ACTIVE_ATTRIBUTE_MAX_LENGTH, &bufSize);
|
||||||
GLint size;
|
GLint size;
|
||||||
GLenum type;
|
GLenum type;
|
||||||
const auto attributeName = new GLchar[bufSize];
|
auto attributeName = new GLchar[bufSize];
|
||||||
for (int i = 0; i < rc; ++i) {
|
for (int i = 0; i < rc; ++i) {
|
||||||
glGetActiveAttrib(id_, i, bufSize, &length, &size, &type, attributeName);
|
glGetActiveAttrib(id_, i, bufSize, &length, &size, &type, attributeName);
|
||||||
cout << "\t" << attributeName << ": " << type << "\n";
|
cout << "\t" << attributeName << ": " << type << "\n";
|
||||||
|
@ -181,7 +197,7 @@ void Shader::PrintStatus() const {
|
||||||
}
|
}
|
||||||
|
|
||||||
void Shader::CheckGLError(const string &errorMessage) {
|
void Shader::CheckGLError(const string &errorMessage) {
|
||||||
const auto rc = glGetError();
|
auto rc = glGetError();
|
||||||
if (rc != GL_NO_ERROR) {
|
if (rc != GL_NO_ERROR) {
|
||||||
cerr << errorMessage << endl;
|
cerr << errorMessage << endl;
|
||||||
throw runtime_error(reinterpret_cast<const char *>(gluErrorString(rc)));
|
throw runtime_error(reinterpret_cast<const char *>(gluErrorString(rc)));
|
||||||
|
@ -196,7 +212,7 @@ void Shader::CheckProgramivError(const GLuint program, const GLenum pname,
|
||||||
cerr << errorMessage << endl;
|
cerr << errorMessage << endl;
|
||||||
GLsizei length, bufSize;
|
GLsizei length, bufSize;
|
||||||
glGetProgramiv(program, GL_INFO_LOG_LENGTH, &bufSize);
|
glGetProgramiv(program, GL_INFO_LOG_LENGTH, &bufSize);
|
||||||
const auto error = new GLchar[bufSize];
|
auto error = new GLchar[bufSize];
|
||||||
glGetProgramInfoLog(program, bufSize, &length, error);
|
glGetProgramInfoLog(program, bufSize, &length, error);
|
||||||
throw runtime_error(error);
|
throw runtime_error(error);
|
||||||
}
|
}
|
||||||
|
@ -210,7 +226,7 @@ void Shader::CheckShaderivError(const GLuint shader, const GLenum pname,
|
||||||
cerr << errorMessage << endl;
|
cerr << errorMessage << endl;
|
||||||
GLsizei length, bufSize;
|
GLsizei length, bufSize;
|
||||||
glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &bufSize);
|
glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &bufSize);
|
||||||
const auto error = new GLchar[bufSize];
|
auto error = new GLchar[bufSize];
|
||||||
glGetShaderInfoLog(shader, bufSize, &length, error);
|
glGetShaderInfoLog(shader, bufSize, &length, error);
|
||||||
throw runtime_error(error);
|
throw runtime_error(error);
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
|
|
||||||
#include <GL/glew.h>
|
#include <GL/glew.h>
|
||||||
|
|
||||||
|
#include <array>
|
||||||
#include <glm/glm.hpp>
|
#include <glm/glm.hpp>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
|
@ -25,11 +26,12 @@ class Shader {
|
||||||
|
|
||||||
void PrintStatus() const;
|
void PrintStatus() const;
|
||||||
|
|
||||||
GLuint id() const { return id_; }
|
inline GLuint id() const { return id_; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
GLuint id_;
|
GLuint id_;
|
||||||
|
|
||||||
|
static std::string ReadFile(const std::string &);
|
||||||
static GLuint CompileShader(const std::string &, GLenum);
|
static GLuint CompileShader(const std::string &, GLenum);
|
||||||
|
|
||||||
static void CheckGLError(const std::string &);
|
static void CheckGLError(const std::string &);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue