Archive for the ‘image’ tag
Normal Maps: WIP
For the record, the below image is not yet correct, but here’s a first-pass at normal mapping in LxEngine:
The tangent vectors are calculated by GLGeom. The algorithm I’m using is somewhat…custom. I haven’t seen an implementation similar to how I’m attempting it – and thus suspect that I’ve missed a key point or two. That’s okay, however – this is for fun and to learn something.
The basic approach is to define a function F(p,v) = dUV, a function that takes a point on the surface of the mesh and a direction vector and returns the change in UV at that point in that direction. If we constraint this function to only be valid at vertices of the mesh (which is fine, since we’re only going to use this function at vertex points), then we can define F(p,v) as the weighted average of all the edges adjacent to the vertex at p – with the weights corresponding to the dot product between v and the direction of that edge. So if we have F(p,v) defined, that we can find tangent and bitangent by finding directions v where F is at a local maximum. This can be done by simple calculus: where the derivative of a function is 0, it is at a local maximum or minimum. Given that F(p,v) is a fairly simple weighted average, the derivative is not complex and solving for where it is 0 is not complex. Thus we end up with the directions in which U increases most and V increase most…which, until I locate the flaw in my understanding of the problem, are theoretically the tangent and bitangent directions.
We’ll see. For now, I have compiling code and a screenshot. That’s enough for today. Testing and debugging will follow
Material System
Work continues on the LxEngine material system…
The above is a simple “toon” shader on the Suzanne model. The shader code is based on the simple example provided at LightHouse3d, but bases the color on a 1d texture look-up on a slightly blurred color texture rather discrete if-else statements.
The Video
Here’s a quick video of some of the material effects:
The Code
At the highest-level, the implementation of the new shader is very simple. The new shader is defined by creating a new directory “ToonSimple” in the materials sub-directory of the media directory. This directory contains a vertex shader, a fragment shader, and JSON parameters description.
The material is then loaded in the C++ code via a call to
pRasterizer->acquireMaterial("ToonSimple")
and attached to the Instance‘s spMaterial member. LxEngine handles all the shader loading and parameter activation.
On to the details…
Vertex Shader
The vertex shader code is quite simple and uses a fixed light direction:
uniform mat4 unifProjMatrix; uniform mat4 unifViewMatrix; uniform mat3 unifNormalMatrix; in vec3 vertNormal; varying out float fragIntensity; void main() { // Keep it simple and use a fixed light direction vec3 lightDir = vec3(.5,-.5, 1.0); // The fragIntensity is effectively just the intensity of the diffuse // value from the Phong reflection model. // fragIntensity = dot(normalize(lightDir), unifNormalMatrix * vertNormal); gl_Position = unifProjMatrix * unifViewMatrix * gl_Vertex; }
The uniforms – unifProjMatrix, unifViewMatrix, unifNormalMatrix – are all “standard” LxEngine names, therefore it will automatically set the correct matrix values when activating the shader. Likewise with the attribute vertNormal; it too will be set automatically by the existing engine code. (This will be explained momentarily.)
Fragment Shader
The fragment shader is quite simple:
#version 150 #extension GL_ARB_explicit_attrib_location : enable uniform sampler1D unifTexture0; in float fragIntensity; layout(location = 0) out vec4 outColor; void main() { outColor = texture(unifTexture0, fragIntensity); }
Now the fragment shader does have an interesting detail: the uniform unifTexture0 is not a “standard” LxEngine uniform. (How could it be? The transformation matrices are common to many shaders, as are properties like the geometry’s normals, but is a texture map ever going to be “standard” enough that the engine would know what to set?)
This is a custom uniform, but it still does not require any C++ code for the engine to set it’s value properly. We’ll get to that momentarily.
Automatically setting the shader variables
The automatic setting of uniforms and attributes is done via calls to getActiveUniform and getActiveAttrib after the GLSL program is compiled. The MaterialClass class wraps the GLSL program and provides iteration functions that exemplify the use of these OpenGL calls:
void MaterialClass::iterateUniforms (std::function<void(const Uniform& uniform)> f) { int uniformCount; gl->getProgramiv(mProgram, GL_ACTIVE_UNIFORMS, &uniformCount); for (int i = 0; i < uniformCount; ++i) { Uniform uniform; char uniformName[128]; GLsizei uniformNameLength; gl->getActiveUniform(mProgram, GLuint(i), sizeof(uniformName), &uniformNameLength, &uniform.size, &uniform.type, uniformName); if (uniformNameLength >= sizeof(uniformName)) { throw lx_error_exception("GLSL program contains a uniform with too long a name size!"); } else { uniform.name = uniformName; uniform.location = gl->getUniformLocation(mProgram, uniformName); f(uniform); } } }
The LxEngine internal rasterizer code, after compiling a GLSL shader for the first time, will iterate over the uniforms and attributes to generate a set of values that need to be set whenever that material is made active. The set of “instructions” necessary to set those values is encapsulated in a std::vector<std::function<void()>> – which, in effect, allows a sort of dynamic code generation at the expense of a bit of overhead to the std::function calls. The flexibility and simplicity definitely win out over the efficiency loss for the purposes of LxEngine.
For example, below is a code snippet from the shader attribute instruction generation function (or see the latest version of the material source code for more details):
std::function<void()> Material::_generateInstruction(RasterizerGL* pRasterizer, const Attribute& attribute, lx0::lxvar& value) { ... if (attribute.name == "vertNormal") { return [=]() { auto& vboNormals = pRasterizer->mContext.spGeometry->mVboNormal; if (vboNormals) { gl->bindBuffer(GL_ARRAY_BUFFER, vboNormals); gl->vertexAttribPointer(location, 3, GL_FLOAT, GL_FALSE, 0, 0); gl->enableVertexAttribArray(location); } else gl->disableVertexAttribArray(location); check_glerror(); }; }
Setting a custom uniform
The non-standard unifTexture0 uniform is set somewhat differently. The material definition – in addition to the vertex and fragment shaders – also includes a simple JSON parameter description file. In this case, it contains only one parameter:
{ parameters: { unifTexture0 : "media2/textures/gradients/1d/suncopper_1-00.png" } }
In this case, the _generateInstruction() method loops over all unrecognized uniform names and searches for a user-specified parameter value for that uniform. In this case, it finds “unifTexture0″ as both an unrecognized uniform and a value in the parameter mapping.
Since the information about the uniform also includes the data type (GL_SAMPLER_1D), LxEngine can figure out to interpret that string value as an image filename, can load that file and store it in the texture cache, and generate an instruction to set that texture when activating the material:
else if (uniform.type == GL_SAMPLER_1D) { auto filename = value.as<std::string>(); TexturePtr spTexture = pRasterizer->mTextureCache.findOrCreate(filename ); GLuint textureId = spTexture->mId; // Activate the corresponding texture unit and set *that* to the GL id return [=]() { const auto unit = pRasterizer->mContext.textureUnit++; // Set the shader uniform to the *texture unit* containing the texture (NOT // the GL id of the texture) gl->uniform1i(loc, unit); gl->activeTexture(GL_TEXTURE0 + unit); gl->bindTexture(GL_TEXTURE_1D, textureId); // Set the parameters on the texture unit gl->texParameteri(GL_TEXTURE_1D, GL_TEXTURE_MAG_FILTER, mFilter); gl->texParameteri(GL_TEXTURE_1D, GL_TEXTURE_MIN_FILTER, mFilter); gl->enable(GL_TEXTURE_1D); check_glerror(); }; }
Adding simple shaders should be simple
The point really is that adding a simple shader, like this toon shader, is simple to do. The new material system in LxEngine makes it trivial as common uniforms and attributes are automatically set up and the mechanism for specifying custom uniforms is quite easy.
The objective is an engine designed to make experimentation and research simple.
What’s Next? LxEngine Tutorial 4
I’m currently working on cleaning up and writing up a good description of “Tutorial 4″ of LxEngine. I want to add a couple more effects to make the tutorial feel a bit more substantial first (perhaps add shadow mapping?), but would also like to get a finished tutorial out the door. As a preview, the fourth tutorial will include at least the following: writing an application via Javascript, geometry generated from scripts, multipass rendering, multithreading, time-lapse events, and…well, probably more if I don’t hurry up and finish this off!
JQuery Seamless Image Preview
I wrote a brief JQuery plug-in which transforms a normal <IMG> element into a dynamic, tiled version of the image with a slider for controlling the size of the image tiles.
Purpose
The purpose would be to preview quickly seamless textures. I wrote this mostly to get a bit more experience with HTML5 and JQuery.
I also like the idea of improving this enough that I could a site like OpenGameArt.org could use it for images tagged with ‘seamless’ – but we’ll see about that: it needs more polish before I would feel right contacting anyone over there.
Note: I’ve called this “version 0.2.0″ since this is really draft quality work: I haven’t written the docs (though the normal JQuery plug-in convention of $("#myimage").seamlessImage() will get you started pretty quickly), I haven’t done any unit testing (i.e. different layout scenarios, different browsers), there are some basic features that should probably be added, etc.
The absolutely minimal documentation is located here.
Demonstration
The demonstration below of the plug-in uses the Cobblestone.png from OpenGameArt.org. (The image was created by Saroman of the Wurm Online project).
Use the slider below the image to use the plug-in!

Implementation
- Uses the HTML5 “range” control to implement the slider
- The majority of the setup occurs on the “onLoad” callback of the Javascript Image object: this ensures the width and height are accurate during the setup. Otherwise, due to timing issues, the setup may occur while the image is still being loaded by the browser so the height/width will not be accurate and corrupt the setup.
- The JQuery $.data method is used to store the internal state of the plug-in
Conclusion
Anyway, good to get something demonstrable and graphical back up on the blog!
Bug
Interesting image from a typo causing LxEngine’s noise function to temporarily break:
All in all, the image suggests that canyon generation might be a good feature to add to the Terrain sample. At the moment, I’m ripping apart and restructuring the Terrain sample match some of the architectural developments in LxEngine over the last couple months (i.e. in short summary, cleaner and more concise MVC structuring to the classes). However, the Terrain sample currently renders the terrain as a surface and I have been tempted to move it to a voxel-based/Minecraft-like structure instead. We’ll see. Clean-up first.




