diff --git a/src/basics/FractalNoise.h b/src/basics/FractalNoise.h index 0f77667..e6e3058 100644 --- a/src/basics/FractalNoise.h +++ b/src/basics/FractalNoise.h @@ -16,6 +16,19 @@ class BASICSSHARED_EXPORT FractalNoise { FractalNoise(); virtual ~FractalNoise(); + inline double getScaling() const { + return scaling; + } + inline double getHeight() const { + return height; + } + inline double getStepScaling() const { + return step_scaling; + } + inline double getStepHeight() const { + return step_height; + } + void setScaling(double scaling, double height = 1.0); void setStep(double scaling_factor, double height_factor = 1.0); void setSlope(double slope_factor); diff --git a/src/basics/NoiseFunctionSimplex.cpp b/src/basics/NoiseFunctionSimplex.cpp index 8aa679b..97a615c 100644 --- a/src/basics/NoiseFunctionSimplex.cpp +++ b/src/basics/NoiseFunctionSimplex.cpp @@ -507,6 +507,7 @@ const Texture2D *NoiseFunctionSimplex::getNormalTexture() { for (int x = 0; x < width; x++) { for (int z = 0; z < height; z++) { + // TODO Make texture tileable double vcenter = noiseSimplexGet2DValue(0.01 * to_double(x), 0.01 * to_double(z)); double vsouth = noiseSimplexGet2DValue(0.01 * to_double(x), 0.01 * to_double(z) + 0.001); double veast = noiseSimplexGet2DValue(0.01 * to_double(x) + 0.001, 0.01 * to_double(z)); diff --git a/src/render/opengl/OpenGLRenderer.cpp b/src/render/opengl/OpenGLRenderer.cpp index abad36a..43bd83f 100644 --- a/src/render/opengl/OpenGLRenderer.cpp +++ b/src/render/opengl/OpenGLRenderer.cpp @@ -16,6 +16,7 @@ #include "GodRaysSampler.h" #include "Logs.h" #include "Vector3.h" +#include "NoiseFunctionSimplex.h" OpenGLRenderer::OpenGLRenderer(Scenery *scenery) : SoftwareRenderer(scenery) { ready = false; @@ -105,6 +106,9 @@ void OpenGLRenderer::initialize() { part->updateScenery(); } + // Common state values + shared_state->set("simplexSampler", NoiseFunctionSimplex::getNormalTexture(), true, true); + cameraChangeEvent(render_camera); checkForErrors("initialize"); diff --git a/src/render/opengl/OpenGLSharedState.h b/src/render/opengl/OpenGLSharedState.h index 06e04b8..b068be8 100644 --- a/src/render/opengl/OpenGLSharedState.h +++ b/src/render/opengl/OpenGLSharedState.h @@ -62,6 +62,9 @@ class OPENGLSHARED_EXPORT OpenGLSharedState { inline void set(const string &name, const Color &color) { get(name)->set(color); } + inline void set(const string &name, const FractalNoise &noise) { + get(name)->set(noise); + } private: map variables; diff --git a/src/render/opengl/OpenGLVariable.cpp b/src/render/opengl/OpenGLVariable.cpp index 8ea0484..42bb33f 100644 --- a/src/render/opengl/OpenGLVariable.cpp +++ b/src/render/opengl/OpenGLVariable.cpp @@ -13,6 +13,7 @@ #include "Texture2D.h" #include "Texture3D.h" #include "Texture4D.h" +#include "FractalNoise.h" typedef enum { TYPE_NONE, @@ -23,6 +24,7 @@ typedef enum { TYPE_FLOAT, TYPE_VECTOR3, TYPE_MATRIX4, + TYPE_NOISE, TYPE_COLOR } OpenGLVariableType; @@ -104,6 +106,9 @@ void OpenGLVariable::apply(OpenGLShaderProgram *program, unsigned int &texture_u functions->glUniform1i(loc, static_cast(texture_unit)); texture_unit++; break; + case TYPE_NOISE: + functions->glUniform1fv(loc, impl->value_int, impl->value_array_float.get()); + break; case TYPE_NONE: break; } @@ -242,6 +247,19 @@ void OpenGLVariable::set(float value) { impl->value_float = value; } +void OpenGLVariable::set(const FractalNoise &noise) { + impl->type = TYPE_NOISE; + + impl->value_int = 4; + + float *data = new float[4]; + data[0] = to_float(noise.getScaling()); + data[1] = to_float(noise.getHeight()); + data[2] = to_float(noise.getStepScaling()); + data[3] = to_float(noise.getStepHeight()); + impl->value_array_float = unique_ptr(data); +} + void OpenGLVariable::set(const Vector3 &vector) { impl->type = TYPE_VECTOR3; impl->value_vector3 = make_unique(vector); @@ -284,6 +302,10 @@ float OpenGLVariable::getFloatValue() const { return impl->value_float; } +float OpenGLVariable::getFloatArrayValue(unsigned int index) const { + return impl->value_array_float[index]; +} + void OpenGLVariable::uploadTexture(OpenGLFunctions *functions) { assert(impl->type == TYPE_TEXTURE_2D or impl->type == TYPE_TEXTURE_3D or impl->type == TYPE_TEXTURE_4D); diff --git a/src/render/opengl/OpenGLVariable.h b/src/render/opengl/OpenGLVariable.h index 8c786d5..6736df7 100644 --- a/src/render/opengl/OpenGLVariable.h +++ b/src/render/opengl/OpenGLVariable.h @@ -14,19 +14,6 @@ namespace opengl { * \brief OpenGL variable that can be bound to a uniform for shaders. */ class OpenGLVariable final { - public: - typedef enum { - TYPE_NONE, - TYPE_TEXTURE_2D, - TYPE_TEXTURE_3D, - TYPE_TEXTURE_4D, - TYPE_INTEGER, - TYPE_FLOAT, - TYPE_VECTOR3, - TYPE_MATRIX4, - TYPE_COLOR - } OpenGLVariableType; - public: OpenGLVariable(const string &name); ~OpenGLVariable(); @@ -53,12 +40,14 @@ class OpenGLVariable final { void set(const Texture4D *texture, bool repeat = false, bool color = true); void set(int value); void set(float value); + void set(const FractalNoise &noise); void set(const Vector3 &vector); void set(const Matrix4 &matrix); void set(const Color &color); int getIntValue() const; float getFloatValue() const; + float getFloatArrayValue(unsigned int index) const; protected: void uploadTexture(OpenGLFunctions *renderer); diff --git a/src/render/opengl/OpenGLWater.cpp b/src/render/opengl/OpenGLWater.cpp index c7a53ce..da87443 100644 --- a/src/render/opengl/OpenGLWater.cpp +++ b/src/render/opengl/OpenGLWater.cpp @@ -8,7 +8,6 @@ #include "Scenery.h" #include "WaterDefinition.h" #include "SurfaceMaterial.h" -#include "NoiseFunctionSimplex.h" #include "FloatNode.h" #include "FloatDiff.h" #include "IntNode.h" @@ -58,8 +57,7 @@ void OpenGLWater::update() { state->set("waterMaterialShininess", water->material->shininess); state->set("waterMaterialHardness", water->material->hardness); - Logs::debug("OpenGL") << "Updating simplex texture" << endl; - state->set("simplexSampler", NoiseFunctionSimplex::getNormalTexture(), true, true); + state->set("waterNoise", renderer->getWaterRenderer()->getNoise()); } void OpenGLWater::render() { diff --git a/src/render/opengl/shaders/noise.frag b/src/render/opengl/shaders/noise.frag index 57b81fe..af0bd99 100644 --- a/src/render/opengl/shaders/noise.frag +++ b/src/render/opengl/shaders/noise.frag @@ -1,15 +1,19 @@ -uniform float noiseInitScaling; -uniform float noiseInitHeight; -uniform float noiseStepScaling; -uniform float noiseStepHeight; uniform sampler2D simplexSampler; -vec3 noiseNormal2d(vec2 location, float detail) +vec3 noiseNormal2d(float[4] data, vec2 location, float detail) { vec3 normal = vec3(0.0, 0.0, 0.0); - for (float scaling = 1.0; scaling < 400.0; scaling *= 1.5) + float scaling = data[0]; + float height = data[1]; + float step_scaling = data[2]; + float step_height = data[3]; + while (height > detail) { + // TODO offsets + // TODO parametrized texture scaling (0.01) normal += texture(simplexSampler, location * 0.01 * scaling).xyz; + scaling *= step_scaling; + height *= step_height; } return normalize(normal); } diff --git a/src/render/opengl/shaders/water.frag b/src/render/opengl/shaders/water.frag index b2c9e88..df61d4d 100644 --- a/src/render/opengl/shaders/water.frag +++ b/src/render/opengl/shaders/water.frag @@ -3,11 +3,13 @@ uniform float waterMaterialReflection; uniform float waterMaterialShininess; uniform float waterMaterialHardness; uniform float waterReflection; +uniform float[4] waterNoise; out vec4 final_color; void main(void) { - vec3 normal = noiseNormal2d(unprojected.xz, 0.001); + // TODO Increased detail near camera + vec3 normal = noiseNormal2d(waterNoise, unprojected.xz, 0.00001); final_color = applyLighting(unprojected, normal, waterMaterialColor, waterMaterialReflection, waterMaterialShininess, waterMaterialHardness); diff --git a/src/render/software/WaterRenderer.h b/src/render/software/WaterRenderer.h index 14c444c..0ce3313 100644 --- a/src/render/software/WaterRenderer.h +++ b/src/render/software/WaterRenderer.h @@ -27,6 +27,10 @@ class SOFTWARESHARED_EXPORT WaterRenderer : public LightFilter { WaterRenderer(SoftwareRenderer *parent); virtual ~WaterRenderer(); + inline const FractalNoise &getNoise() const { + return *noise; + } + virtual void update(); virtual HeightInfo getHeightInfo(); diff --git a/src/tests/OpenGLVariable_Test.cpp b/src/tests/OpenGLVariable_Test.cpp new file mode 100644 index 0000000..56950c3 --- /dev/null +++ b/src/tests/OpenGLVariable_Test.cpp @@ -0,0 +1,20 @@ +#include "BaseTestCase.h" +#include "OpenGLVariable.h" + +#include "NoiseFunctionSimplex.h" + +TEST(OpenGLVariable, setNoise) { + OpenGLVariable var("test"); + NoiseFunctionSimplex noise; + + noise.setScaling(0.5, 2.0); + noise.setStep(3.0, 0.4); + + var.set(noise); + + EXPECT_EQ(4, var.getIntValue()); + EXPECT_FLOAT_EQ(2.0f, var.getFloatArrayValue(0)); + EXPECT_FLOAT_EQ(1.0f, var.getFloatArrayValue(1)); + EXPECT_FLOAT_EQ(1.0f / 3.0f, var.getFloatArrayValue(2)); + EXPECT_FLOAT_EQ(1.2f, var.getFloatArrayValue(3)); +}