Skip to content

Commit fcaface

Browse files
author
Rui Wang
committedSep 9, 2016
Terrains with splat textures are fully supported
1 parent 3aaa545 commit fcaface

9 files changed

+186
-17
lines changed
 

‎README.md

+6-4
Original file line numberDiff line numberDiff line change
@@ -8,14 +8,16 @@ Note that the texture paths are always relative to Unity project folder, so you
88

99
## TODO List
1010
1. Support multiple texture maps (done)
11-
2. Support lightmaps (done)
12-
3. Use specified viewer (with a default shader) to show scene
11+
2. Support lightmaps and lightprobes (partly)
12+
3. Use specified viewer (with a default shader) to show scene (done)
1313
4. Support light and camera data outputs (partly)
14-
5. Change to different camera views in viewer
14+
5. Make use of dynamic lights from Forward+ pass
1515
6. Support game object and camera animations
1616
7. Support character data and animation outputs
1717
8. Play kinds of animations in viewer
1818
9. Support mesh collider data outputs (partly)
1919
10. Load and use colliders in physics engine integrations
2020
11. Support particle animations
21-
12. Support Unity legacy shaders and reimplement them in OSG
21+
12. Support Unity legacy shaders and reimplement them in OSG (partly)
22+
13. Support terrains and plants (partly)
23+
14. Support Unity 5.x standard PBR shader

‎viewer/CMakeLists.txt

+2
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,8 @@ SET(SOURCE_FILES
5555
SET(COMMON_SHADER_FILES
5656
Default.vert
5757
Default.frag
58+
Terrain.vert
59+
Terrain.frag
5860
)
5961

6062
SET(LEGACY_SHADER_FILES

‎viewer/Default.frag

+4-3
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
#version 130
12
varying vec4 gl_TexCoord[gl_MaxTextureCoords];
23
uniform sampler2D mainTexture;
34
uniform sampler2D lightTexture;
@@ -14,11 +15,11 @@ varying vec3 normalVec, tangentVec, binormalVec;
1415

1516
void main()
1617
{
17-
vec4 color = texture2D(mainTexture, gl_TexCoord[0].st);
18-
vec4 light = texture2D(lightTexture, gl_TexCoord[1].st);
18+
vec4 color = texture(mainTexture, gl_TexCoord[0].st);
19+
vec4 light = texture(lightTexture, gl_TexCoord[1].st);
1920

2021
vec3 lightDir = normalize(mat3(osg_ViewMatrix) * lightDirection);
2122
float diff = max(0.0, dot(normalVec.xyz, lightDir));
22-
gl_FragColor.rgb = color.rgb * light.rgb;
23+
gl_FragColor.rgb = color.rgb * light.rgb * lightColor * diff;
2324
gl_FragColor.a = color.a;
2425
}

‎viewer/Legacy_Shaders/Bumped_Diffuse.frag

+3-2
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
#version 130
12
varying vec4 gl_TexCoord[gl_MaxTextureCoords];
23
uniform sampler2D mainTexture;
34
uniform sampler2D normalTexture;
@@ -10,8 +11,8 @@ varying vec3 normalVec, tangentVec, binormalVec;
1011
void main()
1112
{
1213
vec2 uv = gl_TexCoord[0].st;
13-
vec4 color = texture2D(mainTexture, uv);
14-
vec4 normal = texture2D(normalTexture, uv);
14+
vec4 color = texture(mainTexture, uv);
15+
vec4 normal = texture(normalTexture, uv);
1516

1617
vec3 lightDir = normalize(mat3(osg_ViewMatrix) * lightDirection);
1718
float diff = max(0.0, dot(normalVec.xyz, lightDir));

‎viewer/Terrain.frag

+31
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
#version 130
2+
varying vec4 gl_TexCoord[gl_MaxTextureCoords];
3+
uniform sampler2DArray splatTexture;
4+
uniform sampler2D lightTexture;
5+
uniform sampler2D alphaTexture;
6+
uniform vec4 splatTilingOffsets[4];
7+
8+
uniform vec3 lightColor, lightDirection;
9+
uniform mat4 osg_ViewMatrix;
10+
11+
varying vec4 eyeVec;
12+
varying vec3 normalVec;
13+
14+
void main()
15+
{
16+
ivec3 size = textureSize(splatTexture, 0);
17+
vec4 alpha = texture(alphaTexture, gl_TexCoord[0].st);
18+
vec4 color = vec4(0.0, 0.0, 0.0, 1.0);
19+
vec4 light = texture(lightTexture, gl_TexCoord[1].st);
20+
for ( int i=0; i<size.z; ++i )
21+
{
22+
vec4 offset = splatTilingOffsets[i];
23+
vec3 uv = vec3(gl_TexCoord[0].st * offset.xy + offset.zw, float(i));
24+
color += texture(splatTexture, uv) * alpha[3 - i];
25+
}
26+
27+
vec3 lightDir = normalize(mat3(osg_ViewMatrix) * lightDirection);
28+
float diff = max(0.0, dot(normalVec.xyz, lightDir));
29+
gl_FragColor.rgb = color.rgb * light.rgb * lightColor * diff;
30+
gl_FragColor.a = color.a;
31+
}

‎viewer/Terrain.vert

+12
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
varying vec4 gl_TexCoord[gl_MaxTextureCoords];
2+
uniform mat4 gl_TextureMatrix[gl_MaxTextureCoords];
3+
varying vec4 eyeVec;
4+
varying vec3 normalVec;
5+
6+
void main()
7+
{
8+
gl_Position = ftransform();
9+
gl_TexCoord[0] = gl_TextureMatrix[0] * gl_MultiTexCoord0;
10+
normalVec = normalize(vec3(gl_NormalMatrix * gl_Normal));
11+
eyeVec = gl_ModelViewMatrix * gl_Vertex;
12+
}

‎viewer/terrain_data.cpp

+121-5
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
#include <osg/Texture2D>
2+
#include <osg/Texture2DArray>
13
#include <osgDB/FileUtils>
24
#include <osgDB/Registry>
35
#include <osgDB/Input>
@@ -19,9 +21,11 @@ void applyUserTerrains( TerrainDataProxyMap& tdMap, const std::string& dbPath )
1921
for ( short x=0; x<proxy->heightMapSize[0]; ++x )
2022
{
2123
int index = int(x) + int(y) * int(proxy->heightMapSize[0]);
22-
va->push_back( osg::Vec3(float(y) * proxy->size[2] / float(proxy->heightMapSize[1] - 1),
23-
proxy->heightMap[index] * proxy->size[1],
24-
float(x) * proxy->size[0] / float(proxy->heightMapSize[0] - 1)) );
24+
float tx = float(y) / float(proxy->heightMapSize[1] - 1);
25+
float ty = float(x) / float(proxy->heightMapSize[0] - 1);
26+
va->push_back( osg::Vec3(
27+
tx * proxy->size[2], proxy->heightMap[index] * proxy->size[1], ty * proxy->size[0]) );
28+
ta->push_back( osg::Vec2(ty, tx) );
2529
}
2630
}
2731

@@ -37,11 +41,63 @@ void applyUserTerrains( TerrainDataProxyMap& tdMap, const std::string& dbPath )
3741
}
3842
}
3943

44+
// Create splat texture array
45+
osg::ref_ptr<osg::Texture2DArray> splatTexture = new osg::Texture2DArray;
46+
splatTexture->setTextureDepth( proxy->layers );
47+
splatTexture->setWrap( osg::Texture2D::WRAP_S, osg::Texture2D::REPEAT );
48+
splatTexture->setWrap( osg::Texture2D::WRAP_T, osg::Texture2D::REPEAT );
49+
splatTexture->setFilter( osg::Texture2D::MIN_FILTER, osg::Texture2D::LINEAR_MIPMAP_LINEAR );
50+
splatTexture->setFilter( osg::Texture2D::MAG_FILTER, osg::Texture2D::LINEAR );
51+
52+
int splatW = 0, splatH = 0;
53+
for ( int i=0; i<proxy->layers; ++i )
54+
{
55+
osg::Image* image = osgDB::readImageFile(proxy->splatTextures[i]);
56+
splatTexture->setImage( i, image );
57+
58+
if ( !image ) { OSG_NOTICE << "Bad splat file " << proxy->splatTextures[i] << std::endl; }
59+
else if ( !splatW || !splatH ) { splatW = image->s(); splatH = image->t(); }
60+
else if ( splatW!=image->s() || splatH!=image->t() ) image->scaleImage(splatW, splatH, 1);
61+
}
62+
63+
// Create alpha texture
64+
unsigned int dataSize = proxy->alphaMaps.size() * sizeof(osg::Vec4ub);
65+
unsigned char* data = new unsigned char[dataSize];
66+
memcpy( data, (unsigned char*)&(proxy->alphaMaps[0]), dataSize );
67+
68+
osg::ref_ptr<osg::Image> alphaImage = new osg::Image;
69+
alphaImage->setImage( proxy->alphaMapSize[0], proxy->alphaMapSize[1], 1, GL_RGBA, GL_RGBA,
70+
GL_UNSIGNED_BYTE, data, osg::Image::USE_NEW_DELETE );
71+
72+
osg::ref_ptr<osg::Texture2D> alphaTexture = new osg::Texture2D( alphaImage.get() );
73+
alphaTexture->setWrap( osg::Texture2D::WRAP_S, osg::Texture2D::REPEAT );
74+
alphaTexture->setWrap( osg::Texture2D::WRAP_T, osg::Texture2D::REPEAT );
75+
alphaTexture->setFilter( osg::Texture2D::MIN_FILTER, osg::Texture2D::LINEAR_MIPMAP_LINEAR );
76+
alphaTexture->setFilter( osg::Texture2D::MAG_FILTER, osg::Texture2D::LINEAR );
77+
78+
// Create the terrain geometry
4079
osg::ref_ptr<osg::Geometry> geom = new osg::Geometry;
4180
geom->setVertexArray( va.get() );
42-
//geom->setTexCoordArray( 0, ta.get() );
81+
geom->setTexCoordArray( 0, ta.get() );
4382
geom->addPrimitiveSet( de.get() );
4483

84+
osg::StateSet* ss = geom->getOrCreateStateSet();
85+
ss->setTextureAttribute( 0, splatTexture.get() ); // TODO: lightmap at unit 1?
86+
ss->setTextureAttributeAndModes( 2, alphaTexture.get() );
87+
88+
osg::ref_ptr<osg::Program> program = new osg::Program;
89+
program->addShader( osgDB::readShaderFile(osg::Shader::VERTEX, dbPath + "/shaders/Terrain.vert") );
90+
program->addShader( osgDB::readShaderFile(osg::Shader::FRAGMENT, dbPath + "/shaders/Terrain.frag") );
91+
ss->setAttributeAndModes( program.get() );
92+
ss->addUniform( new osg::Uniform("splatTexture", (int)0) );
93+
ss->addUniform( new osg::Uniform("lightTexture", (int)1) );
94+
ss->addUniform( new osg::Uniform("alphaTexture", (int)2) );
95+
96+
osg::Uniform* splatTilingOffsetsUniform = ss->getOrCreateUniform(
97+
"splatTilingOffsets", osg::Uniform::FLOAT_VEC4, 4);
98+
for ( int i=0; i<proxy->layers; ++i )
99+
splatTilingOffsetsUniform->setElement( i, proxy->splatTilingOffsets[i] );
100+
45101
// Add normal and tangent array for the geometry
46102
osgUtil::SmoothingVisitor smv;
47103
smv.smooth( *geom );
@@ -85,7 +141,67 @@ bool TerrainData_readLocalData( osg::Object& obj, osgDB::Input& fr )
85141
iteratorAdvanced = true; ++fr;
86142
}
87143

88-
// TODO
144+
proxy.layers = 0;
145+
if ( fr.matchSequence("AlphaMap %i %i %i {") )
146+
{
147+
int w = 0, h = 0;
148+
fr[1].getInt(w); fr[2].getInt(h); fr[3].getInt(proxy.layers);
149+
proxy.alphaMapSize.set( w, h );
150+
proxy.alphaMaps.resize( w * h );
151+
proxy.splatTextures.resize( proxy.layers );
152+
proxy.splatTilingOffsets.resize( proxy.layers );
153+
154+
int entry0 = fr[0].getNoNestedBrackets();
155+
fr += 5;
156+
while ( !fr.eof() && fr[0].getNoNestedBrackets()>entry0 )
157+
{
158+
if ( fr.matchSequence("Layer %i {") )
159+
{
160+
int id = 0, index = 0;
161+
fr[1].getInt( id );
162+
163+
int entry = fr[0].getNoNestedBrackets();
164+
fr += 3;
165+
if ( id<4 )
166+
{
167+
while ( !fr.eof() && fr[0].getNoNestedBrackets()>entry )
168+
{
169+
float v = 0.0f; fr[0].getFloat(v);
170+
proxy.alphaMaps[index][3 - id] = unsigned char(v * 255.0f); // start from v.w
171+
++fr; ++index;
172+
}
173+
}
174+
else
175+
{
176+
OSG_WARN << "We only handle terrain with equal or less than 4 layers" << std::endl;
177+
while ( !fr.eof() && fr[0].getNoNestedBrackets()>entry ) ++fr;
178+
}
179+
++fr;
180+
}
181+
}
182+
iteratorAdvanced = true; ++fr;
183+
}
184+
185+
for ( int i=0; i<proxy.layers; ++i )
186+
{
187+
std::stringstream ss; ss << "Splat" << i << " %s %s";
188+
if ( fr.matchSequence(ss.str().c_str()) )
189+
{
190+
std::string texName = fr[1].getStr(), texPath = fr[2].getStr();
191+
proxy.splatTextures[i] = texPath;
192+
iteratorAdvanced = true; fr += 3;
193+
}
194+
195+
ss.str(""); ss << "SplatTilingOffset" << i << " %f %f %f %f";
196+
if ( fr.matchSequence(ss.str().c_str()) )
197+
{
198+
osg::Vec4 tilingOffset;
199+
for ( int n=0; n<4; ++n ) fr[1 + n].getFloat( tilingOffset[n] );
200+
proxy.splatTilingOffsets[i].set( tilingOffset[0], tilingOffset[1],
201+
tilingOffset[2], tilingOffset[3] );
202+
iteratorAdvanced = true; fr += 5;
203+
}
204+
}
89205
return iteratorAdvanced;
90206
}
91207

‎viewer/user_data_classes.h

+5-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
#ifndef H_UNITY2OSG_USERDATACLASSES
22
#define H_UNITY2OSG_USERDATACLASSES
33

4+
#include <osg/io_utils>
45
#include <osg/Program>
56
#include <osg/StateSet>
67
#include <osgDB/ReadFile>
@@ -28,9 +29,12 @@ struct TerrainDataProxy : public osg::Geometry
2829
virtual const char* className() const { return "Terrain"; }
2930

3031
std::vector<float> heightMap;
31-
std::vector< std::vector<float> > alphaMaps;
32+
std::vector<osg::Vec4ub> alphaMaps;
33+
std::vector<std::string> splatTextures;
34+
std::vector<osg::Vec4> splatTilingOffsets;
3235
osg::Vec2s heightMapSize, alphaMapSize;
3336
osg::Vec3 size;
37+
int layers;
3438
};
3539

3640
typedef std::map<ShaderDataProxy*, osg::StateSet*> ShaderDataProxyMap;

‎viewer/viewer.cpp

+2-2
Original file line numberDiff line numberDiff line change
@@ -79,8 +79,8 @@ int main( int argc, char** argv )
7979
if ( databasePath.empty() ) databasePath = ".";
8080

8181
LightUniforms sceneLight;
82-
sceneLight.color = new osg::Uniform("lightColor", osg::Vec3(1.0f, 1.0f, 0.9f));
83-
sceneLight.direction = new osg::Uniform("lightDirection", osg::Vec3(0.5f, 0.5f, -0.5f));
82+
sceneLight.color = new osg::Uniform("lightColor", osg::Vec3(1.0f, 1.0f, 1.0f));
83+
sceneLight.direction = new osg::Uniform("lightDirection", osg::Vec3(-0.5f, 0.0f, 0.5f));
8484

8585
// Build the scene graph
8686
osg::ref_ptr<osg::MatrixTransform> root = new osg::MatrixTransform;

0 commit comments

Comments
 (0)
Please sign in to comment.