Texture Splatting

If you are a new Irrlicht Engine user, and have a newbie-question, this is the forum for you. You may also post general programming questions here.
jaeg
Posts: 52
Joined: Thu Jun 28, 2007 11:20 pm

Re: Texture Splatting

Post by jaeg »

http://www.filedropper.com/textureatlas
Here's the textures (it's approximately 9mb)

Here's the most recent shaders:
Vector Shader

Code: Select all

void main()
{
gl_TexCoord[0] = gl_MultiTexCoord0;
gl_TexCoord[1] = gl_MultiTexCoord1;
gl_Position = ftransform();
gl_FogFragCoord = gl_Position.z;
}
Fragment Shader:

Code: Select all

uniform sampler2D splatMap;
uniform sampler2D textureAtlas;
uniform sampler2D normalAtlas;
uniform vec3 lightPosition;
 
 
float getDistance(vec2 p1, vec2 p2){
    return length(p1 - p2);
}
                            
void main(){
 
    float fog = (gl_Fog.end - gl_FogFragCoord) * gl_Fog.scale;
 
    if (fog > .2)
    {
    vec2 texCoord = (fract(gl_TexCoord[1].xy)* 0.25);
    vec3 light_pos = normalize(lightPosition) + vec3(1,1,0);  
 
    //Layer 1
    vec3 normalRed = normalize(texture2D(normalAtlas, texCoord).rgb * 2.0 - 1.0); 
    vec3 normalGreen = normalize(texture2D(normalAtlas, texCoord + vec2(.25,0)).rgb * 2.0 - 1.0); 
    vec3 normalBlue = normalize(texture2D(normalAtlas, texCoord + vec2(.50,0)).rgb * 2.0 - 1.0); 
 
    vec4 SplatCol=texture2D(splatMap,gl_TexCoord[0].xy/4);
 
    float diffuse = max(dot(normalRed, light_pos), 0.0); 
    vec4 tex = texture2D(textureAtlas,texCoord);
    vec4 RedCol=vec4(diffuse * tex.rgb, tex.a);
    
    diffuse = max(dot(normalGreen, light_pos), 0.0); 
    tex = texture2D(textureAtlas,texCoord + vec2(.25,0));
    vec4 GreenCol=vec4(diffuse * tex.rgb, tex.a);
 
    diffuse = max(dot(normalBlue, light_pos), 0.0); 
    tex = texture2D(textureAtlas,texCoord + vec2(.50,0));
    vec4 BlueCol=vec4(diffuse * tex.rgb, tex.a );
 
 
    vec4 layer1 = (vec4(SplatCol.r*RedCol+SplatCol.g*GreenCol+SplatCol.b*BlueCol)*vec4(1,1,1,SplatCol.a));
 
    //Layer2
    normalRed = normalize(texture2D(normalAtlas, texCoord + vec2(.75,0)).rgb * 2.0 - 1.0); 
    normalGreen = normalize(texture2D(normalAtlas, texCoord +  vec2(0,.25)).rgb * 2.0 - 1.0); 
    normalBlue = normalize(texture2D(normalAtlas, texCoord + vec2(.25,.25)).rgb * 2.0 - 1.0); 
 
    SplatCol=texture2D(splatMap,gl_TexCoord[0].xy/4 + vec2(.25,0));
 
    diffuse = max(dot(normalRed, light_pos), 0.0); 
    tex = texture2D(textureAtlas,texCoord + vec2(.75,0));
    RedCol=vec4(diffuse * tex.rgb, tex.a);
    
    diffuse = max(dot(normalGreen, light_pos), 0.0); 
    tex = texture2D(textureAtlas,texCoord + vec2(0,.25));
    GreenCol=vec4(diffuse * tex.rgb, tex.a);
 
    diffuse = max(dot(normalBlue, light_pos), 0.0); 
    tex = texture2D(textureAtlas,texCoord + vec2(.25,.25));
    BlueCol=vec4(diffuse * tex.rgb, tex.a );
 
    vec4 layer2 = (vec4(SplatCol.r*RedCol+SplatCol.g*GreenCol+SplatCol.b*BlueCol)*vec4(1,1,1,SplatCol.a));
 
 
    //Lightmap
    vec4 ambientLight = vec4(.3,.3,.3,1);
    vec4 LightMapCol =texture2D(splatMap,gl_TexCoord[0].xy/4 + vec2(.50,0));
 
    vec4 color = mix(layer1,layer2,SplatCol.a)*(ambientLight + LightMapCol);
    
    gl_FragColor = mix(gl_Fog.color, color, fog);
    }
    else
    {
        gl_FragColor = gl_Fog.color;
    }
}
 
The new version also applies fog to the terrain based on the fog information Irrlicht passes to the shader. So whatever you set with driver->setFog() will affect the shader. Just setting the fog in Irrlicht without applying it in the shader manually doesn't work. Regular lighting does not work either it seems.

As a mild optimization any pixels that'll appear mostly black are not operated on by most of the shader. I have most of the functionality I want so now I'm going to refactor it to make it cleaner and more efficient. I'm also going to wrap up a new terrain scene node class so that it'll be easier to apply everything.
Computer Science Major - Ball State University
hendu
Posts: 2600
Joined: Sat Dec 18, 2010 12:53 pm

Re: Texture Splatting

Post by hendu »

Might want to check the built-in function "distance()" ;)
jaeg
Posts: 52
Joined: Thu Jun 28, 2007 11:20 pm

Re: Texture Splatting

Post by jaeg »

I tried using the distance function but I was getting really weird behaviors. I wanted to use it originally to not even look at fragments after a certain distance from the camera position which I passed to the shader from the callback. But it would not color in weird ways such as only coloring areas that are the farthest from me or as I moved from one side to the other the black color would move from one edge to another. I then tried a getDistance function I found online that didn't do so well either. Once I stumbled upon how to use native fog commands (because that was my goal in general) I just dropped the distance functions altogether. I just forgot to delete it from the shader.

I did some refactoring by getting rid of duplicate code and add some preprocessing to be able to disable the fog (I might change this to be something that is passable through the callback). It is also a lot easier now to add new layers.

Code: Select all

uniform sampler2D splatMap;
uniform sampler2D textureAtlas;
uniform sampler2D normalAtlas;
uniform vec3 lightPosition;
#define NUMBER_OF_COLOR_MAPS 2
#define USE_FOG
 
 
vec4 getTexelFromAtlas(sampler2D atlas,vec2 coord, vec2 offset)
{
    return texture2D(atlas, coord + offset); 
}
 
vec3 getNormalFromAtlas(sampler2D atlas, vec2 coord, vec2 offset)
{
    return normalize(getTexelFromAtlas(atlas,coord,offset).rgb * 2.0 - 1.0);
}
 
vec4 generateLayer(vec2 texCoord, vec3 light_pos, vec2 colorMapCoord, vec2 redTextureCoord, vec2 greenTextureCoord, vec2 blueTextureCoord)
{
        //Obtain normals for normalAtlas
        vec3 normalRed = getNormalFromAtlas(normalAtlas, texCoord, redTextureCoord);
        vec3 normalGreen = getNormalFromAtlas(normalAtlas, texCoord, greenTextureCoord);
        vec3 normalBlue = getNormalFromAtlas(normalAtlas, texCoord, blueTextureCoord);
        
        //Generate diffuse colors
        float diffuseRed = max(dot(normalRed, light_pos), 0.0); 
        float diffuseGreen = max(dot(normalGreen, light_pos), 0.0);
        float diffuseBlue = max(dot(normalBlue, light_pos), 0.0);
        
        //Get color from color map
        vec4 SplatCol=getTexelFromAtlas(splatMap,gl_TexCoord[0].xy*.25,colorMapCoord);
        
        //Get colors from appropriate colors
        vec4 tex = getTexelFromAtlas(textureAtlas,texCoord,redTextureCoord);
        vec4 RedCol=vec4(diffuseRed * tex.rgb, tex.a);
        
        tex = getTexelFromAtlas(textureAtlas,texCoord,greenTextureCoord);
        vec4 GreenCol=vec4(diffuseGreen * tex.rgb, tex.a);
 
        tex = getTexelFromAtlas(textureAtlas,texCoord,blueTextureCoord);
        vec4 BlueCol=vec4(diffuseBlue * tex.rgb, tex.a );
 
        //Mix and return
        return (vec4(SplatCol.r*RedCol+SplatCol.g*GreenCol+SplatCol.b*BlueCol)*vec4(1,1,1,SplatCol.a));
}
 
void main(){
 
    #ifdef USE_FOG
    //Calculate fog
    float fog = (gl_Fog.end - gl_FogFragCoord) * gl_Fog.scale;
    
    if (fog > .2)
    {
    #endif
        vec2 texCoord = (fract(gl_TexCoord[1].xy)* 0.25);
        vec3 light_pos = normalize(lightPosition) + vec3(1,1,0);  
 
        vec4 layer1 = generateLayer(texCoord,light_pos,vec2(0,0), vec2(0,0), vec2(0.25,0), vec2(0.50,0));
        vec4 layer2 = generateLayer(texCoord,light_pos,vec2(0.25,0), vec2(0.75,0), vec2(0,0.25), vec2(0.25,0.25));
 
        //Mix layers
        vec4 color = mix(layer1,layer2,layer2.a);
 
        //Lightmap
        vec4 ambientLight = vec4(.3,.3,.3,1);
        vec4 LightMapCol =texture2D(splatMap,gl_TexCoord[0].xy/4 + vec2(.50,0));
 
        //Apply lightmap
        color = color*(ambientLight + LightMapCol);
        
        //Apply fog
        #ifdef USE_FOG
        color = mix(gl_Fog.color, color, fog);
        #endif
        gl_FragColor = color;
    #ifdef USE_FOG
    }
    else
    {
        gl_FragColor = gl_Fog.color;
    }
    #endif
}
 


EDIT: Added full terrain normal mapping and shadowing. It's kind of weird though, it seems that the normal map is actually doing more of the shadowing work than the lightmapping is. Is this normal? I can literally get rid of the lightmap and see hardly any change but if I get rid of the normal map everything has hardly any shading again. I've been fiddling around with it but really the only thing I ended up doing was getting rid of the lightmap and just added a way for the ambient light to effect the darkness of the bump mapping (it would end up too dark otherwise). I'm going to probably just say, "If it looks right it is right"
Image
Computer Science Major - Ball State University
mongoose7
Posts: 1227
Joined: Wed Apr 06, 2011 12:13 pm

Re: Texture Splatting

Post by mongoose7 »

Hmm, I can't understand your philosophy - crap code will always show its heritage.

Haven't you got a real problem with lightPos? To do normal mapping you have to perform calculations in "tangent space". Passing the light position in to the fragment shader as a uniform will certainly not work. If you want to do normal mapping, you should research it a bit more.
jaeg
Posts: 52
Joined: Thu Jun 28, 2007 11:20 pm

Re: Texture Splatting

Post by jaeg »

Actually it's a phrase from the book Game Coding Complete and again from a Game Physics book. ;) Not intending to make crap code but when you are working on a simulation that just has to appear correct (IE games) it doesn't matter if the method behind the effect is scientifically correct. Especially true for physics.

The shader I have posted is different from what created the picture (I know it wasn't long ago that I posted it but a lot changed in the 5 hours between edits). I'm using a fix point of light and was going off of this tutorial http://www.swiftless.com/tutorials/glsl ... pping.html but was playing around with sending in some various inputs and forgot to take it out when I posted. I'm doing research but I'm also just kind of fiddling around with things by myself to see what I can figure out myself.


EDIT -
I looked up more about uniform variables and it does explain some issues I had with some attempts I was making.
Computer Science Major - Ball State University
jaeg
Posts: 52
Joined: Thu Jun 28, 2007 11:20 pm

Re: Texture Splatting

Post by jaeg »

I found and followed this tutorial: http://www.ozone3d.net/tutorials/bump_mapping.php

I'm getting a lot nicer results now but it doesn't play very well with the LOD of the terrain. Whenever the terrain switches to a lower LOD I end up with black spots on the simplified geometry.
Image

Vertex shader:

Code: Select all

varying vec3 lightVec;
varying vec3 eyeVec;
attribute vec3 vTangent;
 
void main()
{
    gl_Position = ftransform();
    gl_TexCoord[0] = gl_MultiTexCoord0;
    gl_TexCoord[1] = gl_MultiTexCoord1;
    gl_FogFragCoord = gl_Position.z;
    
    vec3 n = normalize(gl_NormalMatrix * gl_Normal);
    vec3 t = normalize(gl_NormalMatrix * vTangent);
    vec3 b = cross(n, t);
    
    vec3 vVertex = vec3(gl_ModelViewMatrix * gl_Vertex);
    vec3 tmpVec = gl_LightSource[0].position.xyz - vVertex;
    
    lightVec.x = dot(tmpVec, t);
    lightVec.y = dot(tmpVec, b);
    lightVec.z = dot(tmpVec, n);
    
    tmpVec = -vVertex;
    eyeVec.x = dot(tmpVec, t);
    eyeVec.y = dot(tmpVec, b);
    eyeVec.z = dot(tmpVec, n);
}
Fragment:

Code: Select all

varying vec3 lightVec;
varying vec3 eyeVec;
uniform sampler2D effectAtlas;
uniform sampler2D textureAtlas;
uniform sampler2D normalAtlas;
uniform float invRadius;
 
 
//#define USE_FOG
 
 
vec4 getTexelFromAtlas(sampler2D atlas,vec2 coord, vec2 offset)
{
    return texture2D(atlas, coord + offset); 
}
 
vec3 getNormalFromAtlas(sampler2D atlas, vec2 coord, vec2 offset)
{
    return normalize(getTexelFromAtlas(atlas,coord,offset).xyz) * 2.0 - 1.0;
}
 
vec4 generateLayer(vec2 texCoord, vec2 colorMapCoord, vec2 redTextureCoord, vec2 greenTextureCoord, vec2 blueTextureCoord)
{
        //Get color from color map
        vec4 SplatCol=getTexelFromAtlas(effectAtlas,gl_TexCoord[0].xy*.25,colorMapCoord);
        
        //Get colors from appropriate colors
        vec4 tex = getTexelFromAtlas(textureAtlas,texCoord,redTextureCoord);
        vec4 RedCol=tex;//vec4(diffuseRed * tex.rgb, tex.a);
        
        tex = getTexelFromAtlas(textureAtlas,texCoord,greenTextureCoord);
        vec4 GreenCol=tex;//vec4(diffuseGreen * tex.rgb, tex.a);
 
        tex = getTexelFromAtlas(textureAtlas,texCoord,blueTextureCoord);
        vec4 BlueCol=tex;//vec4(diffuseBlue * tex.rgb, tex.a );
 
        //Mix and return
        return (vec4(SplatCol.r*RedCol+SplatCol.g*GreenCol+SplatCol.b*BlueCol)*vec4(1,1,1,SplatCol.a));
}
 
void main(){
 
    #ifdef USE_FOG
    //Calculate fog
    float fog = (gl_Fog.end - gl_FogFragCoord) * gl_Fog.scale;
    
    if (fog > .1)
    {
    #endif
        vec2 texCoord = (fract(gl_TexCoord[1].xy)* 0.25);  
 
        //Generate Layers
        vec4 layer1 = generateLayer(texCoord,vec2(0,0), vec2(0,0), vec2(0.25,0), vec2(0.50,0));
        vec4 layer2 = generateLayer(texCoord,vec2(0.25,0), vec2(0.75,0), vec2(0,0.25), vec2(0.25,0.25));
 
        //Mix layers
        vec4 color = mix(layer1,layer2,layer2.a);
 
        //Bump Mapping
        float distSqr = dot(lightVec, lightVec);
        float att = clamp(1.0 - invRadius * sqrt(distSqr), 0.0, 1.0);
        vec3 lVec = lightVec * inversesqrt(distSqr);
        
        vec3 vVec = normalize(eyeVec);
        vec3 bump = getNormalFromAtlas(effectAtlas, gl_TexCoord[0].xy*.25, vec2(0.75,0));
        
        vec4 vAmbient = gl_LightSource[0].ambient * gl_FrontMaterial.ambient;
        
        float diffuse = max(dot(lVec, bump), 0.1);
        vec4 vDiffuse = gl_LightSource[0].diffuse * gl_FrontMaterial.diffuse * diffuse;
        
        float specular = pow(clamp(dot(reflect(-lVec, bump), vVec), 0.0, 1.0), 
                     gl_FrontMaterial.shininess );
    
        vec4 vSpecular = gl_LightSource[0].specular * gl_FrontMaterial.specular * 
                     specular;  
    
        
        color = (vAmbient*color + vDiffuse*color + vSpecular) * att;
        
        //Apply fog
        #ifdef USE_FOG
        color = mix(gl_Fog.color, color, fog);
        #endif
        
        gl_FragColor = color;
    #ifdef USE_FOG
    }
    else
    {
        gl_FragColor = gl_Fog.color;
    }
    #endif
}
 
I'm also starting to come under the assumption that Irricht LightSceneNodes are added to the gl_LightSource array. I've tried messing with its location in Irrlicht and I am not seeing any change.

EDIT -
Figured out the light issue. I was forgetting to pass a value to the invRadius variable.

EDIT EDIT -
So apparently on my machine I can't use gl_FrontMaterial and I have to make sure I set everything in ILightSceneNode as floats in Irrlicht. I ended up manually sending in material information to the shader from the terrain and now the shader appears to be working correctly! I'm still having issues with the LOD screwing things up some however.
Computer Science Major - Ball State University
mongoose7
Posts: 1227
Joined: Wed Apr 06, 2011 12:13 pm

Re: Texture Splatting

Post by mongoose7 »

vec3 tmpVec = gl_LightSource[0].position.xyz - vVertex;

The first one is in model space and the second one is in view space. You can't subtract them.

Here's a clue: if you move the camera and the lighting changes, you've made an error.
jaeg
Posts: 52
Joined: Thu Jun 28, 2007 11:20 pm

Re: Texture Splatting

Post by jaeg »

As far as I can tell the lighting doesn't change when I move the camera. I'll test it more tomorrow though to see if it is happening.

This is what is being produced so far:
Image

The mesh here is completely smooth without shaders.

This is the source I got the bump mapping from.
http://www.ozone3d.net/tutorials/bump_mapping_p4.php
Computer Science Major - Ball State University
Distorion
Posts: 12
Joined: Thu Jul 19, 2012 1:58 am
Location: Canberra, Australia

Re: Texture Splatting

Post by Distorion »

Any chance you could post your full IShaderConstantSetCallBack class and functions i am still having problems.

Thanks!
jaeg
Posts: 52
Joined: Thu Jun 28, 2007 11:20 pm

Re: Texture Splatting

Post by jaeg »

Here's the most recent listing. Please note I haven't had a chance yet to investigate what mongoose7 is talking about yet.
OnSetConstants

Code: Select all

void AdvanceTerrain::OnSetConstants(video::IMaterialRendererServices* services, s32 userData)
{
        int layer0 = 0;
        int layer1 = 1;
        int layer2 = 2;
        float invRadius = 0.00003f;
        video::SColorf ambient(.3f,.3f,.3f,1.f);
        video::SColorf diffuse(.8f,.8f,.8f,1.f);
        video::SColorf specular(.5f,.5f,.5f,1.f);
        float shininess = .9f;
 
        services->setPixelShaderConstant("effectAtlas",&layer0,1);
        services->setPixelShaderConstant("textureAtlas",&layer1,1);
        services->setPixelShaderConstant("normalAtlas",&layer2,1);
        services->setPixelShaderConstant("invRadius",&invRadius,1);
        services->setPixelShaderConstant("mAmbient", reinterpret_cast<f32*>(&ambient),4);
        services->setPixelShaderConstant("mDiffuse",reinterpret_cast<f32*>(&diffuse),4);
        services->setPixelShaderConstant("mShininess",&shininess,1);
        services->setPixelShaderConstant("mSpecular",reinterpret_cast<f32*>(&specular),4);
    
}
Fragment:

Code: Select all

varying vec3 lightVec;
varying vec3 eyeVec;
uniform sampler2D effectAtlas;
uniform sampler2D textureAtlas;
uniform sampler2D normalAtlas;
uniform float invRadius;
uniform vec4 mAmbient;
uniform vec4 mDiffuse;
uniform vec4 mSpecular;
uniform float mShininess;
//#define USE_FOG
#define USE_BUMP
 
 
vec4 getTexelFromAtlas(sampler2D atlas,vec2 coord, vec2 offset)
{
    return texture2D(atlas, coord + offset); 
}
 
vec3 getNormalFromAtlas(sampler2D atlas, vec2 coord, vec2 offset)
{
    return normalize(getTexelFromAtlas(atlas,coord,offset).xyz) * 2.0 - 1.0;
}
 
vec4 generateLayer(vec2 texCoord, vec2 colorMapCoord, vec2 redTextureCoord, vec2 greenTextureCoord, vec2 blueTextureCoord)
{
        //Get color from color map
        vec4 SplatCol=getTexelFromAtlas(effectAtlas,gl_TexCoord[0].xy*.25,colorMapCoord);
        
        //Get colors from appropriate colors
        vec4 tex = getTexelFromAtlas(textureAtlas,texCoord,redTextureCoord);
        vec4 RedCol=tex;//vec4(diffuseRed * tex.rgb, tex.a);
        
        tex = getTexelFromAtlas(textureAtlas,texCoord,greenTextureCoord);
        vec4 GreenCol=tex;//vec4(diffuseGreen * tex.rgb, tex.a);
 
        tex = getTexelFromAtlas(textureAtlas,texCoord,blueTextureCoord);
        vec4 BlueCol=tex;//vec4(diffuseBlue * tex.rgb, tex.a );
 
        //Mix and return
        return (vec4(SplatCol.r*RedCol+SplatCol.g*GreenCol+SplatCol.b*BlueCol)*vec4(1,1,1,SplatCol.a));
}
 
void main(){
 
    #ifdef USE_FOG
    //Calculate fog
    float fog = (gl_Fog.end - gl_FogFragCoord) * gl_Fog.scale;
    
    if (fog > .1)
    {
    #endif
        vec2 texCoord = (fract(gl_TexCoord[1].xy)* 0.25);  
 
        //Generate Layers
        vec4 layer1 = generateLayer(texCoord,vec2(0,0), vec2(0,0), vec2(0.25,0), vec2(0.50,0));
        vec4 layer2 = generateLayer(texCoord,vec2(0.25,0), vec2(0.75,0), vec2(0,0.25), vec2(0.25,0.25));
 
        //Mix layers
        vec4 color = mix(layer1,layer2,layer2.a);
 
        #ifdef USE_BUMP
        //Bump Mapping
        float distSqr = dot(lightVec, lightVec);
        float att = clamp(1.0 - invRadius * sqrt(distSqr), 0.0, 1.0);
        vec3 lVec = lightVec * inversesqrt(distSqr);
        
        vec3 vVec = normalize(eyeVec);
        vec3 bump = getNormalFromAtlas(effectAtlas, gl_TexCoord[0].xy*.25, vec2(0.75,0));
        
        vec4 vAmbient = gl_LightSource[0].ambient * mAmbient;
        
        
        float diffuse = max(dot(lVec, bump), 0.0);
        vec4 vDiffuse = gl_LightSource[0].diffuse * mDiffuse * diffuse;
        
 
        float specular = pow(clamp(dot(reflect(-lVec, bump), vVec), 0.0, 1.0), 
                     mShininess );
        vec4 vSpecular = gl_LightSource[0].specular * mSpecular * specular; 
    
        color = (vAmbient*color + vDiffuse*color + vSpecular) * att;
        
        //color = vSpecular;
        #endif
        //Apply fog
        #ifdef USE_FOG
        color = mix(gl_Fog.color, color, fog);
        #endif
        gl_FragColor = color;
    #ifdef USE_FOG
    }
    else
    {
        gl_FragColor = gl_Fog.color;
    }
    #endif
}
 
 
 
Vertex

Code: Select all

varying vec3 lightVec;
varying vec3 eyeVec;
attribute vec3 vTangent;
void main()
{
    gl_Position = ftransform();
    gl_TexCoord[0] = gl_MultiTexCoord0;
    gl_TexCoord[1] = gl_MultiTexCoord1;
    gl_FogFragCoord = gl_Position.z;
    
    vec3 n = normalize(gl_NormalMatrix * gl_Normal);
    vec3 t = normalize(gl_NormalMatrix * vTangent);
    vec3 b = cross(n, t);
    
    vec3 vVertex = vec3(gl_ModelViewMatrix * gl_Vertex);
    vec3 tmpVec = gl_LightSource[0].position.xyz  - vVertex;
    
    lightVec.x = dot(tmpVec, t);
    lightVec.y = dot(tmpVec, b);
    lightVec.z = dot(tmpVec, n);
    
    tmpVec = -vVertex;
    eyeVec.x = dot(tmpVec, t);
    eyeVec.y = dot(tmpVec, b);
    eyeVec.z = dot(tmpVec, n);
}
EDIT
I've set the light to a fixed position (before I had it just attached to the camera) and I'm noticing weird artifacts on the opposite sides on the hills that the light is on:
Image

It appears to be the specular lights messing up for some reason.
Computer Science Major - Ball State University
Post Reply