source: GTP/trunk/Lib/Illum/IBRBillboardCloudTrees/OGRE/src/LBBCKMeansClusterGenerator.cpp @ 751

Revision 751, 9.4 KB checked in by igarcia, 18 years ago (diff)
Line 
1#include <LBBCKMeansClusterGenerator.h>
2
3namespace LBBC {
4
5void KMeansClusterGenerator::setAlpha(float value)
6{
7        mAlpha = value;
8}
9
10float KMeansClusterGenerator::getAlpha()
11{
12        return mAlpha;
13}
14
15void KMeansClusterGenerator::setNumIterations(unsigned int value)
16{
17        mNumIterations = value;
18}
19
20unsigned int KMeansClusterGenerator::getNumIterations()
21{
22        return mNumIterations;
23}
24
25unsigned int KMeansClusterGenerator::findBestBillboard(Leaf *leaf)
26{
27        float minError = FLT_MAX;
28        unsigned int iMinErrorBillboard = 0;
29       
30        Ogre::Vector3 normalLeaf = leaf->getLeafNormal();
31        Ogre::Vector3 positionLeaf = leaf->getPosition();               
32       
33        for (unsigned int iBillboard = 0; iBillboard < mBillboardCloud->getNumBillboards(); iBillboard++)
34        {
35                BBC::BillboardPtr billboard = mBillboardCloud->getBillboard(iBillboard);
36                BillboardKMeansClusterData *billboardClusterData = (BillboardKMeansClusterData*)billboard->getBillboardClusterData().get();
37                Ogre::Vector3 normalBillboard = billboardClusterData->getNormal();                     
38
39                float d = (normalBillboard.dotProduct(positionLeaf) +  billboardClusterData->getD());
40                float cosine = normalBillboard.dotProduct(normalLeaf);
41                float error = (d*d) + ( 1 - cosine * cosine ) * mAlpha;
42
43                if (error < minError)
44                {
45                        minError = error;
46                        iMinErrorBillboard = billboard->getBillboardHandle();
47                }                               
48        }
49        return iMinErrorBillboard;
50}
51
52void KMeansClusterGenerator::assignLeafBillboard(Leaf *leaf, BBC::BillboardPtr billboard)
53{
54        BillboardKMeansClusterData *billboardClusterData = (BillboardKMeansClusterData*)billboard->getBillboardClusterData().get();                     
55        BBC::EntityClusterPtr entityCluster = billboardClusterData->getEntityCluster();
56
57        BBC::EntityClusterDataPtr entityClusterData = BBC::EntityClusterDataPtr( (BBC::EntityClusterData*) new LeafKMeansClusterData() );
58        entityClusterData->setEntity(leaf);
59        entityCluster->addEntityClusterData(entityClusterData);
60}
61
62void KMeansClusterGenerator::splitLeafDistribution()
63{
64        for (unsigned int iLeaf = 0; iLeaf < mEntityDistribution->getNumEntities(); iLeaf++)
65        {
66                Leaf *leaf = (Leaf*)mEntityDistribution->getEntity(iLeaf).get();
67                unsigned int iMinErrorBillboard = findBestBillboard(leaf);
68
69                BBC::BillboardPtr billboardMinError = mBillboardCloud->getBillboard(iMinErrorBillboard);
70                assignLeafBillboard(leaf,billboardMinError);
71        }
72}
73
74void KMeansClusterGenerator::recomputeBillboard(BBC::BillboardPtr billboard)
75{
76        BillboardKMeansClusterData *billboardClusterData = (BillboardKMeansClusterData*)billboard->getBillboardClusterData().get();                     
77        BBC::EntityClusterPtr entityCluster = billboardClusterData->getEntityCluster();
78
79        if (entityCluster->getNumEntitiesClusterData() > 1)
80        {
81                Ogre::Matrix3 nmii = Ogre::Matrix3::ZERO;
82                Ogre::Matrix3 nmiiSum = Ogre::Matrix3::ZERO;
83                Ogre::Matrix3 miiSum = Ogre::Matrix3::ZERO;
84                Ogre::Matrix3 mii = Ogre::Matrix3::ZERO;       
85                Ogre::Matrix3 mijSum = Ogre::Matrix3::ZERO;
86                Ogre::Matrix3 mij = Ogre::Matrix3::ZERO;
87                Ogre::Vector3 lastY = Ogre::Vector3::ZERO;
88                Ogre::Vector3 piSum = Ogre::Vector3::ZERO;
89                Ogre::Vector3 normSum = Ogre::Vector3::ZERO;
90
91                for (unsigned int iLeaf = 0; iLeaf < entityCluster->getNumEntitiesClusterData(); iLeaf++)
92                {
93                        Leaf* leaf = (Leaf*)entityCluster->getEntityClusterData(iLeaf)->getEntity().get();
94                        Ogre::Vector3 pi = leaf->getPosition();
95                        Ogre::Vector3 norm2 = leaf->getLeafNormal();   
96                        piSum = piSum + pi * (1.0 / (float)entityCluster->getNumEntitiesClusterData());
97                               
98                        mii[0][0] = pi.x * pi.x;
99                        mii[0][1] = pi.x * pi.y;
100                        mii[0][2] = pi.x * pi.z;
101                        mii[1][0] = pi.y * pi.x;
102                        mii[1][1] = pi.y * pi.y;
103                        mii[1][2] = pi.y * pi.z;
104                        mii[2][0] = pi.z * pi.x;
105                        mii[2][1] = pi.z * pi.y;
106                        mii[2][2] = pi.z * pi.z;       
107                        nmii[0][0] = norm2.x * norm2.x;
108                        nmii[0][1] = norm2.x * norm2.y;
109                        nmii[0][2] = norm2.x * norm2.z;
110                        nmii[1][0] = norm2.y * norm2.x;
111                        nmii[1][1] = norm2.y * norm2.y;
112                        nmii[1][2] = norm2.y * norm2.z;
113                        nmii[2][0] = norm2.z * norm2.x;
114                        nmii[2][1] = norm2.z * norm2.y;
115                        nmii[2][2] = norm2.z * norm2.z;
116                       
117                        nmiiSum = nmiiSum + ( nmii * (1.0 / (float)entityCluster->getNumEntitiesClusterData()));
118
119                        miiSum = miiSum + ( mii * (1.0 / (float)entityCluster->getNumEntitiesClusterData()));
120
121                        // Generate the initial value for the iterative method as the average...
122                        Ogre::Vector3 norm = leaf->getLeafNormal();
123                        lastY = lastY + norm;
124
125                        // Generate the sum normal of all the leaves associated to the plane...
126                        normSum = normSum + norm;
127                }
128               
129                mijSum[0][0] = piSum.x * piSum.x;
130                mijSum[0][1] = piSum.x * piSum.y;
131                mijSum[0][2] = piSum.x * piSum.z;
132                mijSum[1][0] = piSum.y * piSum.x;
133                mijSum[1][1] = piSum.y * piSum.y;
134                mijSum[1][2] = piSum.y * piSum.z;
135                mijSum[2][0] = piSum.z * piSum.x;
136                mijSum[2][1] = piSum.z * piSum.y;
137                mijSum[2][2] = piSum.z * piSum.z;       
138
139                Ogre::Matrix3 mA = miiSum - mijSum;
140                mA = mA - (mAlpha * nmiiSum);
141                mA = mA.Inverse();
142
143                lastY.normalise();
144                normSum.normalise();
145
146                // Apply the iterative approach
147                Ogre::Vector3 currY;
148                currY = mA * lastY;
149                currY.normalise();
150
151                for(unsigned int icount = 0; icount < 100; icount++)
152                {
153                        lastY = currY;
154                        currY = mA * lastY;
155                        currY.normalise();
156                }
157
158                // Generate the d parameter...
159                float sumD = 0;
160                for (unsigned int iLeaf = 0; iLeaf < entityCluster->getNumEntitiesClusterData(); iLeaf++)
161                {
162                        Leaf* leaf = (Leaf*)entityCluster->getEntityClusterData(iLeaf)->getEntity().get();
163                        Ogre::Vector3 pi = leaf->getPosition();
164                        sumD = sumD + pi.dotProduct(currY);
165                }
166
167                sumD = - sumD / (float)entityCluster->getNumEntitiesClusterData();
168
169                billboardClusterData->setNormal(currY);
170                billboardClusterData->setD(sumD);
171        }
172        else if (entityCluster->getNumEntitiesClusterData() == 1)
173        {
174                Leaf* leaf = (Leaf*)entityCluster->getEntityClusterData(0)->getEntity().get();
175                billboardClusterData->setNormal(leaf->getLeafNormal());
176                billboardClusterData->setD(leaf->getLeafD());
177        }
178}
179
180void KMeansClusterGenerator::recomputeBillboardCloud()
181{
182        for (unsigned int iBillboard = 0; iBillboard < mBillboardCloud->getNumBillboards(); iBillboard++)
183        {
184                BBC::BillboardPtr billboard = mBillboardCloud->getBillboard(iBillboard);
185                recomputeBillboard(billboard);
186        }
187}
188
189void KMeansClusterGenerator::iterativeRecomputeBillboardCloud()
190{
191        for (unsigned int iIteration = 0; iIteration < mNumIterations; iIteration++)
192        {
193                recomputeBillboardCloud();
194        }
195}
196
197void KMeansClusterGenerator::generate()
198{
199        // Generate the initial random billboards and cluster the leaves with them
200        // 1. Create the billboards and assign an initial random orientation
201        initializeBillboardCloud();
202        // 2. Split the leaf distribution, each leaf in the it's best candidate billboard
203        splitLeafDistribution();
204        // 3. The billboard is recomputed in order to minimize the total error
205        // for the leaves of this cluster with respect to this plane.
206        iterativeRecomputeBillboardCloud();
207        // 4. Generate each entity cluster packed entity and compute the bounding quad for each entity cluster
208        generateBillboardCloudBounds();
209}
210
211BBC::BillboardPtr KMeansClusterGenerator::createBillboard()
212{
213        BBC::BillboardPtr billboard = BBC::BillboardPtr( new BBC::Billboard() );
214        mBillboardCloud->addBillboard(billboard);
215        return billboard;
216}
217
218void KMeansClusterGenerator::initializeBillboardClusterData(BBC::BillboardPtr billboard)
219{
220        BBC::BillboardClusterDataPtr billboardClusterData = BBC::BillboardClusterDataPtr( new BillboardKMeansClusterData() );
221        billboard->setBillboardClusterData(billboardClusterData);
222        BBC::EntityClusterPtr entityCluster = BBC::EntityClusterPtr( new BBC::EntityCluster() );
223        billboard->getBillboardClusterData()->setEntityCluster(entityCluster);
224}
225
226void KMeansClusterGenerator::generateBillboardCloudBounds()
227{
228        for (unsigned int iBillboard = 0; iBillboard < this->getMaxNumBillboards(); iBillboard++)
229        {
230                BBC::BillboardPtr billboard = mBillboardCloud->getBillboard(iBillboard);               
231                BBC::EntityClusterPtr entityCluster = billboard->getBillboardClusterData()->getEntityCluster();
232
233                if (entityCluster->getNumEntitiesClusterData() > 0)
234                {                                       
235                        entityCluster->generateEntityCluster();
236                        billboard->getBillboardClusterData()->generateBillboardBoundingQuad();
237                }
238        }
239}
240
241void KMeansClusterGenerator::initializeRandomBillboard(BBC::BillboardPtr billboard)
242{
243        float dMin = ((LeafDistribution*)mEntityDistribution)->getMinD();
244        float dMax = ((LeafDistribution*)mEntityDistribution)->getMaxD();
245
246        float d = Ogre::Math::RangeRandom(dMin,dMax);
247
248        //Ogre::Vector3 normalMin = ((LeafDistribution*)mEntityDistribution)->getMinNormal();
249        //Ogre::Vector3 normalMax = ((LeafDistribution*)mEntityDistribution)->getMaxNormal();
250        Ogre::Vector3 normal;
251        normal.x = Ogre::Math::RangeRandom(-1,1); // Ogre::Math::RangeRandom(normalMin.x,normalMax.x);
252        normal.y = Ogre::Math::RangeRandom(-1,1); // Ogre::Math::RangeRandom(normalMin.y,normalMax.y);
253        normal.z = Ogre::Math::RangeRandom(-1,1); // Ogre::Math::RangeRandom(normalMin.z,normalMax.z);
254       
255        BillboardKMeansClusterData *mBillboardClusterData = (BillboardKMeansClusterData *)billboard->getBillboardClusterData().get();
256        mBillboardClusterData->setNormal(normal);
257        mBillboardClusterData->setD(d);
258}
259
260void KMeansClusterGenerator::initializeBillboardCloud()
261{
262        for (unsigned int iBillboard = 0; iBillboard < this->getMaxNumBillboards(); iBillboard++)
263        {
264                BBC::BillboardPtr billboard = createBillboard();
265                initializeBillboardClusterData(billboard);
266                initializeRandomBillboard(billboard);
267        }
268}
269
270void KMeansClusterGenerator::init()
271{
272}
273
274KMeansClusterGenerator::KMeansClusterGenerator()
275{
276}
277
278KMeansClusterGenerator::~KMeansClusterGenerator()
279{
280
281}
282
283
284}
Note: See TracBrowser for help on using the repository browser.