Manta Interactive Ray Tracer Development Mailing List

Text archives Help


[MANTA] r1054 - in trunk: Interface Model/AmbientLights Model/Backgrounds Model/Materials Model/Primitives Model/TexCoordMappers Model/Textures StandAlone


Chronological Thread 
  • From: sparker@sci.utah.edu
  • To: manta@sci.utah.edu
  • Subject: [MANTA] r1054 - in trunk: Interface Model/AmbientLights Model/Backgrounds Model/Materials Model/Primitives Model/TexCoordMappers Model/Textures StandAlone
  • Date: Tue, 9 May 2006 22:42:49 -0600 (MDT)

Author: sparker
Date: Tue May  9 22:42:46 2006
New Revision: 1054

Modified:
   trunk/Interface/RayPacket.cc
   trunk/Interface/RayPacket.h
   trunk/Model/AmbientLights/ConstantAmbient.cc
   trunk/Model/Backgrounds/ConstantBackground.cc
   trunk/Model/Materials/Phong.cc
   trunk/Model/Materials/Phong.h
   trunk/Model/Primitives/Sphere.cc
   trunk/Model/TexCoordMappers/UniformMapper.cc
   trunk/Model/Textures/Constant.cc
   trunk/Model/Textures/Constant.h
   trunk/StandAlone/manta.cc
Log:
More optimizations to Phong
Several other vectorizations


Modified: trunk/Interface/RayPacket.cc
==============================================================================
--- trunk/Interface/RayPacket.cc        (original)
+++ trunk/Interface/RayPacket.cc        Tue May  9 22:42:46 2006
@@ -173,3 +173,31 @@
   flags |= HaveHitPositions;
 }
 
+void RayPacket::actualComputeNormals(const RenderContext& context)
+{
+  // Compute normals
+  for(int i=rayBegin;i<rayEnd;){
+    const Primitive* prim = data->hitPrim[i];
+    int tend = i+1;
+    while(tend < rayEnd && data->hitPrim[tend] == prim)
+      tend++;
+    RayPacket subPacket(*this, i, tend);
+    prim->computeNormal(context, subPacket);
+    // BTW, == has higher precedence than &, so mind the ()'s.
+    if ((subPacket.flags & HaveUnitNormals) == 0) {
+      // Normalize the normals if they haven't been.
+      for(int s=i;s<tend;++s){
+        Real sum = 0;
+        for(int j=0;j<3;++j)
+          sum += data->normal[j][s] * data->normal[j][s];
+        Real scale = 1/SCIRun::Sqrt(sum);
+        for(int j=0;j<3;++j)
+          data->normal[j][s] *= scale;
+      }
+    }
+    i=tend;
+  }
+
+  flags |= HaveNormals | HaveUnitNormals;
+}
+

Modified: trunk/Interface/RayPacket.h
==============================================================================
--- trunk/Interface/RayPacket.h (original)
+++ trunk/Interface/RayPacket.h Tue May  9 22:42:46 2006
@@ -12,6 +12,7 @@
 #include <Interface/Primitive.h>
 #include <Interface/TexCoordMapper.h>
 #include <RayPacketParameters.h>
+#include <MantaSSE.h>
 
 // #include <sgi_stl_warnings_off.h>
 // #include <algorithm>
@@ -318,10 +319,35 @@
 
     // Hit information
     void resetHits() {
-      for(int i=rayBegin;i<rayEnd;i++){
+#ifdef MANTA_SSE
+      int b = (rayBegin + 3) & (~3);
+      int e = rayEnd & (~3);
+      if(b == e){
+        for(int i = rayBegin; i < rayEnd; i++){
+          data->hitMatl[i] = 0;
+          data->minT[i] = MAXT;
+        }
+      } else {
+        int i = rayBegin;
+        for(;i<b;i++){
+          data->hitMatl[i] = 0;
+          data->minT[i] = MAXT;
+        }
+        for(;i<e;i+=4){
+          _mm_store_ps((float*)&data->hitMatl[i], _mm_setzero_ps());
+          _mm_store_ps(&data->minT[i], _mm_set1_ps(MAXT));
+        }
+        for(;i<rayEnd;i++){
+          data->hitMatl[i] = 0;
+          data->minT[i] = MAXT;
+        }
+      }
+#else
+      for(int i = rayBegin; i < rayEnd; i++){
         data->hitMatl[i] = 0;
         data->minT[i] = MAXT;
       }
+#endif
       flags |= HaveHitRecords;
     }
     void resetHit(int which) {
@@ -481,30 +507,7 @@
       if(flags & HaveNormals)
         return;
 
-      // Compute normals
-      for(int i=rayBegin;i<rayEnd;){
-        const Primitive* prim = data->hitPrim[i];
-        int tend = i+1;
-        while(tend < rayEnd && data->hitPrim[tend] == prim)
-          tend++;
-        RayPacket subPacket(*this, i, tend);
-        prim->computeNormal(context, subPacket);
-        // BTW, == has higher precedence than &, so mind the ()'s.
-        if ((subPacket.flags & HaveUnitNormals) == 0) {
-          // Normalize the normals if they haven't been.
-          for(int s=i;s<tend;++s){
-            Real sum = 0;
-            for(int j=0;j<3;++j)
-              sum += data->normal[j][s] * data->normal[j][s];
-            Real scale = 1/SCIRun::Sqrt(sum);
-            for(int j=0;j<3;++j)
-              data->normal[j][s] *= scale;
-          }
-        }
-        i=tend;
-      }
-
-      flags |= HaveNormals | HaveUnitNormals;
+      actualComputeNormals(context);
     }
 
     // Hit positions
@@ -553,6 +556,7 @@
   private:
     void actualNormalizeDirections();
     void actualComputeHitPositions();
+    void actualComputeNormals(const RenderContext& context);
 
     // Prevent accidental copying of RayPackets
     RayPacket(const RayPacket&);

Modified: trunk/Model/AmbientLights/ConstantAmbient.cc
==============================================================================
--- trunk/Model/AmbientLights/ConstantAmbient.cc        (original)
+++ trunk/Model/AmbientLights/ConstantAmbient.cc        Tue May  9 22:42:46 
2006
@@ -1,6 +1,7 @@
 
 #include <Model/AmbientLights/ConstantAmbient.h>
 #include <Interface/RayPacket.h>
+#include <MantaSSE.h>
 
 #include <sgi_stl_warnings_off.h>
 #include <sstream>
@@ -26,9 +27,37 @@
                                      RayPacket& rays,
                                      ColorArray ambient) const
 {
-  for(int i=rays.begin();i<rays.end();i++)
-    for(int j=0;j<Color::NumComponents;j++)
-      ambient[j][i] = color[j];
+#ifdef MANTA_SSE
+    int b = (rays.rayBegin + 3) & (~3);
+    int e = rays.rayEnd & (~3);
+    if(b == e){
+      for(int i = rays.begin(); i < rays.end(); i++){
+        for(int j=0;j<Color::NumComponents;j++)
+          ambient[j][i] = color[j];
+      }
+    } else {
+      int i = rays.rayBegin;
+      for(;i<b;i++){
+        for(int j=0;j<Color::NumComponents;j++)
+          ambient[j][i] = color[j];
+      }
+      RayPacketData* data = rays.data;
+      for(;i<e;i+=4){
+        _mm_store_ps(&ambient[0][i], _mm_set1_ps(color[0]));
+        _mm_store_ps(&ambient[1][i], _mm_set1_ps(color[1]));
+        _mm_store_ps(&ambient[2][i], _mm_set1_ps(color[2]));
+      }
+      for(;i<rays.rayEnd;i++){
+        for(int j=0;j<Color::NumComponents;j++)
+          ambient[j][i] = color[j];
+      }
+    }
+#else
+    for(int i = rays.begin(); i < rays.end(); i++){
+      for(int j=0;j<Color::NumComponents;j++)
+        ambient[j][i] = color[j];
+    }
+#endif
 }
 
 string ConstantAmbient::toString() const {

Modified: trunk/Model/Backgrounds/ConstantBackground.cc
==============================================================================
--- trunk/Model/Backgrounds/ConstantBackground.cc       (original)
+++ trunk/Model/Backgrounds/ConstantBackground.cc       Tue May  9 22:42:46 
2006
@@ -1,6 +1,7 @@
 
 #include <Model/Backgrounds/ConstantBackground.h>
 #include <Interface/RayPacket.h>
+#include <MantaSSE.h>
 
 using namespace Manta;
 
@@ -19,6 +20,31 @@
 
 void ConstantBackground::shade(const RenderContext&, RayPacket& rays) const
 {
-  for(int i=rays.begin();i<rays.end();i++)
-    rays.setColor(i, bgcolor);
+#ifdef MANTA_SSE
+    int b = (rays.rayBegin + 3) & (~3);
+    int e = rays.rayEnd & (~3);
+    if(b == e){
+      for(int i = rays.begin(); i < rays.end(); i++){
+        rays.setColor(i, bgcolor);
+      }
+    } else {
+      int i = rays.rayBegin;
+      for(;i<b;i++){
+        rays.setColor(i, bgcolor);
+      }
+      RayPacketData* data = rays.data;
+      for(;i<e;i+=4){
+        _mm_store_ps(&data->color[0][i], _mm_set1_ps(bgcolor[0]));
+        _mm_store_ps(&data->color[1][i], _mm_set1_ps(bgcolor[1]));
+        _mm_store_ps(&data->color[2][i], _mm_set1_ps(bgcolor[2]));
+      }
+      for(;i<rays.rayEnd;i++){
+        rays.setColor(i, bgcolor);
+      }
+    }
+#else
+    for(int i = rays.begin(); i < rays.end(); i++){
+      rays.setColor(i, bgcolor);
+    }
+#endif
 }

Modified: trunk/Model/Materials/Phong.cc
==============================================================================
--- trunk/Model/Materials/Phong.cc      (original)
+++ trunk/Model/Materials/Phong.cc      Tue May  9 22:42:46 2006
@@ -339,15 +339,94 @@
     RayPacketData rdata;
     RayPacket refl_rays(rdata, RayPacket::UnknownShape, rays.begin(), 
rays.end(),
                         rays.getDepth()+1, RayPacket::NormalizedDirections);
-    for(int i=rays.begin();i<rays.end();i++){
+#ifdef MANTA_SSE
+    int b = (rays.rayBegin + 3) & (~3);
+    int e = rays.rayEnd & (~3);
+    if(b == e){
+      for(int i = rays.begin(); i < rays.end(); i++){
+        Vector refl_dir = (rays.getDirection(i) -
+                           rays.getNormal(i)*(2*Dot(rays.getNormal(i), 
rays.getDirection(i) )));
+        refl_rays.setRay(i, rays.getHitPosition(i), refl_dir);
+        refl_rays.setImportance(i, rays.getImportance(i) * refl.data[i]);
+      }
+    } else {
+      int i = rays.rayBegin;
+      for(;i<b;i++){
+        Vector refl_dir = (rays.getDirection(i) -
+                           rays.getNormal(i)*(2*Dot(rays.getNormal(i), 
rays.getDirection(i) )));
+        refl_rays.setRay(i, rays.getHitPosition(i), refl_dir);
+        refl_rays.setImportance(i, rays.getImportance(i) * refl.data[i]);
+      }
+      RayPacketData* data = rays.data;
+      RayPacketData* refldata = refl_rays.data;
+      for(;i<e;i+=4){
+        __m128 dx = _mm_load_ps(&data->direction[0][i]);
+        __m128 dy = _mm_load_ps(&data->direction[1][i]);
+        __m128 dz = _mm_load_ps(&data->direction[2][i]);
+        __m128 normalx = _mm_load_ps(&data->normal[0][i]);
+        __m128 normaly = _mm_load_ps(&data->normal[1][i]);
+        __m128 normalz = _mm_load_ps(&data->normal[2][i]);
+        __m128 cos_theta = _mm_add_ps(_mm_add_ps(_mm_mul_ps(dx, normalx), 
_mm_mul_ps(dy, normaly)), _mm_mul_ps(dz, normalz));
+        __m128 scale = _mm_mul_ps(_mm_set1_ps(2.0f), cos_theta);
+        __m128 rx = _mm_sub_ps(dx, _mm_mul_ps(normalx, scale));
+        __m128 ry = _mm_sub_ps(dy, _mm_mul_ps(normaly, scale));
+        __m128 rz = _mm_sub_ps(dz, _mm_mul_ps(normalz, scale));
+        _mm_store_ps(&refldata->direction[0][i], rx);
+        _mm_store_ps(&refldata->direction[1][i], ry);
+        _mm_store_ps(&refldata->direction[2][i], rz);
+
+        _mm_store_ps(&refldata->origin[0][i], 
_mm_load_ps(&data->hitPosition[0][i]));
+        _mm_store_ps(&refldata->origin[1][i], 
_mm_load_ps(&data->hitPosition[1][i]));
+        _mm_store_ps(&refldata->origin[2][i], 
_mm_load_ps(&data->hitPosition[2][i]));
+        __m128 r = _mm_load_ps(&refl.data[i]);
+        _mm_store_ps(&refldata->importance[0][i], 
_mm_mul_ps(_mm_load_ps(&data->importance[0][i]), r));
+        _mm_store_ps(&refldata->importance[1][i], 
_mm_mul_ps(_mm_load_ps(&data->importance[1][i]), r));
+        _mm_store_ps(&refldata->importance[2][i], 
_mm_mul_ps(_mm_load_ps(&data->importance[2][i]), r));
+      }
+      for(;i<rays.rayEnd;i++){
+        Vector refl_dir = (rays.getDirection(i) -
+                           rays.getNormal(i)*(2*Dot(rays.getNormal(i), 
rays.getDirection(i) )));
+        refl_rays.setRay(i, rays.getHitPosition(i), refl_dir);
+        refl_rays.setImportance(i, rays.getImportance(i) * refl.data[i]);
+      }
+    }
+#else
+    for(int i = rays.begin(); i < rays.end(); i++){
       Vector refl_dir = (rays.getDirection(i) -
                          rays.getNormal(i)*(2*Dot(rays.getNormal(i), 
rays.getDirection(i) )));
       refl_rays.setRay(i, rays.getHitPosition(i), refl_dir);
       refl_rays.setImportance(i, rays.getImportance(i) * refl.data[i]);
     }
+#endif
+
     refl_rays.resetHits();
     context.renderer->traceRays(context, refl_rays);
-    for(int i=rays.begin();i<rays.end();i++)
+#ifdef MANTA_SSE
+    if(b == e){
+      for(int i = rays.begin(); i < rays.end(); i++){
+        rays.setColor(i, rays.getColor(i) + refl_rays.getColor(i) * 
refl.data[i]);
+      }
+    } else {
+      int i = rays.rayBegin;
+      for(;i<b;i++){
+        rays.setColor(i, rays.getColor(i) + refl_rays.getColor(i) * 
refl.data[i]);
+      }
+      RayPacketData* data = rays.data;
+      RayPacketData* refldata = refl_rays.data;
+      for(;i<e;i+=4){
+        __m128 r = _mm_load_ps(&refl.data[i]);        
+        _mm_store_ps(&data->color[0][i], 
_mm_add_ps(_mm_load_ps(&data->color[0][i]), 
_mm_mul_ps(_mm_load_ps(&refldata->color[0][i]), r)));
+        _mm_store_ps(&data->color[1][i], 
_mm_add_ps(_mm_load_ps(&data->color[1][i]), 
_mm_mul_ps(_mm_load_ps(&refldata->color[1][i]), r)));
+        _mm_store_ps(&data->color[2][i], 
_mm_add_ps(_mm_load_ps(&data->color[2][i]), 
_mm_mul_ps(_mm_load_ps(&refldata->color[2][i]), r)));
+      }
+      for(;i<rays.rayEnd;i++){
+        rays.setColor(i, rays.getColor(i) + refl_rays.getColor(i) * 
refl.data[i]);
+      }
+    }
+#else
+    for(int i = rays.begin(); i < rays.end(); i++){
       rays.setColor(i, rays.getColor(i) + refl_rays.getColor(i) * 
refl.data[i]);
+    }
+#endif
   }
 }

Modified: trunk/Model/Materials/Phong.h
==============================================================================
--- trunk/Model/Materials/Phong.h       (original)
+++ trunk/Model/Materials/Phong.h       Tue May  9 22:42:46 2006
@@ -15,7 +15,7 @@
   class Phong : public LitMaterial {
   public:
        
-               // Note if refl == 0 the phong shader won't cast a reflected 
ray.
+    // Note if refl == 0 the phong shader won't cast a reflected ray.
     Phong(const Color& diffuse, const Color& specular,
           int specpow, ColorComponent refl = 0);
     Phong(const Texture<Color>* diffuse, const Texture<Color>* specular,

Modified: trunk/Model/Primitives/Sphere.cc
==============================================================================
--- trunk/Model/Primitives/Sphere.cc    (original)
+++ trunk/Model/Primitives/Sphere.cc    Tue May  9 22:42:46 2006
@@ -185,8 +185,6 @@
         }
       }
 #endif
-      for(int i = rays.begin();i<rays.end();i++){
-      }
     }
     break;
   case RayPacket::ConstantOrigin:

Modified: trunk/Model/TexCoordMappers/UniformMapper.cc
==============================================================================
--- trunk/Model/TexCoordMappers/UniformMapper.cc        (original)
+++ trunk/Model/TexCoordMappers/UniformMapper.cc        Tue May  9 22:42:46 
2006
@@ -16,9 +16,33 @@
                                      RayPacket& rays) const
 {
   rays.computeHitPositions();
-  for(int i=rays.begin();i<rays.end();i++){
-    rays.setTexCoords(i, rays.getHitPosition(i));
-  }
+#ifdef MANTA_SSE
+    int b = (rays.rayBegin + 3) & (~3);
+    int e = rays.rayEnd & (~3);
+    if(b == e){
+      for(int i = rays.begin(); i < rays.end(); i++){
+        rays.setTexCoords(i, rays.getHitPosition(i));
+      }
+    } else {
+      int i = rays.rayBegin;
+      for(;i<b;i++){
+        rays.setTexCoords(i, rays.getHitPosition(i));
+      }
+      RayPacketData* data = rays.data;
+      for(;i<e;i+=4){
+        _mm_store_ps(&data->texCoords[0][i], 
_mm_load_ps(&data->hitPosition[0][i]));
+        _mm_store_ps(&data->texCoords[1][i], 
_mm_load_ps(&data->hitPosition[1][i]));
+        _mm_store_ps(&data->texCoords[2][i], 
_mm_load_ps(&data->hitPosition[2][i]));
+      }
+      for(;i<rays.rayEnd;i++){
+        rays.setTexCoords(i, rays.getHitPosition(i));
+      }
+    }
+#else
+    for(int i = rays.begin(); i < rays.end(); i++){
+      rays.setTexCoords(i, rays.getHitPosition(i));
+    }
+#endif
   rays.setFlag(RayPacket::HaveTexture2|RayPacket::HaveTexture3);
 }
 
@@ -26,9 +50,33 @@
                                      RayPacket& rays) const
 {
   rays.computeHitPositions();
-  for(int i=rays.begin();i<rays.end();i++){
-    rays.setTexCoords(i, rays.getHitPosition(i));
-  }
+#ifdef MANTA_SSE
+    int b = (rays.rayBegin + 3) & (~3);
+    int e = rays.rayEnd & (~3);
+    if(b == e){
+      for(int i = rays.begin(); i < rays.end(); i++){
+        rays.setTexCoords(i, rays.getHitPosition(i));
+      }
+    } else {
+      int i = rays.rayBegin;
+      for(;i<b;i++){
+        rays.setTexCoords(i, rays.getHitPosition(i));
+      }
+      RayPacketData* data = rays.data;
+      for(;i<e;i+=4){
+        _mm_store_ps(&data->texCoords[0][i], 
_mm_load_ps(&data->hitPosition[0][i]));
+        _mm_store_ps(&data->texCoords[1][i], 
_mm_load_ps(&data->hitPosition[1][i]));
+        _mm_store_ps(&data->texCoords[2][i], 
_mm_load_ps(&data->hitPosition[2][i]));
+      }
+      for(;i<rays.rayEnd;i++){
+        rays.setTexCoords(i, rays.getHitPosition(i));
+      }
+    }
+#else
+    for(int i = rays.begin(); i < rays.end(); i++){
+      rays.setTexCoords(i, rays.getHitPosition(i));
+    }
+#endif
   rays.setFlag(RayPacket::HaveTexture2|RayPacket::HaveTexture3);
 }
 

Modified: trunk/Model/Textures/Constant.cc
==============================================================================
--- trunk/Model/Textures/Constant.cc    (original)
+++ trunk/Model/Textures/Constant.cc    Tue May  9 22:42:46 2006
@@ -2,6 +2,70 @@
 #include <Model/Textures/Constant.h>
 #include <Interface/RayPacket.h>
 
-namespace Manta {
+using namespace Manta;
 
+template<>
+void Constant<Color>::mapValues(Packet<Color>& results,
+                                const RenderContext& context,
+                                RayPacket& rays) const
+{
+#ifdef MANTA_SSE
+  int b = (rays.rayBegin + 3) & (~3);
+  int e = rays.rayEnd & (~3);
+  if(b == e){
+    for(int i = rays.begin(); i < rays.end(); i++){
+      results.set(i, value);
+    }
+  } else {
+    int i = rays.rayBegin;
+    for(;i<b;i++){
+      results.set(i, value);
+    }
+    RayPacketData* data = rays.data;
+    for(;i<e;i+=4){
+      _mm_store_ps(&results.colordata[0][i], _mm_set1_ps(value[0]));
+      _mm_store_ps(&results.colordata[1][i], _mm_set1_ps(value[1]));
+      _mm_store_ps(&results.colordata[2][i], _mm_set1_ps(value[2]));
+    }
+    for(;i<rays.rayEnd;i++){
+      results.set(i, value);
+    }
+  }
+#else
+  for(int i = rays.begin(); i < rays.end(); i++){
+    results.set(i, value);
+  }
+#endif
+}
+
+template<>
+void Constant<float>::mapValues(Packet<float>& results,
+                                const RenderContext& context,
+                                RayPacket& rays) const
+{
+#ifdef MANTA_SSE
+  int b = (rays.rayBegin + 3) & (~3);
+  int e = rays.rayEnd & (~3);
+  if(b == e){
+    for(int i = rays.begin(); i < rays.end(); i++){
+      results.set(i, value);
+    }
+  } else {
+    int i = rays.rayBegin;
+    for(;i<b;i++){
+      results.set(i, value);
+    }
+    RayPacketData* data = rays.data;
+    for(;i<e;i+=4){
+      _mm_store_ps(&results.data[i], _mm_set1_ps(value));
+    }
+    for(;i<rays.rayEnd;i++){
+      results.set(i, value);
+    }
+  }
+#else
+  for(int i = rays.begin(); i < rays.end(); i++){
+    results.set(i, value);
+  }
+#endif
 }

Modified: trunk/Model/Textures/Constant.h
==============================================================================
--- trunk/Model/Textures/Constant.h     (original)
+++ trunk/Model/Textures/Constant.h     Tue May  9 22:42:46 2006
@@ -4,6 +4,7 @@
 
 #include <Interface/Texture.h>
 #include <Interface/RayPacket.h>
+#include <MantaSSE.h>
 
 namespace Manta {
   class RayPacket;
@@ -44,7 +45,17 @@
     for(int i=rays.begin();i<rays.end();i++)
       results.set(i, value);
   }
-}
 
+#ifdef MANTA_SSE
+  template<>
+    void Constant<Color>::mapValues(Packet<Color>& results,
+                                    const RenderContext& context,
+                                    RayPacket& rays) const;
+  template<>
+    void Constant<float>::mapValues(Packet<float>& results,
+                                    const RenderContext& context,
+                                    RayPacket& rays) const;
+#endif
+}
 
 #endif

Modified: trunk/StandAlone/manta.cc
==============================================================================
--- trunk/StandAlone/manta.cc   (original)
+++ trunk/StandAlone/manta.cc   Tue May  9 22:42:46 2006
@@ -1,5 +1,4 @@
 
-
 /*
   For more information, please see: http://software.sci.utah.edu
 
@@ -339,8 +338,6 @@
       else if (arg == "-stack") {
         if (!getStringArg(i,args,stack_file))
           usage(rtrt);
-      } else {
-        usage(rtrt);
       }
     }
 
@@ -473,9 +470,12 @@
         throw IllegalArgument( s, i, args );
       }
     } else if(arg == "-renderer"){
+      cerr << "renderer\n";
       string s;
-      if(!getStringArg(i, args, s))
+      if(!getStringArg(i, args, s)){
         usage(rtrt);
+        cerr << "oops\n";
+      }
       if(!rtrt->selectRenderer(s)){
         cerr << "Invalid renderer: " << s << ", available renderers are:\n";
         throw IllegalArgument( s, i, args );




  • [MANTA] r1054 - in trunk: Interface Model/AmbientLights Model/Backgrounds Model/Materials Model/Primitives Model/TexCoordMappers Model/Textures StandAlone, sparker, 05/09/2006

Archive powered by MHonArc 2.6.16.

Top of page