//---------------------------------------------------------------------------- bool FxCompiler::CreateEffect (const Program& vProgram, const Program& pProgram) { InputArray vInputs, pInputs; OutputArray vOutputs, pOutputs; ConstantArray vConstants, pConstants; SamplerArray vSamplers, pSamplers; if (!Process(vProgram, vInputs, vOutputs, vConstants, vSamplers)) { return false; } if (!Process(pProgram, pInputs, pOutputs, pConstants, pSamplers)) { return false; } mVShader = (VertexShader*)CreateShader(true, vProgram, vInputs, vOutputs, vConstants, vSamplers); mPShader = (PixelShader*)CreateShader(false, pProgram, pInputs, pOutputs, pConstants, pSamplers); VisualPass* pass = new0 VisualPass(); pass->SetVertexShader(mVShader); pass->SetPixelShader(mPShader); // TODO. Once Cg FX files are parsed, the global state from each pass // should be set here. For now, the application is responsible for // setting the global state after the *.wmfx file is loaded. pass->SetAlphaState(new0 AlphaState()); pass->SetCullState(new0 CullState()); pass->SetDepthState(new0 DepthState()); pass->SetOffsetState(new0 OffsetState()); pass->SetStencilState(new0 StencilState()); pass->SetWireState(new0 WireState()); // TODO. Once Cg FX files are parsed, we might have multiple techniques // or multiple passes per technique. VisualTechnique* technique = new0 VisualTechnique(); technique->InsertPass(pass); mEffect = new0 VisualEffect(); mEffect->InsertTechnique(technique); return true; }
//---------------------------------------------------------------------------- VisualEffectInstance* GeodesicHeightField::CreateEffectInstance () { // Create the vertex shader. VertexShader* vshader = new0 VertexShader("Wm5.DLight2MatTex", 3, 3, 16, 0, false); vshader->SetInput(0, "modelPosition", Shader::VT_FLOAT3, Shader::VS_POSITION); vshader->SetInput(1, "modelNormal", Shader::VT_FLOAT3, Shader::VS_NORMAL); vshader->SetInput(2, "modelTCoord", Shader::VT_FLOAT2, Shader::VS_TEXCOORD0); vshader->SetOutput(0, "clipPosition", Shader::VT_FLOAT4, Shader::VS_POSITION); vshader->SetOutput(1, "vertexColor", Shader::VT_FLOAT4, Shader::VS_COLOR0); vshader->SetOutput(2, "vertexTCoord", Shader::VT_FLOAT2, Shader::VS_TEXCOORD0); vshader->SetConstant( 0, "PVWMatrix", 4); vshader->SetConstant( 1, "CameraModelPosition", 1); vshader->SetConstant( 2, "MaterialEmissive", 1); vshader->SetConstant( 3, "MaterialAmbient", 1); vshader->SetConstant( 4, "MaterialDiffuse", 1); vshader->SetConstant( 5, "MaterialSpecular", 1); vshader->SetConstant( 6, "Light0ModelDirection", 1); vshader->SetConstant( 7, "Light0Ambient", 1); vshader->SetConstant( 8, "Light0Diffuse", 1); vshader->SetConstant( 9, "Light0Specular", 1); vshader->SetConstant(10, "Light0Attenuation", 1); vshader->SetConstant(11, "Light1ModelDirection", 1); vshader->SetConstant(12, "Light1Ambient", 1); vshader->SetConstant(13, "Light1Diffuse", 1); vshader->SetConstant(14, "Light1Specular", 1); vshader->SetConstant(15, "Light1Attenuation", 1); vshader->SetBaseRegisters(msVRegisters); vshader->SetPrograms(msVPrograms); // Create the pixel shader. PixelShader* pshader = new0 PixelShader("Wm5.DLight2MatTex", 2, 1, 0, 1, false); pshader->SetInput(0, "vertexColor", Shader::VT_FLOAT4, Shader::VS_COLOR0); pshader->SetInput(1, "vertexTCoord", Shader::VT_FLOAT2, Shader::VS_TEXCOORD0); pshader->SetOutput(0, "pixelColor", Shader::VT_FLOAT4, Shader::VS_COLOR0); pshader->SetSampler(0, "BaseSampler", Shader::ST_2D); pshader->SetFilter(0, Shader::SF_LINEAR /*_LINEAR */); pshader->SetCoordinate(0, 0, Shader::SC_CLAMP_EDGE); pshader->SetCoordinate(0, 1, Shader::SC_CLAMP_EDGE); pshader->SetTextureUnits(msPTextureUnits); pshader->SetPrograms(msPPrograms); VisualPass* pass = new0 VisualPass(); pass->SetVertexShader(vshader); pass->SetPixelShader(pshader); pass->SetAlphaState(new0 AlphaState()); pass->SetCullState(new0 CullState()); pass->SetDepthState(new0 DepthState()); pass->SetOffsetState(new0 OffsetState()); pass->SetStencilState(new0 StencilState()); pass->SetWireState(new0 WireState()); // Create the effect. VisualTechnique* technique = new0 VisualTechnique(); technique->InsertPass(pass); VisualEffect* effect = new0 VisualEffect(); effect->InsertTechnique(technique); // Create the material for the effect. Float4 black(0.0f, 0.0f, 0.0f, 1.0f); Float4 white(1.0f, 1.0f, 1.0f, 1.0f); Material* material = new0 Material(); material->Emissive = black; material->Ambient = Float4(0.24725f, 0.2245f, 0.0645f, 1.0f); material->Diffuse = Float4(0.34615f, 0.3143f, 0.0903f, 1.0f); material->Specular = Float4(0.797357f, 0.723991f, 0.208006f, 83.2f); // Create the lights for the effect. Light* light0 = new0 Light(Light::LT_DIRECTIONAL); light0->SetDirection(AVector(0.0f, 0.0f, -1.0f)); light0->Ambient = white; light0->Diffuse = white; light0->Specular = black; Light* light1 = new0 Light(Light::LT_DIRECTIONAL); light1->SetDirection(AVector(0.0f, 0.0f, 1.0f)); light1->Ambient = white; light1->Diffuse = white; light1->Specular = black; // Create a texture for the effect. mTexture = new0 Texture2D(Texture::TF_A8R8G8B8, 512, 512, 0); unsigned char* data = (unsigned char*)mTexture->GetData(0); memset(data, 0xFF, mTexture->GetNumLevelBytes(0)); // Create an instance of the effect. VisualEffectInstance* instance = new0 VisualEffectInstance(effect, 0); instance->SetVertexConstant(0, 0, new0 PVWMatrixConstant()); instance->SetVertexConstant(0, 1, new0 CameraModelPositionConstant()); instance->SetVertexConstant(0, 2, new0 MaterialEmissiveConstant(material)); instance->SetVertexConstant(0, 3, new0 MaterialAmbientConstant(material)); instance->SetVertexConstant(0, 4, new0 MaterialDiffuseConstant(material)); instance->SetVertexConstant(0, 5, new0 MaterialSpecularConstant(material)); instance->SetVertexConstant(0, 6, new0 LightModelDVectorConstant(light0)); instance->SetVertexConstant(0, 7, new0 LightAmbientConstant(light0)); instance->SetVertexConstant(0, 8, new0 LightDiffuseConstant(light0)); instance->SetVertexConstant(0, 9, new0 LightSpecularConstant(light0)); instance->SetVertexConstant(0, 10, new0 LightAttenuationConstant(light0)); instance->SetVertexConstant(0, 11, new0 LightModelDVectorConstant(light1)); instance->SetVertexConstant(0, 12, new0 LightAmbientConstant(light1)); instance->SetVertexConstant(0, 13, new0 LightDiffuseConstant(light1)); instance->SetVertexConstant(0, 14, new0 LightSpecularConstant(light1)); instance->SetVertexConstant(0, 15, new0 LightAttenuationConstant(light1)); instance->SetPixelTexture(0, 0, mTexture); return instance; }
//---------------------------------------------------------------------------- void VolumeTextures::CreateScene () { mScene = new0 Node(); mAlphaState = new0 AlphaState(); mAlphaState->BlendEnabled = true; mRenderer->SetOverrideAlphaState(mAlphaState); mCullState = new0 CullState(); mCullState->Enabled = false; mRenderer->SetOverrideCullState(mCullState); // Create the grid of square meshes. const int numSlices = 64; const int numSamples = 32; // The vertex format that is shared by all square meshes. VertexFormat* vformat = VertexFormat::Create(2, VertexFormat::AU_POSITION, VertexFormat::AT_FLOAT3, 0, VertexFormat::AU_TEXCOORD, VertexFormat::AT_FLOAT3, 0); int vstride = vformat->GetStride(); // The index buffer that is shared by all square meshes. int numIndices = 6*(numSamples-1)*(numSamples-1); IndexBuffer* ibuffer = new0 IndexBuffer(numIndices, sizeof(int)); int* indices = (int*)ibuffer->GetData(); for (int i1 = 0; i1 < numSamples - 1; ++i1) { for (int i0 = 0; i0 < numSamples - 1; ++i0) { int v0 = i0 + numSamples * i1; int v1 = v0 + 1; int v2 = v1 + numSamples; int v3 = v0 + numSamples; *indices++ = v0; *indices++ = v1; *indices++ = v2; *indices++ = v0; *indices++ = v2; *indices++ = v3; } } // Create the volume texture. Three Gaussian distributions are used for // the RGB color channels. The alpha channel is constant. const int bound = 64; Texture3D* texture = new0 Texture3D(Texture::TF_A8R8G8B8, bound, bound, bound, 1); unsigned char* data = (unsigned char*)texture->GetData(0); const float mult = 1.0f/(bound - 1.0f); const float rParam = 0.01f; const float gParam = 0.01f; const float bParam = 0.01f; const float extreme = 8.0f; APoint rCenter( 0.5f*extreme, 0.0f, 0.0f); APoint gCenter(-0.5f*extreme, -0.5f*extreme, 0.0f); APoint bCenter(-0.5f*extreme, +0.5f*extreme, 0.0f); unsigned char commonAlpha = 12; APoint point; for (int z = 0; z < bound; ++z) { point[2] = -extreme + 2.0f*extreme*mult*z; for (int y = 0; y < bound; ++y) { point[1] = -extreme + 2.0f*extreme*mult*y; for (int x = 0; x < bound; ++x) { point[0] = -extreme + 2.0f*extreme*mult*x; AVector diff = point - rCenter; float sqrLength = diff.SquaredLength(); float rGauss = 1.0f - rParam*sqrLength; if (rGauss < 0.0f) { rGauss = 0.0f; } diff = point - gCenter; sqrLength = diff.SquaredLength(); float gGauss = 1.0f - gParam*sqrLength; if (gGauss < 0.0f) { gGauss = 0.0f; } diff = point - bCenter; sqrLength = diff.SquaredLength(); float bGauss = 1.0f - bParam*sqrLength; if (bGauss < 0.0f) { bGauss = 0.0f; } *data++ = (unsigned char)(255.0f*bGauss); *data++ = (unsigned char)(255.0f*gGauss); *data++ = (unsigned char)(255.0f*rGauss); *data++ = commonAlpha; } } } // The volume texture effect that is shared by all square meshes. std::string effectFile = Environment::GetPathR("VolumeTextures.wmfx"); VolumeTextureEffect* effect = new0 VolumeTextureEffect(effectFile); VisualEffectInstance* instance = effect->CreateInstance(texture); // The grid of squares. const int numVertices = numSamples*numSamples; float inv = 1.0f/(numSamples - 1.0f); VertexBufferAccessor vba; for (int slice = 0; slice < numSlices; ++slice) { VertexBuffer* vbuffer = new0 VertexBuffer(numVertices, vstride); vba.ApplyTo(vformat, vbuffer); float w = slice/(numSlices - 1.0f); float z = 2.0f*w - 1.0f; for (int i1 = 0, i = 0; i1 < numSamples; ++i1) { float v = i1*inv; float y = 2.0f*v - 1.0f; for (int i0 = 0; i0 < numSamples; ++i0, ++i) { float u = i0*inv; float x = 2.0f*u - 1.0f; vba.Position<Float3>(i) = Float3(x, y, z); vba.TCoord<Float3>(0, i) = Float3(u, v, w); } } TriMesh* mesh = new0 TriMesh(vformat, vbuffer, ibuffer); mesh->SetEffectInstance(instance); mScene->AttachChild(mesh); } }
//---------------------------------------------------------------------------- Node* SimplePendulumFriction::CreatePendulum () { VertexFormat* vformat = VertexFormat::Create(2, VertexFormat::AU_POSITION, VertexFormat::AT_FLOAT3, 0, VertexFormat::AU_NORMAL, VertexFormat::AT_FLOAT3, 0); StandardMesh sm(vformat); // Pendulum rod. TriMesh* rod = sm.Cylinder(2, 8, 0.05f, 12.0f, true); rod->LocalTransform.SetTranslate(APoint(0.0f, 0.0f, 10.0f)); // The pendulum bulb. Start with a sphere (to get the connectivity) and // then adjust the vertices to form a pair of joined cones. TriMesh* bulb = sm.Sphere(16, 32, 2.0f); VertexBufferAccessor vba(bulb); int numVertices = vba.GetNumVertices(); int i; for (i = 0; i < numVertices; ++i) { Float3& pos = vba.Position<Float3>(i); float r = Mathf::Sqrt(pos[0]*pos[0] + pos[1]*pos[1]); float z = pos[2] + 2.0f; if (z >= 2.0f) { z = 4.0f - r; } else { z = r; } pos[2] = z; } // Translate the pendulum joint to the origin for the purpose of // rotation. for (i = 0; i < numVertices; ++i) { vba.Position<Float3>(i)[2] -= 16.0f; } bulb->UpdateModelSpace(Visual::GU_NORMALS); vba.ApplyTo(rod); numVertices = vba.GetNumVertices(); for (i = 0; i < numVertices; ++i) { vba.Position<Float3>(i)[2] -= 16.0f; } rod->UpdateModelSpace(Visual::GU_NORMALS); // Group the objects into a single subtree. mPendulum = new0 Node(); mPendulum->AttachChild(rod); mPendulum->AttachChild(bulb); // Translate back to original model position. mPendulum->LocalTransform.SetTranslate(APoint(0.0f, 0.0f, 16.0f)); // Add a material for coloring. Float4 black(0.0f, 0.0f, 0.0f, 1.0f); Float4 white(1.0f, 1.0f, 1.0f, 1.0f); Material* material = new0 Material(); material->Emissive = black; material->Ambient = Float4(0.1f, 0.1f, 0.1f, 1.0f); material->Diffuse = Float4(0.99607f, 0.83920f, 0.67059f, 1.0f); material->Specular = black; // Use two lights to illuminate the pendulum. Light* light[2]; light[0] = new0 Light(Light::LT_DIRECTIONAL); light[0]->Ambient = white; light[0]->Diffuse = white; light[0]->Specular = black; light[0]->SetDirection(AVector(-1.0f, -1.0f, 0.0f)); light[1] = new0 Light(Light::LT_DIRECTIONAL); light[1]->Ambient = white; light[1]->Diffuse = white; light[1]->Specular = black; light[1]->SetDirection(AVector(+1.0f, -1.0f, 0.0f)); // TODO: The following code is used to piece together an effect with // two passes. It is better to write an effect whose vertex shader // has constants corresponding to the two lights (for a single-pass // effect). LightDirPerVerEffect* effect = new0 LightDirPerVerEffect(); VisualTechnique* technique = effect->GetTechnique(0); VisualPass* pass0 = technique->GetPass(0); VisualPass* pass1 = new0 VisualPass(); pass1->SetVertexShader(pass0->GetVertexShader()); pass1->SetPixelShader(pass0->GetPixelShader()); AlphaState* astate = new0 AlphaState(); astate->BlendEnabled = true; astate->SrcBlend = AlphaState::SBM_ONE; astate->DstBlend = AlphaState::DBM_ONE; pass1->SetAlphaState(astate); pass1->SetCullState(pass0->GetCullState()); pass1->SetDepthState(pass0->GetDepthState()); pass1->SetStencilState(pass0->GetStencilState()); pass1->SetOffsetState(pass0->GetOffsetState()); pass1->SetWireState(pass0->GetWireState()); technique->InsertPass(pass1); VisualEffectInstance* instance = new0 VisualEffectInstance(effect, 0); for (int pass = 0; pass < 2; ++pass) { instance->SetVertexConstant(pass, 0, new0 PVWMatrixConstant()); instance->SetVertexConstant(pass, 1, new0 CameraModelPositionConstant()); instance->SetVertexConstant(pass, 2, new0 MaterialEmissiveConstant(material)); instance->SetVertexConstant(pass, 3, new0 MaterialAmbientConstant(material)); instance->SetVertexConstant(pass, 4, new0 MaterialDiffuseConstant(material)); instance->SetVertexConstant(pass, 5, new0 MaterialSpecularConstant(material)); instance->SetVertexConstant(pass, 6, new0 LightModelDVectorConstant(light[pass])); instance->SetVertexConstant(pass, 7, new0 LightAmbientConstant(light[pass])); instance->SetVertexConstant(pass, 8, new0 LightDiffuseConstant(light[pass])); instance->SetVertexConstant(pass, 9, new0 LightSpecularConstant(light[pass])); instance->SetVertexConstant(pass, 10, new0 LightAttenuationConstant(light[pass])); } rod->SetEffectInstance(instance); bulb->SetEffectInstance(instance); return mPendulum; }