//---------------------------------------------------------------------------- void VolumeFog::CreateScene () { // Create a screen-space camera for the background image. mScreenCamera = ScreenTarget::CreateCamera(); // Create a screen polygon for the background image. VertexFormat* vformat = VertexFormat::Create(2, VertexFormat::AU_POSITION, VertexFormat::AT_FLOAT3, 0, VertexFormat::AU_TEXCOORD, VertexFormat::AT_FLOAT2, 0); mScreenPolygon = ScreenTarget::CreateRectangle(vformat, GetWidth(), GetHeight(), 0.0f, 1.0f, 0.0f, 1.0f, 1.0f); std::string skyName = Environment::GetPathR("BlueSky.wmtf"); Texture2D* skyTexture = Texture2D::LoadWMTF(skyName); Texture2DEffect* skyEffect = new0 Texture2DEffect(); mScreenPolygon->SetEffectInstance(skyEffect->CreateInstance(skyTexture)); // Create the scene graph for the terrain. mScene = new0 Node(); // Begin with a flat height field. vformat = VertexFormat::Create(3, VertexFormat::AU_POSITION, VertexFormat::AT_FLOAT3, 0, VertexFormat::AU_COLOR, VertexFormat::AT_FLOAT4, 0, VertexFormat::AU_TEXCOORD, VertexFormat::AT_FLOAT2, 0); mMesh = StandardMesh(vformat).Rectangle(64, 64, 8.0f, 8.0f); mScene->AttachChild(mMesh); // Set the heights based on a precomputed height field. Also create a // texture image to go with the height field. std::string heightFieldName = Environment::GetPathR("HeightField.wmtf"); Texture2D* heightTexture = Texture2D::LoadWMTF(heightFieldName); unsigned char* data = (unsigned char*)heightTexture->GetData(0); Float4 white(1.0f, 1.0f, 1.0f, 0.0f); VertexBufferAccessor vba(mMesh); for (int i = 0; i < vba.GetNumVertices(); ++i) { unsigned char value = *data; float height = 3.0f*value/255.0f + 0.05f*Mathf::SymmetricRandom(); *data++ = (unsigned char)Mathf::IntervalRandom(32.0f, 64.0f); *data++ = 3*(128 - value/2)/4; *data++ = 0; *data++ = 255; vba.Position<Float3>(i)[2] = height; // The fog color is white. The alpha channel is filled in by the // function UpdateFog(). vba.Color<Float4>(0, i) = white; } UpdateFog(); std::string effectFile = Environment::GetPathR("VolumeFog.wmfx"); VolumeFogEffect* effect = new0 VolumeFogEffect(effectFile); mMesh->SetEffectInstance(effect->CreateInstance(heightTexture)); }
//---------------------------------------------------------------------------- VisualEffectInstance* Texture2DEffect::CreateUniqueInstance ( Texture2D* texture, Shader::SamplerFilter filter, Shader::SamplerCoordinate coordinate0, Shader::SamplerCoordinate coordinate1) { Texture2DEffect* effect = new0 Texture2DEffect(); PixelShader* pshader = effect->GetPixelShader(); pshader->SetFilter(0, filter); pshader->SetCoordinate(0, 0, coordinate0); pshader->SetCoordinate(0, 1, coordinate1); return effect->CreateInstance(texture); }
//---------------------------------------------------------------------------- void ReflectionsAndShadows::CreatePlanes () { VertexFormat* vformat = VertexFormat::Create(2, VertexFormat::AU_POSITION, VertexFormat::AT_FLOAT3, 0, VertexFormat::AU_TEXCOORD, VertexFormat::AT_FLOAT2, 0); int vstride = vformat->GetStride(); // Create the floor mesh. VertexBuffer* vbuffer = new0 VertexBuffer(4, vstride); VertexBufferAccessor floor(vformat, vbuffer); float xValue = 128.0f; float yValue = 256.0f; float zValue = 0.0f; floor.Position<Float3>(0) = Float3(-xValue, -yValue, zValue); floor.Position<Float3>(1) = Float3(+xValue, -yValue, zValue); floor.Position<Float3>(2) = Float3(+xValue, +yValue, zValue); floor.Position<Float3>(3) = Float3(-xValue, +yValue, zValue); floor.TCoord<Float2>(0, 0) = Float2(0.0f, 0.0f); floor.TCoord<Float2>(0, 1) = Float2(1.0f, 0.0f); floor.TCoord<Float2>(0, 2) = Float2(1.0f, 1.0f); floor.TCoord<Float2>(0, 3) = Float2(0.0f, 1.0f); IndexBuffer* ibuffer = new0 IndexBuffer(6, sizeof(int)); int* indices = (int*)ibuffer->GetData(); indices[0] = 0; indices[1] = 1; indices[2] = 2; indices[3] = 0; indices[4] = 2; indices[5] = 3; mPlane0 = new0 TriMesh(vformat, vbuffer, ibuffer); Texture2DEffect* effect = new0 Texture2DEffect(Shader::SF_LINEAR_LINEAR, Shader::SC_REPEAT, Shader::SC_REPEAT); std::string path = Environment::GetPathR("Sand.wmtf"); Texture2D* texture = Texture2D::LoadWMTF(path); mPlane0->SetEffectInstance(effect->CreateInstance(texture)); mScene->AttachChild(mPlane0); // Create the wall mesh. vbuffer = new0 VertexBuffer(4, vstride); VertexBufferAccessor wall(vformat, vbuffer); xValue = -128.0f; yValue = 256.0f; zValue = 128.0f; wall.Position<Float3>(0) = Float3(xValue, -yValue, 0.0f); wall.Position<Float3>(1) = Float3(xValue, +yValue, 0.0f); wall.Position<Float3>(2) = Float3(xValue, +yValue, zValue); wall.Position<Float3>(3) = Float3(xValue, -yValue, zValue); wall.TCoord<Float2>(0, 0) = Float2(0.0f, 0.0f); wall.TCoord<Float2>(0, 1) = Float2(1.0f, 0.0f); wall.TCoord<Float2>(0, 2) = Float2(1.0f, 1.0f); wall.TCoord<Float2>(0, 3) = Float2(0.0f, 1.0f); mPlane1 = new0 TriMesh(vformat, vbuffer, ibuffer); path = Environment::GetPathR("Stone.wmtf"); texture = Texture2D::LoadWMTF(path); mPlane1->SetEffectInstance(effect->CreateInstance(texture)); mScene->AttachChild(mPlane1); }
//---------------------------------------------------------------------------- void CubeMaps::CreateScene () { // Create the root of the scene. mScene = new0 Node(); mWireState = new0 WireState(); mRenderer->SetOverrideWireState(mWireState); // Create the walls of the cube room. Each of the six texture images is // RGBA 64-by-64. Node* room = new0 Node(); mScene->AttachChild(room); // Index buffer shared by the room walls. IndexBuffer* ibuffer = new0 IndexBuffer(6, sizeof(int)); int* indices = (int*)ibuffer->GetData(); indices[0] = 0; indices[1] = 1; indices[2] = 3; indices[3] = 0; indices[4] = 3; indices[5] = 2; // The vertex format shared by the room walls. VertexFormat* vformat = VertexFormat::Create(2, VertexFormat::AU_POSITION, VertexFormat::AT_FLOAT3, 0, VertexFormat::AU_TEXCOORD, VertexFormat::AT_FLOAT2, 0); int vstride = vformat->GetStride(); VertexBufferAccessor vba; // The texture effect shared by the room walls. Texture2DEffect* effect = new0 Texture2DEffect(Shader::SF_LINEAR); VertexBuffer* vbuffer; TriMesh* wall; std::string textureName; // +x wall vbuffer = new0 VertexBuffer(4, vstride); vba.ApplyTo(vformat, vbuffer); vba.Position<Float3>(0) = Float3(+1.0f, -1.0f, -1.0f); vba.Position<Float3>(1) = Float3(+1.0f, -1.0f, +1.0f); vba.Position<Float3>(2) = Float3(+1.0f, +1.0f, -1.0f); vba.Position<Float3>(3) = Float3(+1.0f, +1.0f, +1.0f); vba.TCoord<Float2>(0, 0) = Float2(0.0f, 0.0f); vba.TCoord<Float2>(0, 1) = Float2(1.0f, 0.0f); vba.TCoord<Float2>(0, 2) = Float2(0.0f, 1.0f); vba.TCoord<Float2>(0, 3) = Float2(1.0f, 1.0f); wall = new0 TriMesh(vformat, vbuffer, ibuffer); room->AttachChild(wall); textureName = Environment::GetPathR("XpFace.wmtf"); Texture2D* xpTexture = Texture2D::LoadWMTF(textureName); wall->SetEffectInstance(effect->CreateInstance(xpTexture)); // -x wall vbuffer = new0 VertexBuffer(4, vstride); vba.ApplyTo(vformat, vbuffer); vba.Position<Float3>(0) = Float3(-1.0f, -1.0f, +1.0f); vba.Position<Float3>(1) = Float3(-1.0f, -1.0f, -1.0f); vba.Position<Float3>(2) = Float3(-1.0f, +1.0f, +1.0f); vba.Position<Float3>(3) = Float3(-1.0f, +1.0f, -1.0f); vba.TCoord<Float2>(0, 0) = Float2(0.0f, 0.0f); vba.TCoord<Float2>(0, 1) = Float2(1.0f, 0.0f); vba.TCoord<Float2>(0, 2) = Float2(0.0f, 1.0f); vba.TCoord<Float2>(0, 3) = Float2(1.0f, 1.0f); wall = new0 TriMesh(vformat, vbuffer, ibuffer); room->AttachChild(wall); textureName = Environment::GetPathR("XmFace.wmtf"); Texture2D* xmTexture = Texture2D::LoadWMTF(textureName); wall->SetEffectInstance(effect->CreateInstance(xmTexture)); // +y wall vbuffer = new0 VertexBuffer(4, vstride); vba.ApplyTo(vformat, vbuffer); vba.Position<Float3>(0) = Float3(+1.0f, +1.0f, +1.0f); vba.Position<Float3>(1) = Float3(-1.0f, +1.0f, +1.0f); vba.Position<Float3>(2) = Float3(+1.0f, +1.0f, -1.0f); vba.Position<Float3>(3) = Float3(-1.0f, +1.0f, -1.0f); vba.TCoord<Float2>(0, 0) = Float2(0.0f, 0.0f); vba.TCoord<Float2>(0, 1) = Float2(1.0f, 0.0f); vba.TCoord<Float2>(0, 2) = Float2(0.0f, 1.0f); vba.TCoord<Float2>(0, 3) = Float2(1.0f, 1.0f); wall = new0 TriMesh(vformat, vbuffer, ibuffer); room->AttachChild(wall); textureName = Environment::GetPathR("YpFace.wmtf"); Texture2D* ypTexture = Texture2D::LoadWMTF(textureName); wall->SetEffectInstance(effect->CreateInstance(ypTexture)); // -y wall vbuffer = new0 VertexBuffer(4, vstride); vba.ApplyTo(vformat, vbuffer); vba.Position<Float3>(0) = Float3(+1.0f, -1.0f, -1.0f); vba.Position<Float3>(1) = Float3(-1.0f, -1.0f, -1.0f); vba.Position<Float3>(2) = Float3(+1.0f, -1.0f, +1.0f); vba.Position<Float3>(3) = Float3(-1.0f, -1.0f, +1.0f); vba.TCoord<Float2>(0, 0) = Float2(0.0f, 0.0f); vba.TCoord<Float2>(0, 1) = Float2(1.0f, 0.0f); vba.TCoord<Float2>(0, 2) = Float2(0.0f, 1.0f); vba.TCoord<Float2>(0, 3) = Float2(1.0f, 1.0f); wall = new0 TriMesh(vformat, vbuffer, ibuffer); room->AttachChild(wall); textureName = Environment::GetPathR("YmFace.wmtf"); Texture2D* ymTexture = Texture2D::LoadWMTF(textureName); wall->SetEffectInstance(effect->CreateInstance(ymTexture)); // +z wall vbuffer = new0 VertexBuffer(4, vstride); vba.ApplyTo(vformat, vbuffer); vba.Position<Float3>(0) = Float3(+1.0f, -1.0f, +1.0f); vba.Position<Float3>(1) = Float3(-1.0f, -1.0f, +1.0f); vba.Position<Float3>(2) = Float3(+1.0f, +1.0f, +1.0f); vba.Position<Float3>(3) = Float3(-1.0f, +1.0f, +1.0f); vba.TCoord<Float2>(0, 0) = Float2(0.0f, 0.0f); vba.TCoord<Float2>(0, 1) = Float2(1.0f, 0.0f); vba.TCoord<Float2>(0, 2) = Float2(0.0f, 1.0f); vba.TCoord<Float2>(0, 3) = Float2(1.0f, 1.0f); wall = new0 TriMesh(vformat, vbuffer, ibuffer); room->AttachChild(wall); textureName = Environment::GetPathR("ZpFace.wmtf"); Texture2D* zpTexture = Texture2D::LoadWMTF(textureName); wall->SetEffectInstance(effect->CreateInstance(zpTexture)); // -z wall vbuffer = new0 VertexBuffer(4, vstride); vba.ApplyTo(vformat, vbuffer); vba.Position<Float3>(0) = Float3(-1.0f, -1.0f, -1.0f); vba.Position<Float3>(1) = Float3(+1.0f, -1.0f, -1.0f); vba.Position<Float3>(2) = Float3(-1.0f, +1.0f, -1.0f); vba.Position<Float3>(3) = Float3(+1.0f, +1.0f, -1.0f); vba.TCoord<Float2>(0, 0) = Float2(0.0f, 0.0f); vba.TCoord<Float2>(0, 1) = Float2(1.0f, 0.0f); vba.TCoord<Float2>(0, 2) = Float2(0.0f, 1.0f); vba.TCoord<Float2>(0, 3) = Float2(1.0f, 1.0f); wall = new0 TriMesh(vformat, vbuffer, ibuffer); room->AttachChild(wall); textureName = Environment::GetPathR("ZmFace.wmtf"); Texture2D* zmTexture = Texture2D::LoadWMTF(textureName); wall->SetEffectInstance(effect->CreateInstance(zmTexture)); // A sphere to reflect the environment via a cube map. The colors will // be used to modulate the cube map texture. vformat = VertexFormat::Create(3, VertexFormat::AU_POSITION, VertexFormat::AT_FLOAT3, 0, VertexFormat::AU_NORMAL, VertexFormat::AT_FLOAT3, 0, VertexFormat::AU_COLOR, VertexFormat::AT_FLOAT3, 0); vstride = vformat->GetStride(); mSphere = StandardMesh(vformat).Sphere(64, 64, 0.125f); room->AttachChild(mSphere); // Generate random vertex colors for the sphere. The StandardMesh class // produces a sphere with duplicated vertices along a longitude line. // This allows texture coordinates to be assigned in a manner that treats // the sphere as if it were a rectangle mesh. For vertex colors, we want // the duplicated vertices to have the same color, so a hash table is used // to look up vertex colors for the duplicates. vba.ApplyTo(mSphere); std::map<Float3,Float3> dataMap; for (int i = 0; i < vba.GetNumVertices(); ++i) { Float3& position = vba.Position<Float3>(i); Float3& color = vba.Color<Float3>(0, i); std::map<Float3,Float3>::iterator iter = dataMap.find(position); if (iter != dataMap.end()) { color = iter->second; } else { color[0] = 0.0f; color[1] = Mathf::IntervalRandom(0.5f, 0.75f); color[2] = Mathf::IntervalRandom(0.75f, 1.0f); dataMap.insert(std::make_pair(position, color)); } } // Create the cube map and attach it to the sphere. std::string effectFile = Environment::GetPathR("CubeMap.wmfx"); CubeMapEffect* cubeMapEffect = new0 CubeMapEffect(effectFile); ShaderFloat* reflectivity = new0 ShaderFloat(1); (*reflectivity)[0] = 0.5f; std::string cubeName = Environment::GetPathR("CubeMap.wmtf"); TextureCube* cubeTexture = TextureCube::LoadWMTF(cubeName); cubeTexture->GenerateMipmaps(); mCubeMapInstance = cubeMapEffect->CreateInstance(cubeTexture, reflectivity, false); mSphere->SetEffectInstance(mCubeMapInstance); // Allow culling to be disabled on the sphere so when you move inside // the sphere, you can see the previously hidden facets and verify that // the cube image for those facets is correctly oriented. mSphereCullState = cubeMapEffect->GetCullState(0, 0); }
//---------------------------------------------------------------------------- void ScreenPolygons::CreateScene () { // The screen camera is designed to map (x,y,z) in [0,1]^3 to (x',y,'z') // in [-1,1]^2 x [0,1]. mScreenCamera = new0 Camera(false); mScreenCamera->SetFrustum(0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 1.0f); mScreenCamera->SetFrame(APoint::ORIGIN, AVector::UNIT_Z, AVector::UNIT_Y, AVector::UNIT_X); // Load the biped just for some model to display. #ifdef WM5_LITTLE_ENDIAN std::string path = Environment::GetPathR("SkinnedBipedPN.wmof"); #else std::string path = Environment::GetPathR("SkinnedBipedPN.be.wmof"); #endif InStream source; source.Load(path); mScene = DynamicCast<Node>(source.GetObjectAt(0)); assertion(mScene != 0, "Error in biped stream.\n"); // The background is a textured screen polygon (z = 1). VertexFormat* vformat = VertexFormat::Create(2, VertexFormat::AU_POSITION, VertexFormat::AT_FLOAT3, 0, VertexFormat::AU_TEXCOORD, VertexFormat::AT_FLOAT2, 0); int vstride = vformat->GetStride(); VertexBuffer* vbuffer = new0 VertexBuffer(4, vstride); VertexBufferAccessor vba(vformat, vbuffer); vba.Position<Float3>(0) = Float3(0.0f, 0.0f, 1.0f); vba.Position<Float3>(1) = Float3(1.0f, 0.0f, 1.0f); vba.Position<Float3>(2) = Float3(1.0f, 1.0f, 1.0f); vba.Position<Float3>(3) = Float3(0.0f, 1.0f, 1.0f); vba.TCoord<Float2>(0, 0) = Float2(0.0f, 0.0f); vba.TCoord<Float2>(0, 1) = Float2(1.0f, 0.0f); vba.TCoord<Float2>(0, 2) = Float2(1.0f, 1.0f); vba.TCoord<Float2>(0, 3) = Float2(0.0f, 1.0f); IndexBuffer* ibuffer = new0 IndexBuffer(6, sizeof(int)); int* indices = (int*)ibuffer->GetData(); indices[0] = 0; indices[1] = 1; indices[2] = 2; indices[3] = 0; indices[4] = 2; indices[5] = 3; mBackPoly = new0 TriMesh(vformat, vbuffer, ibuffer); path = Environment::GetPathR("RedSky.wmtf"); Texture2DEffect* effect = new0 Texture2DEffect(Shader::SF_LINEAR); Texture2D* texture = Texture2D::LoadWMTF(path); mBackPoly->SetEffectInstance(effect->CreateInstance(texture)); // The middle polygon, which may be translated via '+' or '-'. vbuffer = new0 VertexBuffer(4, vstride); vba.ApplyTo(vformat, vbuffer); vba.Position<Float3>(0) = Float3(0.0f, 0.3f, 0.0f); vba.Position<Float3>(1) = Float3(1.0f, 0.3f, 0.0f); vba.Position<Float3>(2) = Float3(1.0f, 0.7f, 0.0f); vba.Position<Float3>(3) = Float3(0.0f, 0.7f, 0.0f); vba.TCoord<Float2>(0, 0) = Float2(0.0f, 0.3f); vba.TCoord<Float2>(0, 1) = Float2(1.0f, 0.3f); vba.TCoord<Float2>(0, 2) = Float2(1.0f, 0.7f); vba.TCoord<Float2>(0, 3) = Float2(0.0f, 0.7f); mMidPoly = new0 TriMesh(vformat, vbuffer, ibuffer); path = Environment::GetPathR("BallTexture.wmtf"); texture = Texture2D::LoadWMTF(path); mMidPoly->SetEffectInstance(effect->CreateInstance(texture)); mLinearZ = 1.0f; mDepthZ = 1.0f; mMidPoly->LocalTransform.SetTranslate(APoint(0.0f, 0.0f, mLinearZ)); // A portion of the foreground is a textured screen polygon (z = 0). vbuffer = new0 VertexBuffer(5, vstride); vba.ApplyTo(vformat, vbuffer); vba.Position<Float3>(0) = Float3(0.0f, 0.0f, 0.0f); vba.Position<Float3>(1) = Float3(0.5f, 0.0f, 0.0f); vba.Position<Float3>(2) = Float3(0.75f, 0.5f, 0.0f); vba.Position<Float3>(3) = Float3(0.5f, 0.75f, 0.0f); vba.Position<Float3>(4) = Float3(0.0f, 0.5f, 0.0f); vba.TCoord<Float2>(0, 0) = Float2(0.0f, 0.0f); vba.TCoord<Float2>(0, 1) = Float2(0.67f, 0.0f); vba.TCoord<Float2>(0, 2) = Float2(1.0f, 0.67f); vba.TCoord<Float2>(0, 3) = Float2(0.67f, 1.0f); vba.TCoord<Float2>(0, 4) = Float2(0.0f, 0.67f); ibuffer = new0 IndexBuffer(9, sizeof(int)); indices = (int*)ibuffer->GetData(); indices[0] = 0; indices[1] = 1; indices[2] = 2; indices[3] = 0; indices[4] = 2; indices[5] = 3; indices[6] = 0; indices[7] = 3; indices[8] = 4; mForePoly = new0 TriMesh(vformat, vbuffer, ibuffer); path = Environment::GetPathR("Flower.wmtf"); Texture2DEffect* foreEffect = new0 Texture2DEffect(Shader::SF_LINEAR); texture = Texture2D::LoadWMTF(path); mForePoly->SetEffectInstance(foreEffect->CreateInstance(texture)); // Make the foreground semitransparent. foreEffect->GetAlphaState(0, 0)->BlendEnabled = true; }
//---------------------------------------------------------------------------- void CollisionsBoundTree::CreateScene () { // The root of the scene will have two cylinders as children. mScene = new0 Node(); mWireState = new0 WireState(); mRenderer->SetOverrideWireState(mWireState); mCullState = new0 CullState(); mCullState->Enabled = false; mRenderer->SetOverrideCullState(mCullState); // Create a texture image to be used by both cylinders. Texture2D* texture = new0 Texture2D(Texture::TF_A8R8G8B8, 2, 2, 1); unsigned int* data = (unsigned int*)texture->GetData(0); data[0] = Color::MakeR8G8B8(0, 0, 255); // blue data[1] = Color::MakeR8G8B8(0, 255, 255); // cyan data[2] = Color::MakeR8G8B8(255, 0, 0); // red data[3] = Color::MakeR8G8B8(255, 255, 0); // yellow Texture2DEffect* effect = new0 Texture2DEffect(Shader::SF_LINEAR); // Create two cylinders, one short and thick, one tall and thin. VertexFormat* vformat = VertexFormat::Create(2, VertexFormat::AU_POSITION, VertexFormat::AT_FLOAT3, 0, VertexFormat::AU_TEXCOORD, VertexFormat::AT_FLOAT2, 0); StandardMesh sm(vformat); VertexBufferAccessor vba; int i; mCylinder0 = sm.Cylinder(8, 16, 1.0f, 2.0f, false); vba.ApplyTo(mCylinder0); for (i = 0; i < vba.GetNumVertices(); ++i) { vba.TCoord<Float2>(0, i) = mBlueUV; } mCylinder0->SetEffectInstance(effect->CreateInstance(texture)); mScene->AttachChild(mCylinder0); mCylinder1 = sm.Cylinder(16,8,0.25,4.0,false); vba.ApplyTo(mCylinder1); for (i = 0; i < vba.GetNumVertices(); ++i) { vba.TCoord<Float2>(0, i) = mRedUV; } mCylinder1->SetEffectInstance(effect->CreateInstance(texture)); mScene->AttachChild(mCylinder1); mScene->Update(); // Set up the collision system. Record0 handles the collision response. // Record1 is not given a callback so that 'double processing' of the // events does not occur. CTree* tree0 = new0 CTree(mCylinder0, 1, false); CRecord* record0 = new0 CRecord(tree0, 0, Response, this); CTree* tree1 = new0 CTree(mCylinder1, 1, false); CRecord* record1 = new0 CRecord(tree1, 0, 0, 0); mGroup = new0 CGroup(); mGroup->Add(record0); mGroup->Add(record1); ResetColors(); mGroup->TestIntersection(); }
//---------------------------------------------------------------------------- void Terrains::CreateScene () { // Create the root of the scene. mScene = new0 Node(); // Load and initialize the sky dome. It follows the camera. std::string skyMeshName = Environment::GetPathR("SkyDomePNT2.wmvf"); Visual::PrimitiveType type; VertexFormat* vformat; VertexBuffer* vbuffer; IndexBuffer* ibuffer; Visual::LoadWMVF(skyMeshName, type, vformat, vbuffer, ibuffer); mSkyDome = new0 TriMesh(vformat, vbuffer, ibuffer); mScene->AttachChild(mSkyDome); APoint skyPosition = mCamera->GetPosition(); skyPosition[2] = 0.0f; mSkyDome->LocalTransform.SetTranslate(skyPosition); mSkyDome->LocalTransform.SetUniformScale(mCamera->GetDMax()); Texture2DEffect* skyEffect = new0 Texture2DEffect( Shader::SF_LINEAR_LINEAR, Shader::SC_REPEAT, Shader::SC_REPEAT); std::string skyTextureName = Environment::GetPathR("SkyDome.wmtf"); Texture2D* skyTexture = Texture2D::LoadWMTF(skyTextureName); skyTexture->GenerateMipmaps(); mSkyDome->SetEffectInstance(skyEffect->CreateInstance(skyTexture)); // Load the height field and create the terrain. vformat = VertexFormat::Create(3, VertexFormat::AU_POSITION, VertexFormat::AT_FLOAT3, 0, VertexFormat::AU_TEXCOORD, VertexFormat::AT_FLOAT2, 0, VertexFormat::AU_TEXCOORD, VertexFormat::AT_FLOAT2, 1); // For lower-resolution terrain, change the paths to Height64/Color64 or // Height32/Color32. std::string heightName = ThePath + "Data/Height128/height"; std::string colorName = ThePath + "Data/Color128/color"; mTerrain = new0 Terrain(heightName, vformat, mCamera); mScene->AttachChild(mTerrain); // The effect that is shared across all pages. std::string effectFile = Environment::GetPathR("BaseMulDetailFogExpSqr.wmfx"); TerrainEffect* terrainEffect = new0 TerrainEffect(effectFile); std::string detailName = Environment::GetPathR("Detail.wmtf"); Texture2D* detailTexture = Texture2D::LoadWMTF(detailName); detailTexture->GenerateMipmaps(); ShaderFloat* fogColorDensity = new0 ShaderFloat(1); (*fogColorDensity)[0] = 0.5686f; (*fogColorDensity)[1] = 0.7255f; (*fogColorDensity)[2] = 0.8353f; (*fogColorDensity)[3] = 0.0015f; // Attach an effect to each page. Preload all resources to video memory. // This will avoid frame rate stalls when new terrain pages are // encountered as the camera moves. const int numRows = mTerrain->GetRowQuantity(); const int numCols = mTerrain->GetColQuantity(); for (int r = 0; r < numRows; ++r) { for (int c = 0; c < numCols; ++c) { TerrainPage* page = mTerrain->GetPage(r, c); char suffix[32]; sprintf(suffix, ".%d.%d.wmtf", r, c); std::string colorTextureName = colorName + std::string(suffix); Texture2D* colorTexture = Texture2D::LoadWMTF(colorTextureName); colorTexture->GenerateMipmaps(); VisualEffectInstance* instance = terrainEffect->CreateInstance( colorTexture, detailTexture, fogColorDensity); page->SetEffectInstance(instance); mRenderer->Bind(page->GetVertexBuffer()); mRenderer->Bind(page->GetVertexFormat()); mRenderer->Bind(page->GetIndexBuffer()); mRenderer->Bind(colorTexture); } } }
//---------------------------------------------------------------------------- void ClodMeshes::CreateScene () { mScene = new0 Node(); mTrnNode = new0 Node(); mScene->AttachChild(mTrnNode); mWireState = new0 WireState(); mRenderer->SetOverrideWireState(mWireState); // Load the face model. #ifdef WM5_LITTLE_ENDIAN std::string path = Environment::GetPathR("FacePN.wmof"); #else std::string path = Environment::GetPathR("FacePN.be.wmof"); #endif InStream inStream; inStream.Load(path); TriMeshPtr mesh = StaticCast<TriMesh>(inStream.GetObjectAt(0)); VertexBufferAccessor vba0(mesh); // Remove the normals and add texture coordinates. VertexFormat* vformat = VertexFormat::Create(2, VertexFormat::AU_POSITION, VertexFormat::AT_FLOAT3, 0, VertexFormat::AU_TEXCOORD, VertexFormat::AT_FLOAT2, 0); int vstride = vformat->GetStride(); VertexBuffer* vbuffer = new0 VertexBuffer(vba0.GetNumVertices(), vstride); VertexBufferAccessor vba1(vformat, vbuffer); float xmin = Mathf::MAX_REAL, xmax = -Mathf::MAX_REAL; float ymin = Mathf::MAX_REAL, ymax = -Mathf::MAX_REAL; int i; for (i = 0; i < vba0.GetNumVertices(); ++i) { Float3 position = vba0.Position<Float3>(i); vba1.Position<Float3>(i) = position; float x = position[0]; float y = position[2]; vba1.TCoord<Float2>(0, i) = Float2(x, y); if (x < xmin) { xmin = x; } if (x > xmax) { xmax = x; } if (y < ymin) { ymin = y; } if (y > ymax) { ymax = y; } } float xmult = 1.0f/(xmax - xmin); float ymult = 1.0f/(ymax - ymin); for (i = 0; i < vba1.GetNumVertices(); ++i) { Float2 tcoord = vba1.TCoord<Float2>(0, i); vba1.TCoord<Float2>(0,i) = Float2( (tcoord[0] - xmin)*xmult, (tcoord[1] - ymin)*ymult); } mesh->SetVertexFormat(vformat); mesh->SetVertexBuffer(vbuffer); // Create a texture for the face. Use the generated texture coordinates. Texture2DEffect* effect = new0 Texture2DEffect(Shader::SF_LINEAR); path = Environment::GetPathR("Magician.wmtf"); Texture2D* texture = Texture2D::LoadWMTF(path); #ifdef USE_CLOD_MESH // Create the collapse records to be shared by two CLOD meshes. int numRecords = 0; CollapseRecord* records = 0; CreateClodMesh ccm(mesh, numRecords, records); CollapseRecordArray* recordArray = new0 CollapseRecordArray(numRecords, records); mClod[0] = new0 ClodMesh(mesh, recordArray); mClod[0]->LocalTransform = mesh->LocalTransform; mClod[0]->LocalTransform.SetTranslate(mesh->LocalTransform.GetTranslate() - 150.0f*AVector::UNIT_X); mClod[0]->SetEffectInstance(effect->CreateInstance(texture)); mTrnNode->AttachChild(mClod[0]); mClod[1] = new0 ClodMesh(mesh, recordArray); mClod[1]->LocalTransform = mesh->LocalTransform; mClod[1]->LocalTransform.SetTranslate(mesh->LocalTransform.GetTranslate() + 150.0f*AVector::UNIT_X - 100.0f*AVector::UNIT_Y); mClod[1]->SetEffectInstance(effect->CreateInstance(texture)); mTrnNode->AttachChild(mClod[1]); mActive = mClod[0]; #else IndexBuffer* ibuffer = mesh->GetIndexBuffer(); TriMesh* face = new0 TriMesh(vformat, vbuffer,ibuffer); face->LocalTransform = mesh->LocalTransform; face->LocalTransform.SetTranslate(mesh->LocalTransform.GetTranslate() - 150.0f*AVector::UNIT_X); face->SetEffectInstance(effect->CreateInstance(texture)); mTrnNode->AttachChild(face); face = new0 TriMesh(vformat, vbuffer, ibuffer); face->LocalTransform = mesh->LocalTransform; face->LocalTransform.SetTranslate(mesh->LocalTransform.GetTranslate() + 150.0f*AVector::UNIT_X); face->SetEffectInstance(effect->CreateInstance(texture)); mTrnNode->AttachChild(face); #endif }
//---------------------------------------------------------------------------- void BillboardNodes::CreateScene () { mScene = new0 Node(); mCullState = new0 CullState(); mRenderer->SetOverrideCullState(mCullState); mWireState = new0 WireState(); mRenderer->SetOverrideWireState(mWireState); // All triangle meshes have this common vertex format. Use StandardMesh // to create these meshes. VertexFormat* vformat = VertexFormat::Create(2, VertexFormat::AU_POSITION, VertexFormat::AT_FLOAT3, 0, VertexFormat::AU_TEXCOORD, VertexFormat::AT_FLOAT2, 0); StandardMesh stdMesh(vformat); // Create the ground. It covers a square with vertices (1,1,0), (1,-1,0), // (-1,1,0), and (-1,-1,0). Multiply the texture coordinates by a factor // to enhance the wrap-around. mGround = stdMesh.Rectangle(2, 2, 16.0f, 16.0f); VertexBufferAccessor vba(mGround); int i; for (i = 0; i < vba.GetNumVertices(); ++i) { Float2& tcoord = vba.TCoord<Float2>(0, i); tcoord[0] *= 128.0f; tcoord[1] *= 128.0f; } // Create a texture effect for the ground. std::string path = Environment::GetPathR("Horizontal.wmtf"); Texture2D* texture = Texture2D::LoadWMTF(path); VisualEffectInstance* instance = Texture2DEffect::CreateUniqueInstance( texture, Shader::SF_LINEAR_LINEAR, Shader::SC_REPEAT, Shader::SC_REPEAT); mGround->SetEffectInstance(instance); mScene->AttachChild(mGround); // Create a rectangle mesh. The mesh is in the xy-plane. Do not apply // local transformations to the mesh. Use the billboard node transforms // to control the mesh location and orientation. mRectangle = stdMesh.Rectangle(2, 2, 0.125f, 0.25f); // Create a texture effect for the rectangle and for the torus. Texture2DEffect* geomEffect = new0 Texture2DEffect(Shader::SF_LINEAR); path = Environment::GetPathR("RedSky.wmtf"); texture = Texture2D::LoadWMTF(path); mRectangle->SetEffectInstance(geomEffect->CreateInstance(texture)); // Create a billboard node that causes a rectangle to always be facing // the camera. This is the type of billboard for an avatar. mBillboard0 = new0 BillboardNode(mCamera); mBillboard0->AttachChild(mRectangle); mScene->AttachChild(mBillboard0); // The billboard rotation is about its model-space up-vector (0,1,0). In // this application, world-space up is (0,0,1). Locally rotate the // billboard so it's up-vector matches the world's. mBillboard0->LocalTransform.SetTranslate(APoint(-0.25f, 0.0f, 0.25f)); mBillboard0->LocalTransform.SetRotate(HMatrix(AVector::UNIT_X, Mathf::HALF_PI)); // Create a torus mesh. Do not apply local transformations to the mesh. // Use the billboard node transforms to control the mesh location and // orientation. mTorus = StandardMesh(vformat, false).Torus(16, 16, 1.0f, 0.25f); mTorus->LocalTransform.SetUniformScale(0.1f); // Create a texture effect for the torus. It uses the RedSky image that // the rectangle uses. mTorus->SetEffectInstance(geomEffect->CreateInstance(texture)); // Create a billboard node that causes an object to always be oriented // the same way relative to the camera. mBillboard1 = new0 BillboardNode(mCamera); mBillboard1->AttachChild(mTorus); mScene->AttachChild(mBillboard1); // The billboard rotation is about its model-space up-vector (0,1,0). In // this application, world-space up is (0,0,1). Locally rotate the // billboard so it's up-vector matches the world's. mBillboard1->LocalTransform.SetTranslate(APoint(0.25f, 0.0f, 0.25f)); mBillboard1->LocalTransform.SetRotate(HMatrix(AVector::UNIT_X, Mathf::HALF_PI)); #ifdef DEMONSTRATE_VIEWPORT_BOUNDING_RECTANGLE // The screen camera is designed to map (x,y,z) in [0,1]^3 to (x',y,'z') // in [-1,1]^2 x [0,1]. mSSCamera = new0 Camera(false); mSSCamera->SetFrustum(0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 1.0f); mSSCamera->SetFrame(APoint::ORIGIN, AVector::UNIT_Z, AVector::UNIT_Y, AVector::UNIT_X); // Create a semitransparent screen rectangle. VertexFormat* ssVFormat = VertexFormat::Create(2, VertexFormat::AU_POSITION, VertexFormat::AT_FLOAT3, 0, VertexFormat::AU_COLOR, VertexFormat::AT_FLOAT4, 0); int ssVStride = ssVFormat->GetStride(); VertexBuffer* ssVBuffer = new0 VertexBuffer(4, ssVStride); VertexBufferAccessor ssVba(ssVFormat, ssVBuffer); Float4 ssColor(0.0f, 0.0f, 1.0f, 0.25f); ssVba.Position<Float3>(0) = Float3(0.0f, 0.0f, 0.0f); ssVba.Position<Float3>(1) = Float3(1.0f, 0.0f, 0.0f); ssVba.Position<Float3>(2) = Float3(1.0f, 1.0f, 0.0f); ssVba.Position<Float3>(3) = Float3(0.0f, 1.0f, 0.0f); ssVba.Color<Float4>(0, 0) = ssColor; ssVba.Color<Float4>(0, 1) = ssColor; ssVba.Color<Float4>(0, 2) = ssColor; ssVba.Color<Float4>(0, 3) = ssColor; IndexBuffer* ssIBuffer = new0 IndexBuffer(6, sizeof(int)); int* indices = (int*)ssIBuffer->GetData(); indices[0] = 0; indices[1] = 1; indices[2] = 2; indices[3] = 0; indices[4] = 2; indices[5] = 3; mSSRectangle = new0 TriMesh(ssVFormat, ssVBuffer, ssIBuffer); mSSRectangle->Update(); // Create a vertex color effect for the screen rectangle. VertexColor4Effect* ssEffect = new0 VertexColor4Effect(); mSSRectangle->SetEffectInstance(ssEffect->CreateInstance()); // Alpha blending must be enabled to obtain the semitransparency. ssEffect->GetAlphaState(0, 0)->BlendEnabled = true; #endif }
//---------------------------------------------------------------------------- void ParticleSystems::CreateScene () { mScene = new0 Node(); mWireState = new0 WireState(); mRenderer->SetOverrideWireState(mWireState); VertexFormat* vformat = VertexFormat::Create(2, VertexFormat::AU_POSITION, VertexFormat::AT_FLOAT3, 0, VertexFormat::AU_TEXCOORD, VertexFormat::AT_FLOAT2, 0); int vstride = vformat->GetStride(); const int numParticles = 32; VertexBuffer* vbuffer = new0 VertexBuffer(4*numParticles, vstride); Float4* positionSizes = new1<Float4>(numParticles); for (int i = 0; i < numParticles; ++i) { positionSizes[i][0] = Mathf::SymmetricRandom(); positionSizes[i][1] = Mathf::SymmetricRandom(); positionSizes[i][2] = Mathf::SymmetricRandom(); positionSizes[i][3] = 0.25f*Mathf::UnitRandom(); } Particles* particles = new0 Particles(vformat, vbuffer, sizeof(int), positionSizes, 1.0f); particles->AttachController(new0 BloodCellController()); mScene->AttachChild(particles); // Create an image with transparency. const int xsize = 32, ysize = 32; Texture2D* texture = new0 Texture2D(Texture::TF_A8R8G8B8, xsize, ysize, 1); unsigned char* data = (unsigned char*)texture->GetData(0); float factor = 1.0f/(xsize*xsize + ysize*ysize); for (int y = 0, i = 0; y < ysize; ++y) { for (int x = 0; x < xsize; ++x) { // The image is red. data[i++] = 0; data[i++] = 0; data[i++] = 255; // Semitransparent within a disk, dropping off to zero outside the // disk. int dx = 2*x - xsize; int dy = 2*y - ysize; float value = factor*(dx*dx + dy*dy); if (value < 0.125f) { value = Mathf::Cos(4.0f*Mathf::PI*value); } else { value = 0.0f; } data[i++] = (unsigned char)(255.0f*value); } } Texture2DEffect* effect = new0 Texture2DEffect(Shader::SF_LINEAR); effect->GetAlphaState(0, 0)->BlendEnabled = true; effect->GetDepthState(0, 0)->Enabled = false; particles->SetEffectInstance(effect->CreateInstance(texture)); }
//---------------------------------------------------------------------------- void SwitchNodes::CreateScene () { mScene = new0 Node(); mWireState = new0 WireState(); mRenderer->SetOverrideWireState(mWireState); mSwitch = new0 SwitchNode(); mScene->AttachChild(mSwitch); // Texture effect to be shared by all objects. Texture2DEffect* effect = new0 Texture2DEffect(Shader::SF_LINEAR); std::string path = Environment::GetPathR("Flower.wmtf"); Texture2D* texture = Texture2D::LoadWMTF(path); // Create the children of the switch node. VertexFormat* vformat = VertexFormat::Create(2, VertexFormat::AU_POSITION, VertexFormat::AT_FLOAT3, 0, VertexFormat::AU_TEXCOORD, VertexFormat::AT_FLOAT2, 0); StandardMesh sm(vformat); // Create a rectangle mesh (child 0). TriMesh* mesh = sm.Rectangle(4, 4, 1.0f, 1.0f); mesh->SetEffectInstance(effect->CreateInstance(texture)); mSwitch->AttachChild(mesh); // Create a disk mesh (child 1). mesh = sm.Disk(8,16,1.0f); mesh->SetEffectInstance(effect->CreateInstance(texture)); mSwitch->AttachChild(mesh); // Create a box mesh (child 2). mesh = sm.Box(1.0f,0.5f,0.25f); mesh->SetEffectInstance(effect->CreateInstance(texture)); mSwitch->AttachChild(mesh); // Create a closed cylinder mesh (child 3). mesh = sm.Cylinder(8,16,1.0f,2.0f,false); mesh->SetEffectInstance(effect->CreateInstance(texture)); mSwitch->AttachChild(mesh); // Create a sphere mesh (child 4). mesh = sm.Sphere(32,16,1.0f); mesh->SetEffectInstance(effect->CreateInstance(texture)); mSwitch->AttachChild(mesh); // Create a torus mesh (child 5). mesh = sm.Torus(16,16,1.0f,0.25f); mesh->SetEffectInstance(effect->CreateInstance(texture)); mSwitch->AttachChild(mesh); // Create a tetrahedron (child 6). mesh = sm.Tetrahedron(); mesh->SetEffectInstance(effect->CreateInstance(texture)); mSwitch->AttachChild(mesh); // Create a hexahedron (child 7). mesh = sm.Hexahedron(); mesh->SetEffectInstance(effect->CreateInstance(texture)); mSwitch->AttachChild(mesh); // Create an octahedron (child 8). mesh = sm.Octahedron(); mesh->SetEffectInstance(effect->CreateInstance(texture)); mSwitch->AttachChild(mesh); // Create a dodecahedron (child 9). mesh = sm.Dodecahedron(); mesh->SetEffectInstance(effect->CreateInstance(texture)); mSwitch->AttachChild(mesh); // Create an icosahedron (child 10). mesh = sm.Icosahedron(); mesh->SetEffectInstance(effect->CreateInstance(texture)); mSwitch->AttachChild(mesh); // Set the active child (otherwise it is invalid). mSwitch->SetActiveChild(0); }
//---------------------------------------------------------------------------- void BspNodes::CreateScene () { // Create the scene graph. // // 1. The rectangles represent the BSP planes of the BSP tree. They // share a VertexColor3Effect. You can see a plane from either side // (backface culling disabled). The planes do not interfere with view // of the solid objects (wirestate enabled). // // 2. The sphere, tetrahedron, and cube share a TextureEffect. These // objects are convex. The backfacing triangles are discarded // (backface culling enabled). The front facing triangles are drawn // correctly by convexity, so depthbuffer reads are disabled and // depthbuffer writes are enabled. The BSP-based sorting of objects // guarantees that front faces of convex objects in the foreground // are drawn after the front faces of convex objects in the background, // which allows us to set the depthbuffer state as we have. That is, // BSPNode sorts from back to front. // // 3. The torus has backface culling enabled and depth buffering enabled. // This is necessary, because the torus is not convex. // // 4. Generally, if all objects are opaque, then you want to draw from // front to back with depth buffering fully enabled. You need to // reverse-order the elements of the visible set before drawing. If // any of the objects are semitransparent, then drawing back to front // is the correct order to handle transparency. However, you do not // get the benefit of early z-rejection for opaque objects. A better // BSP sorter needs to be built to produce a visible set with opaque // objects listed first (front-to-back order) and semitransparent // objects listed last (back-to-front order). // // scene // ground // bsp0 // bsp1 // bsp3 // torus // rectangle3 // sphere // rectangle1 // tetrahedron // rectangle0 // bsp2 // cube // rectangle2 // octahedron mScene = new0 Node(); // Create the ground. It covers a square with vertices (1,1,0), (1,-1,0), // (-1,1,0), and (-1,-1,0). Multiply the texture coordinates by a factor // to enhance the wrap-around. VertexFormat* vformat = VertexFormat::Create(2, VertexFormat::AU_POSITION, VertexFormat::AT_FLOAT3, 0, VertexFormat::AU_TEXCOORD, VertexFormat::AT_FLOAT2, 0); StandardMesh sm(vformat); VertexBufferAccessor vba; TriMesh* ground = sm.Rectangle(2, 2, 16.0f, 16.0f); vba.ApplyTo(ground); for (int i = 0; i < vba.GetNumVertices(); ++i) { Float2& tcoord = vba.TCoord<Float2>(0, i); tcoord[0] *= 128.0f; tcoord[1] *= 128.0f; } std::string path = Environment::GetPathR("Horizontal.wmtf"); Texture2D* texture = Texture2D::LoadWMTF(path); ground->SetEffectInstance(Texture2DEffect::CreateUniqueInstance(texture, Shader::SF_LINEAR_LINEAR, Shader::SC_REPEAT, Shader::SC_REPEAT)); mScene->AttachChild(ground); // Partition the region above the ground into 5 convex pieces. Each plane // is perpendicular to the ground (not required generally). VertexColor3Effect* vceffect = new0 VertexColor3Effect(); vceffect->GetCullState(0, 0)->Enabled = false; vceffect->GetWireState(0, 0)->Enabled = true; Vector2f v0(-1.0f, 1.0f); Vector2f v1(1.0f, -1.0f); Vector2f v2(-0.25f, 0.25f); Vector2f v3(-1.0f, -1.0f); Vector2f v4(0.0f, 0.0f); Vector2f v5(1.0f, 0.5f); Vector2f v6(-0.75f, -7.0f/12.0f); Vector2f v7(-0.75f, 0.75f); Vector2f v8(1.0f, 1.0f); BspNode* bsp0 = CreateNode(v0, v1, vceffect, Float3(1.0f, 0.0f, 0.0f)); BspNode* bsp1 = CreateNode(v2, v3, vceffect, Float3(0.0f, 0.5f, 0.0f)); BspNode* bsp2 = CreateNode(v4, v5, vceffect, Float3(0.0f, 0.0f, 1.0f)); BspNode* bsp3 = CreateNode(v6, v7, vceffect, Float3(0.0f, 0.0f, 0.0f)); bsp0->AttachPositiveChild(bsp1); bsp0->AttachNegativeChild(bsp2); bsp1->AttachPositiveChild(bsp3); // Attach an object in each convex region. float height = 0.1f; Vector2f center; TriMesh* mesh; // The texture effect for the convex objects. Texture2DEffect* cvxeffect = new0 Texture2DEffect(Shader::SF_LINEAR_LINEAR); cvxeffect->GetDepthState(0, 0)->Enabled = false; cvxeffect->GetDepthState(0, 0)->Writable = true; // The texture effect for the torus. Texture2DEffect* toreffect = new0 Texture2DEffect(Shader::SF_LINEAR_LINEAR); // The texture image shared by the objects. path = Environment::GetPathR("Flower.wmtf"); texture = Texture2D::LoadWMTF(path); // Region 0: Create a torus mesh. mesh = sm.Torus(16, 16, 1.0f, 0.25f); mesh->SetEffectInstance(toreffect->CreateInstance(texture)); mesh->LocalTransform.SetUniformScale(0.1f); center = (v2 + v6 + v7)/3.0f; mesh->LocalTransform.SetTranslate(APoint(center[0], center[1], height)); bsp3->AttachPositiveChild(mesh); // Region 1: Create a sphere mesh. mesh = sm.Sphere(32, 16, 1.0f); mesh->SetEffectInstance(cvxeffect->CreateInstance(texture)); mesh->LocalTransform.SetUniformScale(0.1f); center = (v0 + v3 + v6 + v7)/4.0f; mesh->LocalTransform.SetTranslate(APoint(center[0], center[1], height)); bsp3->AttachNegativeChild(mesh); // Region 2: Create a tetrahedron. mesh = sm.Tetrahedron(); mesh->SetEffectInstance(cvxeffect->CreateInstance(texture)); mesh->LocalTransform.SetUniformScale(0.1f); center = (v1 + v2 + v3)/3.0f; mesh->LocalTransform.SetTranslate(APoint(center[0], center[1], height)); bsp1->AttachNegativeChild(mesh); // Region 3: Create a hexahedron (cube). mesh = sm.Hexahedron(); mesh->SetEffectInstance(cvxeffect->CreateInstance(texture)); mesh->LocalTransform.SetUniformScale(0.1f); center = (v1 + v4 + v5)/3.0f; mesh->LocalTransform.SetTranslate(APoint(center[0], center[1], height)); bsp2->AttachPositiveChild(mesh); // Region 4: Create an octahedron. mesh = sm.Octahedron(); mesh->SetEffectInstance(cvxeffect->CreateInstance(texture)); mesh->LocalTransform.SetUniformScale(0.1f); center = (v0 + v4 + v5 + v8)/4.0f; mesh->LocalTransform.SetTranslate(APoint(center[0], center[1], height)); bsp2->AttachNegativeChild(mesh); mScene->AttachChild(bsp0); }