第二人生的源码分析(13)树显示的实现
在室外场境的实现中,有很多植物是需要显示出来的,比如树和花草是最常见的植物。下面就来看看第二人生里树显示的实现,如下图所示:
<shapetype id="_x0000_t75" stroked="f" filled="f" path="[email protected]@[email protected]@[email protected]@[email protected]@5xe" o:preferrelative="t" o:spt="75" coordsize="21600,21600"><stroke joinstyle="miter"></stroke><formulas><f eqn="if lineDrawn pixelLineWidth 0"></f><f eqn="sum @0 1 0"></f><f eqn="sum 0 0 @1"></f><f eqn="prod @2 1 2"></f><f eqn="prod @3 21600 pixelWidth"></f><f eqn="prod @3 21600 pixelHeight"></f><f eqn="sum @0 0 1"></f><f eqn="prod @6 1 2"></f><f eqn="prod @7 21600 pixelWidth"></f><f eqn="sum @8 21600 0"></f><f eqn="prod @7 21600 pixelHeight"></f><f eqn="sum @10 21600 0"></f></formulas><path o:connecttype="rect" gradientshapeok="t" o:extrusionok="f"></path><lock aspectratio="t" v:ext="edit"></lock></shapetype><shape id="_x0000_i1025" style="WIDTH: 436.5pt; HEIGHT: 311.25pt" type="#_x0000_t75"><imagedata o:title="tree" src="file:///C:/DOCUME~1/caijs/LOCALS~1/Temp/msohtml1/01/clip_image001.jpg"></imagedata></shape>
蔡军生 <chsdate w:st="on" year="2008" month="1" day="13" islunardate="False" isrocdate="False">2008/01/13</chsdate> QQ:9073204 深圳
看到如此优美的画面,让人感觉就是身临其境,快活如神仙一般。这样才提供给人们快乐的环境,度过美好的人生。那么这么优美的树是怎么样实现的呢?现在就来分析一下第二人生里树显示的实现,跟前面地面和天空一样,都是先创建网格,然再加上合适的纹理来实现的,代码如下:
#001 BOOL LLVOTree::updateGeometry(LLDrawable *drawable)
#002 {
#003 LLFastTimer ftm(LLFastTimer::FTM_UPDATE_TREE);
#004 U32 i, j;
#005 const S32 MAX_SLICES = 32;
#006
#007 const F32 LEAF_LEFT = <chmetcnv w:st="on" unitname="F" sourcevalue=".52" hasspace="False" negative="False" numbertype="1" tcsc="0">0.52f</chmetcnv>;
#008 const F32 LEAF_RIGHT = <chmetcnv w:st="on" unitname="F" sourcevalue=".98" hasspace="False" negative="False" numbertype="1" tcsc="0">0.98f</chmetcnv>;
#009 const F32 LEAF_TOP = <chmetcnv w:st="on" unitname="F" sourcevalue="1" hasspace="False" negative="False" numbertype="1" tcsc="0">1.0f</chmetcnv>;
#010 const F32 LEAF_BOTTOM = <chmetcnv w:st="on" unitname="F" sourcevalue=".52" hasspace="False" negative="False" numbertype="1" tcsc="0">0.52f</chmetcnv>;
#011
#012 const F32 LEAF_WIDTH = 1.f;
#013
#014
#015 U32 slices = MAX_SLICES;
#016
#017 S32 max_indices = LEAF_INDICES;
#018 S32 max_vertices = LEAF_VERTICES;
#019 S32 lod;
#020
#021 LLFace *face = drawable->getFace(0);
#022
获取树显示的表面。
#023 face->mCenterAgent = getPositionAgent();
#024 face->mCenterLocal = face->mCenterAgent;
#025
#026 for (lod = 0; lod < 4; lod++)
#027 {
#028 slices = sLODSlices[lod];
#029 sLODVertexOffset[lod] = max_vertices;
#030 sLODVertexCount[lod] = slices*slices;
#031 sLODIndexOffset[lod] = max_indices;
#032 sLODIndexCount[lod] = (slices-1)*(slices-1)*6;
#033 max_indices += sLODIndexCount[lod];
#034 max_vertices += sLODVertexCount[lod];
#035 }
#036
计算有多少顶点实现树网格。
#037 LLStrider<LLVector3> vertices;
#038 LLStrider<LLVector3> normals;
#039 LLStrider<LLVector2> tex_coords;
#040 LLStrider<U32> indicesp;
#041
#042 face->setSize(max_vertices, max_indices);
设置表面的顶点个数和索引个数。
#043
#044 face->mVertexBuffer = new LLVertexBuffer(LLDrawPoolTree::VERTEX_DATA_MASK, GL_STATIC_DRAW_ARB);
#045 face->mVertexBuffer->allocateBuffer(max_vertices, max_indices, TRUE);
分配表面的顶点和索引内存缓冲区。
#046 face->setGeomIndex(0);
#047 face->setIndicesIndex(0);
#048
#049 face->getGeometry(vertices, normals, tex_coords, indicesp);
获取顶点、法线、纹理、索引的保存数组开始位置。
#050
#051
#052 S32 vertex_count = 0;
#053 S32 index_count = 0;
#054
#055 // First leaf
#056 for (i = 0; i < 4; i++)
#057 {
#058 *(normals++) = LLVector3(0.f, 0.f, 1.f);
#059 }
#060
#061 *(tex_coords++) = LLVector2(LEAF_LEFT, LEAF_BOTTOM);
#062 *(vertices++) = LLVector3(<chmetcnv w:st="on" unitname="F" sourcevalue=".5" hasspace="False" negative="True" numbertype="1" tcsc="0">-0.5f</chmetcnv>*LEAF_WIDTH, 0.f, 0.f);
#063 vertex_count++;
#064
#065 *(tex_coords++) = LLVector2(LEAF_RIGHT, LEAF_TOP);
#066 *(vertices++) = LLVector3(<chmetcnv w:st="on" unitname="F" sourcevalue=".5" hasspace="False" negative="False" numbertype="1" tcsc="0">0.5f</chmetcnv>*LEAF_WIDTH, 0.f, 1.f);
#067 vertex_count++;
#068
#069 *(tex_coords++) = LLVector2(LEAF_LEFT, LEAF_TOP);
#070 *(vertices++) = LLVector3(<chmetcnv w:st="on" unitname="F" sourcevalue=".5" hasspace="False" negative="True" numbertype="1" tcsc="0">-0.5f</chmetcnv>*LEAF_WIDTH, 0.f, 1.f);
#071 vertex_count++;
#072
#073 *(tex_coords++) = LLVector2(LEAF_RIGHT, LEAF_BOTTOM);
#074 *(vertices++) = LLVector3(<chmetcnv w:st="on" unitname="F" sourcevalue=".5" hasspace="False" negative="False" numbertype="1" tcsc="0">0.5f</chmetcnv>*LEAF_WIDTH, 0.f, 0.f);
#075 vertex_count++;
#076
#077
#078 *(indicesp++) = 0;
#079 index_count++;
#080 *(indicesp++) = 1;
#081 index_count++;
#082 *(indicesp++) = 2;
#083 index_count++;
#084
#085 *(indicesp++) = 0;
#086 index_count++;
#087 *(indicesp++) = 3;
#088 index_count++;
#089 *(indicesp++) = 1;
#090 index_count++;
上面计算第一个叶子平面的四个顶点和纹理坐标。
#091
#092 // Same leaf, inverse winding/normals
#093 for (i = 0; i < 4; i++)
#094 {
#095 *(normals++) = LLVector3(0.f, 0.f, 1.f);
#096 }
#097
#098 *(tex_coords++) = LLVector2(LEAF_LEFT, LEAF_BOTTOM);
#099 *(vertices++) = LLVector3(<chmetcnv w:st="on" unitname="F" sourcevalue=".5" hasspace="False" negative="True" numbertype="1" tcsc="0">-0.5f</chmetcnv>*LEAF_WIDTH, 0.f, 0.f);
#100 vertex_count++;
#101
#102 //*(tex_coords++) = LLVector2(1.f, <chmetcnv w:st="on" unitname="F" sourcevalue="1" hasspace="False" negative="False" numbertype="1" tcsc="0">1.0f</chmetcnv>);
#103 *(tex_coords++) = LLVector2(LEAF_RIGHT, LEAF_TOP);
#104 *(vertices++) = LLVector3(<chmetcnv w:st="on" unitname="F" sourcevalue=".5" hasspace="False" negative="False" numbertype="1" tcsc="0">0.5f</chmetcnv>*LEAF_WIDTH, 0.f, 1.f);
#105 vertex_count++;
#106
#107 //*(tex_coords++) = LLVector2(<chmetcnv w:st="on" unitname="F" sourcevalue=".52" hasspace="False" negative="False" numbertype="1" tcsc="0">0.52f</chmetcnv>, <chmetcnv w:st="on" unitname="F" sourcevalue="1" hasspace="False" negative="False" numbertype="1" tcsc="0">1.0f</chmetcnv>);
#108 *(tex_coords++) = LLVector2(LEAF_LEFT, LEAF_TOP);
#109 *(vertices++) = LLVector3(<chmetcnv w:st="on" unitname="F" sourcevalue=".5" hasspace="False" negative="True" numbertype="1" tcsc="0">-0.5f</chmetcnv>*LEAF_WIDTH, 0.f, 1.f);
#110 vertex_count++;
#111
#112 //*(tex_coords++) = LLVector2(1.f, <chmetcnv w:st="on" unitname="F" sourcevalue=".52" hasspace="False" negative="False" numbertype="1" tcsc="0">0.52f</chmetcnv>);
#113 *(tex_coords++) = LLVector2(LEAF_RIGHT, LEAF_BOTTOM);
#114 *(vertices++) = LLVector3(<chmetcnv w:st="on" unitname="F" sourcevalue=".5" hasspace="False" negative="False" numbertype="1" tcsc="0">0.5f</chmetcnv>*LEAF_WIDTH, 0.f, 0.f);
#115 vertex_count++;
#116
#117 *(indicesp++) = 4;
#118 index_count++;
#119 *(indicesp++) = 6;
#120 index_count++;
#121 *(indicesp++) = 5;
#122 index_count++;
#123
#124 *(indicesp++) = 4;
#125 index_count++;
#126 *(indicesp++) = 5;
#127 index_count++;
#128 *(indicesp++) = 7;
#129 index_count++;
#130
#131
#132 for (i = 0; i < 4; i++)
#133 {
#134 *(normals++) = LLVector3(0.f, 0.f, 1.f);
#135 }
#136
#137 *(tex_coords++) = LLVector2(LEAF_LEFT, LEAF_BOTTOM);
#138 *(vertices++) = LLVector3(0.f, <chmetcnv w:st="on" unitname="F" sourcevalue=".5" hasspace="False" negative="True" numbertype="1" tcsc="0">-0.5f</chmetcnv>*LEAF_WIDTH, 0.f);
#139 vertex_count++;
#140
#141 *(tex_coords++) = LLVector2(LEAF_RIGHT, LEAF_TOP);
#142 *(vertices++) = LLVector3(0.f, <chmetcnv w:st="on" unitname="F" sourcevalue=".5" hasspace="False" negative="False" numbertype="1" tcsc="0">0.5f</chmetcnv>*LEAF_WIDTH, 1.f);
#143 vertex_count++;
#144
#145 *(tex_coords++) = LLVector2(LEAF_LEFT, LEAF_TOP);
#146 *(vertices++) = LLVector3(0.f, <chmetcnv w:st="on" unitname="F" sourcevalue=".5" hasspace="False" negative="True" numbertype="1" tcsc="0">-0.5f</chmetcnv>*LEAF_WIDTH, 1.f);
#147 vertex_count++;
#148
#149 *(tex_coords++) = LLVector2(LEAF_RIGHT, LEAF_BOTTOM);
#150 *(vertices++) = LLVector3(0.f, <chmetcnv w:st="on" unitname="F" sourcevalue=".5" hasspace="False" negative="False" numbertype="1" tcsc="0">0.5f</chmetcnv>*LEAF_WIDTH, 0.f);
#151 vertex_count++;
#152
#153 *(indicesp++) = 8;
#154 index_count++;
#155 *(indicesp++) = 9;
#156 index_count++;
#157 *(indicesp++) = 10;
#158 index_count++;
#159
#160 *(indicesp++) = 8;
#161 index_count++;
#162 *(indicesp++) = 11;
#163 index_count++;
#164 *(indicesp++) = 9;
#165 index_count++;
#166
#167 for (i = 0; i < 4; i++)
#168 {
#169 *(normals++) = LLVector3(0.f, 0.f, 1.f);
#170 }
#171
#172 *(tex_coords++) = LLVector2(LEAF_LEFT, LEAF_BOTTOM);
#173 *(vertices++) = LLVector3(0.f, <chmetcnv w:st="on" unitname="F" sourcevalue=".5" hasspace="False" negative="True" numbertype="1" tcsc="0">-0.5f</chmetcnv>*LEAF_WIDTH, 0.f);
#174 vertex_count++;
#175
#176 *(tex_coords++) = LLVector2(LEAF_RIGHT, LEAF_TOP);
#177 *(vertices++) = LLVector3(0.f, <chmetcnv w:st="on" unitname="F" sourcevalue=".5" hasspace="False" negative="False" numbertype="1" tcsc="0">0.5f</chmetcnv>*LEAF_WIDTH, 1.f);
#178 vertex_count++;
#179
#180 *(tex_coords++) = LLVector2(LEAF_LEFT, LEAF_TOP);
#181 *(vertices++) = LLVector3(0.f, <chmetcnv w:st="on" unitname="F" sourcevalue=".5" hasspace="False" negative="True" numbertype="1" tcsc="0">-0.5f</chmetcnv>*LEAF_WIDTH, 1.f);
#182 vertex_count++;
#183
#184 *(tex_coords++) = LLVector2(LEAF_RIGHT, LEAF_BOTTOM);
#185 *(vertices++) = LLVector3(0.f, <chmetcnv w:st="on" unitname="F" sourcevalue=".5" hasspace="False" negative="False" numbertype="1" tcsc="0">0.5f</chmetcnv>*LEAF_WIDTH, 0.f);
#186 vertex_count++;
#187
#188
#189 *(indicesp++) = 12;
#190 index_count++;
#191 *(indicesp++) = 14;
#192 index_count++;
#193 *(indicesp++) = 13;
#194 index_count++;
#195
#196 *(indicesp++) = 12;
#197 index_count++;
#198 *(indicesp++) = 13;
#199 index_count++;
#200 *(indicesp++) = 15;
#201 index_count++;
#202
#203 // Generate geometry for the cylinders
#204
#205 // Different LOD's
#206
#207 // Generate the vertices
#208 // Generate the indices
#209
下面生成4个级别的树形显示。
#210 for (lod = 0; lod < 4; lod++)
#211 {
#212 slices = sLODSlices[lod];
#<chmetcnv w:st="on" unitname="F" sourcevalue="213" hasspace="False" negative="False" numbertype="1" tcsc="0">213 </chmetcnv> F32 base_radius = <chmetcnv w:st="on" unitname="F" sourcevalue=".65" hasspace="False" negative="False" numbertype="1" tcsc="0">0.65f</chmetcnv>;
#<chmetcnv w:st="on" unitname="F" sourcevalue="214" hasspace="False" negative="False" numbertype="1" tcsc="0">214 </chmetcnv> F32 top_radius = base_radius * sSpeciesTable[mSpecies]->mTaper;
#215 //llinfos << "Species " << ((U32) mSpecies) << ", taper = " << sSpeciesTable[mSpecies].mTaper << llendl;
#216 //llinfos << "Droop " << mDroop << ", branchlength: " << mBranchLength << llendl;
#<chmetcnv w:st="on" unitname="F" sourcevalue="217" hasspace="False" negative="False" numbertype="1" tcsc="0">217 </chmetcnv> F32 angle = 0;
#<chmetcnv w:st="on" unitname="F" sourcevalue="218" hasspace="False" negative="False" numbertype="1" tcsc="0">218 </chmetcnv> F32 angle_inc = 360.f/(slices-1);
#<chmetcnv w:st="on" unitname="F" sourcevalue="219" hasspace="False" negative="False" numbertype="1" tcsc="0">219 </chmetcnv> F32 z = 0.f;
#<chmetcnv w:st="on" unitname="F" sourcevalue="220" hasspace="False" negative="False" numbertype="1" tcsc="0">220 </chmetcnv> F32 z_inc = 1.f;
#221 if (slices > 3)
#222 {
#223 z_inc = 1.f/(slices - 3);
#224 }
#<chmetcnv w:st="on" unitname="F" sourcevalue="225" hasspace="False" negative="False" numbertype="1" tcsc="0">225 </chmetcnv> F32 radius = base_radius;
#226
#<chmetcnv w:st="on" unitname="F" sourcevalue="227" hasspace="False" negative="False" numbertype="1" tcsc="0">227 </chmetcnv> F32 x1,y1;
#<chmetcnv w:st="on" unitname="F" sourcevalue="228" hasspace="False" negative="False" numbertype="1" tcsc="0">228 </chmetcnv> F32 noise_scale = sSpeciesTable[mSpecies]->mNoiseMag;
#229 LLVector3 nvec;
#230
#231 const F32 cap_nudge = <chmetcnv w:st="on" unitname="F" sourcevalue=".1" hasspace="False" negative="False" numbertype="1" tcsc="0">0.1f</chmetcnv>; // Height to 'peak' the caps on top/bottom of branch
#232
#233 const S32 fractal_depth = 5;
#<chmetcnv w:st="on" unitname="F" sourcevalue="234" hasspace="False" negative="False" numbertype="1" tcsc="0">234 </chmetcnv> F32 nvec_scale = 1.f * sSpeciesTable[mSpecies]->mNoiseScale;
#<chmetcnv w:st="on" unitname="F" sourcevalue="235" hasspace="False" negative="False" numbertype="1" tcsc="0">235 </chmetcnv> F32 nvec_scalez = 4.f * sSpeciesTable[mSpecies]->mNoiseScale;
#236
#<chmetcnv w:st="on" unitname="F" sourcevalue="237" hasspace="False" negative="False" numbertype="1" tcsc="0">237 </chmetcnv> F32 tex_z_repeat = sSpeciesTable[mSpecies]->mRepeatTrunkZ;
#238
#<chmetcnv w:st="on" unitname="F" sourcevalue="239" hasspace="False" negative="False" numbertype="1" tcsc="0">239 </chmetcnv> F32 start_radius;
#<chmetcnv w:st="on" unitname="F" sourcevalue="240" hasspace="False" negative="False" numbertype="1" tcsc="0">240 </chmetcnv> F32 nangle = 0;
#<chmetcnv w:st="on" unitname="F" sourcevalue="241" hasspace="False" negative="False" numbertype="1" tcsc="0">241 </chmetcnv> F32 height = 1.f;
#<chmetcnv w:st="on" unitname="F" sourcevalue="242" hasspace="False" negative="False" numbertype="1" tcsc="0">242 </chmetcnv> F32 r0;
#243
下面生成圆柱形状树形顶点和纹理坐标.
#244 for (i = 0; i < slices; i++)
#245 {
#246 if (i == 0)
#247 {
#248 z = - cap_nudge;
#249 r0 = 0.0;
#250 }
#251 else if (i == (slices - 1))
#252 {
#253 z = 1.f + cap_nudge;//((i - 2) * z_inc) + cap_nudge;
#254 r0 = 0.0;
#255 }
#256 else
#257 {
#258 z = (i - 1) * z_inc;
#259 r0 = base_radius + (top_radius - base_radius)*z;
#260 }
#261
#262 for (j = 0; j < slices; j++)
#263 {
#264 if (slices - 1 == j)
#265 {
#266 angle = 0.f;
#267 }
#268 else
#269 {
#270 angle = j*angle_inc;
#271 }
#272
#273 nangle = angle;
#274
#275 x1 = cos(angle * DEG_TO_RAD);
#276 y1 = sin(angle * DEG_TO_RAD);
#277 LLVector2 tc;
#278 // This isn't totally accurate. Should compute based on slope as well.
#279 start_radius = r0 * (1.f + <chmetcnv w:st="on" unitname="F" sourcevalue="1.2" hasspace="False" negative="False" numbertype="1" tcsc="0">1.2f</chmetcnv>*fabs(z - <chmetcnv w:st="on" unitname="F" sourcevalue=".66" hasspace="False" negative="False" numbertype="1" tcsc="0">0.66f</chmetcnv>*height)/height);
#280 nvec.setVec( cos(nangle * DEG_TO_RAD)*start_radius*nvec_scale,
#281 sin(nangle * DEG_TO_RAD)
#282 *start_radius*nvec_scale,
#283 z*nvec_scalez);
#284 // First and last slice at 0 radius (to bring in top/bottom of structure)
#285 radius = start_radius + turbulence3((F32*)&nvec.mV, (F32)fractal_depth)*noise_scale;
#286
#287 if (slices - 1 == j)
#288 {
#289 // Not 0.5 for slight slop factor to avoid edges on leaves
#290 tc = LLVector2(<chmetcnv w:st="on" unitname="F" sourcevalue=".49" hasspace="False" negative="False" numbertype="1" tcsc="0">0.490f</chmetcnv>, (1.f - z/2.f)*tex_z_repeat);
#291 }
#292 else
#293 {
#294 tc = LLVector2((angle/360.f)*<chmetcnv w:st="on" unitname="F" sourcevalue=".5" hasspace="False" negative="False" numbertype="1" tcsc="0">0.5f</chmetcnv>, (1.f - z/2.f)*tex_z_repeat);
#295 }
#296
#297 *(vertices++) = LLVector3(x1*radius, y1*radius, z);
#298 *(normals++) = LLVector3(x1, y1, 0.f);
#299 *(tex_coords++) = tc;
#300 vertex_count++;
#301 }
#302 }
#303
#304 for (i = 0; i < (slices - 1); i++)
#305 {
#306 for (j = 0; j < (slices - 1); j++)
#307 {
#308 S32 x1_offset = j+1;
#309 if ((j+1) == slices)
#310 {
#311 x1_offset = 0;
#312 }
#313 // Generate the matching quads
#314 *(indicesp) = j + (i*slices) + sLODVertexOffset[lod];
#315 llassert(*(indicesp) < (U32)max_vertices);
#316 indicesp++;
#317 index_count++;
#318 *(indicesp) = x1_offset + ((i+1)*slices) + sLODVertexOffset[lod];
#319 llassert(*(indicesp) < (U32)max_vertices);
#320 indicesp++;
#321 index_count++;
#322 *(indicesp) = j + ((i+1)*slices) + sLODVertexOffset[lod];
#323 llassert(*(indicesp) < (U32)max_vertices);
#324 indicesp++;
#325 index_count++;
#326
#327 *(indicesp) = j + (i*slices) + sLODVertexOffset[lod];
#328 llassert(*(indicesp) < (U32)max_vertices);
#329 indicesp++;
#330 index_count++;
#331 *(indicesp) = x1_offset + (i*slices) + sLODVertexOffset[lod];
#332 llassert(*(indicesp) < (U32)max_vertices);
#333 indicesp++;
#334 index_count++;
#335 *(indicesp) = x1_offset + ((i+1)*slices) + sLODVertexOffset[lod];
#336 llassert(*(indicesp) < (U32)max_vertices);
#337 indicesp++;
#338 index_count++;
#339 }
#340 }
#341 slices /= 2;
#342 }
#343
#344 llassert(vertex_count == max_vertices);
#345 llassert(index_count == max_indices);
#346
#347 return TRUE;
#348 }
#349
这段代码是先生成四个叶子平面,也就是八个三角形,接着再生成树干的顶点和纹理坐标。这样就可以通过不同的纹理图片显示出来就是不同的种类的树了。