第二人生的源码分析(13)树显示的实现

在室外场境的实现中,有很多植物是需要显示出来的,比如树和花草是最常见的植物。下面就来看看第二人生里树显示的实现,如下图所示:

第二人生的源码分析(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

这段代码是先生成四个叶子平面,也就是八个三角形,接着再生成树干的顶点和纹理坐标。这样就可以通过不同的纹理图片显示出来就是不同的种类的树了。