=== added file 'data/models/asteroid-high.3ds'
Binary files data/models/asteroid-high.3ds 1970-01-01 00:00:00 +0000 and data/models/asteroid-high.3ds 2011-07-14 11:25:43 +0000 differ
=== added file 'data/models/asteroid-low.3ds'
Binary files data/models/asteroid-low.3ds 1970-01-01 00:00:00 +0000 and data/models/asteroid-low.3ds 2011-07-14 11:25:43 +0000 differ
=== added file 'data/shaders/bump-normals.frag'
@@ -0,0 +1,50 @@
+#ifdef GL_ES
+precision mediump float;
+#endif
+
+uniform vec4 LightSourcePosition;
+uniform vec3 LightSourceHalfVector;
+uniform sampler2D NormalMap;
+uniform mat4 NormalMatrix;
+
+varying vec2 TextureCoord;
+
+void main(void)
+{
+ const vec4 LightSourceAmbient = vec4(0.1, 0.1, 0.1, 1.0);
+ const vec4 LightSourceDiffuse = vec4(0.8, 0.8, 0.8, 1.0);
+ const vec4 LightSourceSpecular = vec4(0.8, 0.8, 0.8, 1.0);
+ const vec4 MaterialAmbient = vec4(1.0, 1.0, 1.0, 1.0);
+ const vec4 MaterialDiffuse = vec4(1.0, 1.0, 1.0, 1.0);
+ const vec4 MaterialSpecular = vec4(0.2, 0.2, 0.2, 1.0);
+ const float MaterialShininess = 100.0;
+
+ // Get the raw normal XYZ data from the normal map
+ vec3 normal_raw = texture2D(NormalMap, TextureCoord).xyz;
+ // Map "color" range [0, 1.0] to normal range [-1.0, 1.0]
+ vec3 normal_scaled = normal_raw * 2.0 - 1.0;
+
+ // Convert the normal to eye coordinates. Note that the normal map
+ // we are using is using object coordinates (not tangent!) for the
+ // normals, so we can multiply by the NormalMatrix as usual.
+ vec3 N = normalize(vec3(NormalMatrix * vec4(normal_scaled, 1.0)));
+
+ // In the lighting model we are using here (Blinn-Phong with light at
+ // infinity, viewer at infinity), the light position/direction and the
+ // half vector is constant for the all the fragments.
+ vec3 L = normalize(LightSourcePosition.xyz);
+ vec3 H = normalize(LightSourceHalfVector);
+
+ // Calculate the diffuse color according to Lambertian reflectance
+ vec4 diffuse = MaterialDiffuse * LightSourceDiffuse * max(dot(N, L), 0.0);
+
+ // Calculate the ambient color
+ vec4 ambient = MaterialAmbient * LightSourceAmbient;
+
+ // Calculate the specular color according to the Blinn-Phong model
+ vec4 specular = MaterialSpecular * LightSourceSpecular *
+ pow(max(dot(N,H), 0.0), MaterialShininess);
+
+ // Calculate the final color
+ gl_FragColor = ambient + specular + diffuse;
+}
=== added file 'data/shaders/bump-normals.vert'
@@ -0,0 +1,14 @@
+attribute vec3 position;
+attribute vec2 texcoord;
+
+uniform mat4 ModelViewProjectionMatrix;
+
+varying vec2 TextureCoord;
+
+void main(void)
+{
+ TextureCoord = texcoord;
+
+ // Transform the position to clip coordinates
+ gl_Position = ModelViewProjectionMatrix * vec4(position, 1.0);
+}
=== added file 'data/shaders/bump-poly.frag'
@@ -0,0 +1,40 @@
+#ifdef GL_ES
+precision mediump float;
+#endif
+
+uniform vec4 LightSourcePosition;
+uniform vec3 LightSourceHalfVector;
+
+varying vec3 Normal;
+
+void main(void)
+{
+ const vec4 LightSourceAmbient = vec4(0.1, 0.1, 0.1, 1.0);
+ const vec4 LightSourceDiffuse = vec4(0.8, 0.8, 0.8, 1.0);
+ const vec4 LightSourceSpecular = vec4(0.8, 0.8, 0.8, 1.0);
+ const vec4 MaterialAmbient = vec4(1.0, 1.0, 1.0, 1.0);
+ const vec4 MaterialDiffuse = vec4(1.0, 1.0, 1.0, 1.0);
+ const vec4 MaterialSpecular = vec4(0.2, 0.2, 0.2, 1.0);
+ const float MaterialShininess = 100.0;
+
+ vec3 N = normalize(Normal);
+
+ // In the lighting model we are using here (Blinn-Phong with light at
+ // infinity, viewer at infinity), the light position/direction and the
+ // half vector is constant for the all the fragments.
+ vec3 L = normalize(LightSourcePosition.xyz);
+ vec3 H = normalize(LightSourceHalfVector);
+
+ // Calculate the diffuse color according to Lambertian reflectance
+ vec4 diffuse = MaterialDiffuse * LightSourceDiffuse * max(dot(N, L), 0.0);
+
+ // Calculate the ambient color
+ vec4 ambient = MaterialAmbient * LightSourceAmbient;
+
+ // Calculate the specular color according to the Blinn-Phong model
+ vec4 specular = MaterialSpecular * LightSourceSpecular *
+ pow(max(dot(N,H), 0.0), MaterialShininess);
+
+ // Calculate the final color
+ gl_FragColor = ambient + specular + diffuse;
+}
=== added file 'data/shaders/bump-poly.vert'
@@ -0,0 +1,16 @@
+attribute vec3 position;
+attribute vec3 normal;
+
+uniform mat4 ModelViewProjectionMatrix;
+uniform mat4 NormalMatrix;
+
+varying vec3 Normal;
+
+void main(void)
+{
+ // Transform the normal to eye coordinates
+ Normal = normalize(vec3(NormalMatrix * vec4(normal, 1.0)));
+
+ // Transform the position to clip coordinates
+ gl_Position = ModelViewProjectionMatrix * vec4(position, 1.0);
+}
=== added file 'data/textures/asteroid-normal-map.png'
Binary files data/textures/asteroid-normal-map.png 1970-01-01 00:00:00 +0000 and data/textures/asteroid-normal-map.png 2011-07-14 11:25:43 +0000 differ
=== modified file 'src/main.cpp'
@@ -48,6 +48,8 @@
"shading:shading=gouraud",
"shading:shading=blinn-phong-inf",
"shading:shading=phong",
+ "bump:bump-render=high-poly",
+ "bump:bump-render=normals",
"conditionals:vertex-steps=0:fragment-steps=0",
"conditionals:vertex-steps=0:fragment-steps=5",
"conditionals:vertex-steps=5:fragment-steps=0",
@@ -218,6 +220,7 @@
Benchmark::register_scene(*new SceneConditionals(canvas));
Benchmark::register_scene(*new SceneFunction(canvas));
Benchmark::register_scene(*new SceneLoop(canvas));
+ Benchmark::register_scene(*new SceneBump(canvas));
if (Options::list_scenes) {
list_scenes();
=== added file 'src/scene-bump.cpp'
@@ -0,0 +1,247 @@
+/*
+ * Copyright © 2010-2011 Linaro Limited
+ *
+ * This file is part of the glmark2 OpenGL (ES) 2.0 benchmark.
+ *
+ * glmark2 is free software: you can redistribute it and/or modify it under the
+ * terms of the GNU General Public License as published by the Free Software
+ * Foundation, either version 3 of the License, or (at your option) any later
+ * version.
+ *
+ * glmark2 is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * glmark2. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Authors:
+ * Alexandros Frantzis (glmark2)
+ */
+#include "scene.h"
+#include "log.h"
+#include "mat.h"
+#include "stack.h"
+#include <cmath>
+
+SceneBump::SceneBump(Canvas &pCanvas) :
+ Scene(pCanvas, "bump")
+{
+ mOptions["bump-render"] = Scene::Option("bump-render", "off",
+ "How to render bumps [off, normals, high-poly]");
+}
+
+SceneBump::~SceneBump()
+{
+}
+
+int SceneBump::load()
+{
+ mRotationSpeed = 36.0f;
+
+ mRunning = false;
+
+ return 1;
+}
+
+void SceneBump::unload()
+{
+}
+
+void
+SceneBump::setup_model_plain(const std::string &type)
+{
+ static const std::string vtx_shader_filename(GLMARK_DATA_PATH"/shaders/bump-poly.vert");
+ static const std::string frg_shader_filename(GLMARK_DATA_PATH"/shaders/bump-poly.frag");
+ static const std::string low_poly_filename(GLMARK_DATA_PATH"/models/asteroid-low.3ds");
+ static const std::string high_poly_filename(GLMARK_DATA_PATH"/models/asteroid-high.3ds");
+ Model model;
+
+ std::string poly_filename = type == "high-poly" ?
+ high_poly_filename : low_poly_filename;
+
+ if(!model.load_3ds(poly_filename))
+ return;
+
+ model.calculate_normals();
+
+ /* Tell the converter that we only care about position and normal attributes */
+ std::vector<std::pair<Model::AttribType, int> > attribs;
+ attribs.push_back(std::pair<Model::AttribType, int>(Model::AttribTypePosition, 3));
+ attribs.push_back(std::pair<Model::AttribType, int>(Model::AttribTypeNormal, 3));
+
+ model.convert_to_mesh(mMesh, attribs);
+
+ if (!Scene::load_shaders_from_files(mProgram, vtx_shader_filename,
+ frg_shader_filename))
+ {
+ return;
+ }
+
+ std::vector<GLint> attrib_locations;
+ attrib_locations.push_back(mProgram.getAttribIndex("position"));
+ attrib_locations.push_back(mProgram.getAttribIndex("normal"));
+ mMesh.set_attrib_locations(attrib_locations);
+}
+
+void
+SceneBump::setup_model_normals()
+{
+ static const std::string vtx_shader_filename(GLMARK_DATA_PATH"/shaders/bump-normals.vert");
+ static const std::string frg_shader_filename(GLMARK_DATA_PATH"/shaders/bump-normals.frag");
+ Model model;
+
+ if(!model.load_3ds(GLMARK_DATA_PATH"/models/asteroid-low.3ds"))
+ return;
+
+ /*
+ * We don't care about the vertex normals. We are using a per-fragment
+ * normal map (in object space coordinates).
+ */
+ std::vector<std::pair<Model::AttribType, int> > attribs;
+ attribs.push_back(std::pair<Model::AttribType, int>(Model::AttribTypePosition, 3));
+ attribs.push_back(std::pair<Model::AttribType, int>(Model::AttribTypeTexcoord, 2));
+
+ model.convert_to_mesh(mMesh, attribs);
+
+ if (!Scene::load_shaders_from_files(mProgram, vtx_shader_filename,
+ frg_shader_filename))
+ {
+ return;
+ }
+
+ std::vector<GLint> attrib_locations;
+ attrib_locations.push_back(mProgram.getAttribIndex("position"));
+ attrib_locations.push_back(mProgram.getAttribIndex("texcoord"));
+ mMesh.set_attrib_locations(attrib_locations);
+
+ Texture::load(GLMARK_DATA_PATH"/textures/asteroid-normal-map.png", &mTexture,
+ GL_NEAREST, GL_NEAREST, 0);
+}
+
+void SceneBump::setup()
+{
+ Scene::setup();
+
+ const std::string &bump_render = mOptions["bump-render"].value;
+
+ if (bump_render == "normals")
+ setup_model_normals();
+ else if (bump_render == "off" || bump_render == "high-poly")
+ setup_model_plain(bump_render);
+
+ static const LibMatrix::vec4 lightPosition(20.0f, 20.0f, 10.0f, 1.0f);
+
+ mMesh.build_vbo();
+
+ mProgram.start();
+
+ // Load lighting and material uniforms
+ mProgram.loadUniformVector(lightPosition, "LightSourcePosition");
+
+ // Calculate and load the half vector
+ LibMatrix::vec3 halfVector(lightPosition.x(), lightPosition.y(), lightPosition.z());
+ halfVector.normalize();
+ halfVector += LibMatrix::vec3(0.0, 0.0, 1.0);
+ halfVector.normalize();
+ mProgram.loadUniformVector(halfVector, "LightSourceHalfVector");
+
+ // Load texture sampler value
+ mProgram.loadUniformScalar(0, "NormalMap");
+
+ mCurrentFrame = 0;
+ mRotation = 0.0;
+ mRunning = true;
+ mStartTime = Scene::get_timestamp_us() / 1000000.0;
+ mLastUpdateTime = mStartTime;
+}
+
+void
+SceneBump::teardown()
+{
+ mMesh.reset();
+
+ mProgram.stop();
+ mProgram.release();
+
+ glDeleteTextures(1, &mTexture);
+
+ Scene::teardown();
+}
+
+void SceneBump::update()
+{
+ double current_time = Scene::get_timestamp_us() / 1000000.0;
+ double dt = current_time - mLastUpdateTime;
+ double elapsed_time = current_time - mStartTime;
+
+ mLastUpdateTime = current_time;
+
+ if (elapsed_time >= mDuration) {
+ mAverageFPS = mCurrentFrame / elapsed_time;
+ mRunning = false;
+ }
+
+ mRotation += mRotationSpeed * dt;
+
+ mCurrentFrame++;
+}
+
+void SceneBump::draw()
+{
+ LibMatrix::Stack4 model_view;
+
+ // Load the ModelViewProjectionMatrix uniform in the shader
+ LibMatrix::mat4 model_view_proj(mCanvas.projection());
+
+ model_view.translate(0.0f, 0.0f, -3.5f);
+ model_view.rotate(mRotation, 0.0f, 1.0f, 0.0f);
+ model_view_proj *= model_view.getCurrent();
+
+ mProgram.loadUniformMatrix(model_view_proj, "ModelViewProjectionMatrix");
+
+ // Load the NormalMatrix uniform in the shader. The NormalMatrix is the
+ // inverse transpose of the model view matrix.
+ LibMatrix::mat4 normal_matrix(model_view.getCurrent());
+ normal_matrix.inverse().transpose();
+ mProgram.loadUniformMatrix(normal_matrix, "NormalMatrix");
+
+ mMesh.render_vbo();
+}
+
+Scene::ValidationResult
+SceneBump::validate()
+{
+ static const double radius_3d(std::sqrt(3.0));
+
+ if (mRotation != 0)
+ return Scene::ValidationUnknown;
+
+ Canvas::Pixel ref;
+
+ Canvas::Pixel pixel = mCanvas.read_pixel(mCanvas.width() / 2,
+ mCanvas.height() / 2);
+
+ const std::string &bump_render = mOptions["bump-render"].value;
+
+ if (bump_render == "off")
+ ref = Canvas::Pixel(0x81, 0x81, 0x81, 0xff);
+ else if (bump_render == "high-poly")
+ ref = Canvas::Pixel(0x9c, 0x9c, 0x9c, 0xff);
+ else if (bump_render == "normals")
+ ref = Canvas::Pixel(0xa4, 0xa4, 0xa4, 0xff);
+ else
+ return Scene::ValidationUnknown;
+
+ double dist = pixel_value_distance(pixel, ref);
+
+ if (dist < radius_3d + 0.01) {
+ return Scene::ValidationSuccess;
+ }
+ else {
+ Log::debug("Validation failed! Expected: 0x%x Actual: 0x%x Distance: %f\n",
+ ref.to_le32(), pixel.to_le32(), dist);
+ return Scene::ValidationFailure;
+ }
+}
=== modified file 'src/scene.h'
@@ -253,4 +253,31 @@
~SceneLoop();
};
+
+class SceneBump : public Scene
+{
+public:
+ SceneBump(Canvas &pCanvas);
+ int load();
+ void unload();
+ void setup();
+ void teardown();
+ void update();
+ void draw();
+ ValidationResult validate();
+
+ ~SceneBump();
+
+protected:
+ Program mProgram;
+
+ Mesh mMesh;
+ GLuint mTexture;
+ float mRotation;
+ float mRotationSpeed;
+private:
+ void setup_model_plain(const std::string &type);
+ void setup_model_normals();
+};
+
#endif