iOS中Native的方式集成Vuforia、其源碼解讀以及自定義模型


??隨著前有Apple在iOS11中提供了ARKit类浪,后有Google推出的ARCore载城,顯然掀起了一股AR熱潮(都是一堆廢話,說白了就是公司要求做)费就。由于高通的Vuforia已經(jīng)存在較長(zhǎng)時(shí)間了诉瓦,相對(duì)于EasyAR或者百度AR更為成熟一點(diǎn)兒,所以它成了第一個(gè)技術(shù)選擇力细。EasyAR和百度的AR——DuMix AR后面再依次去學(xué)習(xí)睬澡。好吧,先開始來學(xué)習(xí)Vuforia吧眠蚂!
該文章同步發(fā)布在我的博客.

集成步驟

由于這些步驟相對(duì)來說比較基礎(chǔ)煞聪,我就直接羅列出來。

  • 1逝慧、開發(fā)者官網(wǎng)https://developer.vuforia.com昔脯;

  • 2、下載ios-sdk和ios-sample笛臣,并按照官方文檔要求將ios-sample放入到ios-sdk的sample文件夾下

  • 3云稚、在vuforia的開發(fā)者官網(wǎng)上的License Manager和Target Manager,添加License-key和database


    License-Key
  • 4沈堡、將上一步添加的License-key静陈,放在ios-sample中的代碼文件SampleApplicationSession.mm中的方法Vuforia::setInitParameters(mVuforiaInitFlags,"");中。具體步驟見官網(wǎng)踱蛀。

     Vuforia::setInitParameters(mVuforiaInitFlags,"AT16FIX/////AAAAGVieZ/kg1UkghTnYAz5zXWs8+y5JjeF/NJRcjgVDoCSvsrSt+lWzFMcIVBbQ2YSFRF+6J0GceHoaz8NctXib3cndJEacXmR+1FyO5FhalO7sC4hE9d1/x72qTNDhkPs4rF04JulMYT876Grsnmg9C61oyaDVwBfSpzNZ7gx3NADkkV5q4NQs4ghZwVCdMhj6LVt1YTJcwiuULtDTEgpFZZeW/nC8yiC53hpUFOVxhH++ILx1T65jpY8yDn6ct++3mgVeVotg/5tWXYb5FYqBtJiwU/LJJxhJYqUWyy4pd9dHUJBQojuAE8FoW1DmjokrpDWgjOMMp3am4GjNT04hCg+o0Z3SByYx6VIqfSR9fsXw");
    
  • 5窿给、將第3步中Target Manager創(chuàng)建的database,傳入相關(guān)的圖片文件率拒。也可以不傳崩泡,這步可選;怎樣使用設(shè)備數(shù)據(jù)猬膨。我們?cè)?a target="_blank" rel="nofollow">官方Developer創(chuàng)建角撞,下載對(duì)應(yīng)的Database呛伴,在添加圖片時(shí),對(duì)應(yīng)的星星數(shù)越高表明識(shí)別度越高

    Target-Manager

    解壓并將其引入到工程中:
    引入工程

    這一步可以不做谒所,因?yàn)檫@只是在給后面打基礎(chǔ)而已热康,如果只是運(yùn)行demo的話是不需要做這一步的。如果做了這一步劣领,在掃描你對(duì)應(yīng)的圖片的時(shí)候是沒有任何效果的姐军,具體的操作后面。

  • 6尖淘、編譯運(yùn)行奕锌,由于需要使用到傳感器,所以必須使用真機(jī)來運(yùn)行村生。關(guān)于真機(jī)運(yùn)行的相關(guān)事項(xiàng)查看apple developer

源碼閱讀順序

源碼說明:
Voforia SDK版本:vuforia-sdk-ios-6-5-19
iOS Samples版本:vuforia-samples-core-ios-6-5-20

如果不想看源碼相關(guān)可直接跳過這部分惊暴,直接跟著“收尾”做自定義的tracker和模型(替換Teapot茶壺模型為自己的)

為何要閱讀源碼?因?yàn)樵?strong>Voforia的官方文檔中我沒有找到我自己想要的信息趁桃。所以我們需要通過閱讀源碼辽话,來找到怎樣才能去修改貼在目標(biāo)圖像中虛擬模型。以sample中ImageTargetsViewController為例來解讀卫病!
首先查看ImageTargetsViewController.h文件油啤,我們先不看成員變量。先來看屬性

屬性 屬性類型 初步作用
eaglView ImageTargetsEAGLView* 初步認(rèn)定為一個(gè)展示視圖
tapGestureRecognizer UITapGestureRecognizer* 一個(gè)點(diǎn)擊手勢(shì)
vapp SampleApplicationSession* 初步認(rèn)定為一個(gè)會(huì)話層(類似于ISO網(wǎng)絡(luò)七層模型中忽肛,在TCP可以歸于應(yīng)用層村砂,也就是說想偷懶可以直接將其代碼放入控制器中。個(gè)人理解)
showingMenu BOOL 一個(gè)flag

從上表中出現(xiàn)的屬性屹逛,我們先來分析一下屬性eaglViewvapp础废。

SampleApplicationSession類

ImageTargetsViewController控制器類中,和下面會(huì)講到的ImageTargetsEAGLView都有SampleApplicationSession類型的屬性罕模,所以我們有必要先來看看該類评腺。同樣的先看頭文件,因?yàn)轭^文件能夠讓我們對(duì)于該類有大體的認(rèn)識(shí)淑掌,而不拘于類具體的實(shí)現(xiàn)細(xì)節(jié)蒿讥。
??粗略來看,提供了一個(gè)初始化方法抛腕;一個(gè)初始化AR的方法芋绸;四個(gè)對(duì)AR的操作方法(它們不是我們需要的重點(diǎn),等到需要的時(shí)候再來仔細(xì)閱讀)担敌;以及一個(gè)對(duì)Camera的方法:

- (id)initWithDelegate:(id<SampleApplicationControl>) delegate;
- (void) initAR:(int) VuforiaInitFlags orientation:(UIInterfaceOrientation) ARViewOrientation;
- (bool) startAR:(Vuforia::CameraDevice::CAMERA_DIRECTION) camera error:(NSError **)error;
- (bool) pauseAR:(NSError **)error;
- (bool) resumeAR:(NSError **)error;
- (bool) stopAR:(NSError **)error;
- (bool) stopCamera:(NSError **)error;

上述的initAR方法是通過異步實(shí)現(xiàn)的摔敛,當(dāng)其AR初始化完成之后會(huì)調(diào)用方法下面會(huì)提到的代理方法onInitARDone。順藤摸瓜全封,我們來看看該代理马昙,那么該代理所需要處理的事務(wù)有哪些呢桃犬?這里先將SampleApplicationControl的所有方法先列出來:

@required
- (void) onInitARDone:(NSError *)error;
- (bool) doInitTrackers;
- (bool) doLoadTrackersData;
- (bool) doStartTrackers;
- (bool) doStopTrackers;
- (bool) doUnloadTrackersData;
- (bool) doDeinitTrackers;
- (void)configureVideoBackgroundWithViewWidth:(float)viewWidth andHeight:(float)viewHeight;

@optional
- (void) onVuforiaUpdate: (Vuforia::State *) state;

該代理方法中大多是涉及到的是tracker。通過從初始化方法開始查看方法調(diào)用行楞,得出了一個(gè)程序執(zhí)行流程圖攒暇,

圖-1

我們主動(dòng)調(diào)用initAR方法,其結(jié)果會(huì)由回調(diào)方法onInitARDone反應(yīng)給開發(fā)者子房。開發(fā)者可以用通過調(diào)用doInitTrackers來控制是否需要去加載tracker數(shù)據(jù)形用,如果可以加載數(shù)據(jù)則通過調(diào)用回調(diào)方法doLoadTrackersData來獲取數(shù)據(jù)。關(guān)于該類中其他幾個(gè)方法startAR , pauseAR, resumeAR, stopAR由調(diào)用人員主動(dòng)調(diào)用池颈,調(diào)用這些方法會(huì)觸發(fā)對(duì)應(yīng)的方法回調(diào)尾序。
現(xiàn)在我們需要把目光轉(zhuǎn)向ImageTargetsEAGLView類,并去具體的看一下里面的相關(guān)細(xì)節(jié)躯砰。

SampleAppRenderer類

這個(gè)類主要是做渲染相關(guān)的工作,其源碼大多數(shù)為OpenGL携丁。所以對(duì)于該類我只做具體的作用分析琢歇,而不去解釋具體的源代碼(因?yàn)槲乙膊欢缬行枰脑捗渭孕猩罹堪衫蠲#??。這里先將各個(gè)方法的作用羅列出來:

方法名 方法作用
initWithSampleAppRendererControl 類初始化方法
initRendering 渲染相關(guān)的初始化
setNearPlane:farPlane: 配置投影矩陣數(shù)據(jù)
renderFrameVuforia 由Vuforia調(diào)用肥橙,渲染數(shù)據(jù)幀到屏幕
renderVideoBackground 后臺(tái)渲染視頻
configureVideoBackgroundWithViewWidth:andHeight: 視頻相關(guān)的配置
updateRenderingPrimitives 更新渲染數(shù)據(jù)

下面具體分析:老規(guī)矩魄宏,同樣先看頭文件,我們根據(jù)頭文件暴露出來的方法一層一層往里剝存筏。該類存在一個(gè)協(xié)議SampleAppRendererControl宠互,和一個(gè)初始化方法initWithSampleAppRendererControl。使用這個(gè)方法需要傳入一個(gè)遵守SampleAppRendererControl協(xié)議的類實(shí)例椭坚,第二個(gè)參數(shù)來決定VR/AR的模式予跌,以及三個(gè)用于決定投影矩陣的參數(shù)。除了在初始化方法設(shè)置投影矩陣的參數(shù)善茎,該類提供了一個(gè)public方法setNearPlane:farPlane:券册。進(jìn)入到.mm文件中查看該初始化方法可以看出,只是對(duì)類內(nèi)部私有屬性進(jìn)行相關(guān)的賦值操作以及對(duì)硬件設(shè)備進(jìn)行相關(guān)的設(shè)置吧垂涯。
??現(xiàn)在來看看方法initRendering烁焙,這個(gè)方法里面主要是做了一些OpenGLES的東西,我們只需要知道里面做了一些和具體業(yè)務(wù)邏輯無關(guān)的東西就行了耕赘。
??接下來看renderFrameVuforia的作用是什么骄蝇?源代碼中說的很清楚:使用OpenGL繪制當(dāng)前幀,當(dāng)需要將當(dāng)前幀渲染到屏幕上時(shí)鞠苟,Vuforia會(huì)定期的在后臺(tái)線程調(diào)用該方法乞榨。同樣和業(yè)務(wù)邏輯無關(guān)秽之,源碼不細(xì)看。同樣方法renderVideoBackground也是使用OpenGL來做吃既,我們只需要從該方法的名字得知其用途(后臺(tái)渲染視頻)即可考榨。
??configureVideoBackgroundWithViewWidth:andHeight:方法從名字就可以知道其作用。updateRenderingPrimitives方法的作用是:當(dāng)屏幕尺寸發(fā)生改變或者是設(shè)備朝向改變之后鹦倚,調(diào)用該方法來更新渲染原始數(shù)據(jù)河质。
??最后需要介紹一下該類很重要的的一個(gè)協(xié)議方法:renderFrameWithState,該方法被用于獲取渲染相關(guān)的數(shù)據(jù)震叙。通過對(duì).mm文件可知掀鹅,每渲染一次都會(huì)調(diào)用該方法一次。

ImageTargetsEAGLView類

該類的頭文件所暴露出來的初始化方法- (id)initWithFrame:(CGRect)frame appSession:(SampleApplicationSession *) app媒楼,我們以該方法入手來分析乐尊。第一個(gè)參數(shù)為當(dāng)前視圖的大小設(shè)置,第二個(gè)參數(shù)為前面我們講到過的一個(gè)類實(shí)例划址。頭文件中余下的方法還有:

- (void)finishOpenGLESCommands;
- (void)freeOpenGLESResources;

- (void) setOffTargetTrackingMode:(BOOL) enabled;
- (void) configureVideoBackgroundWithViewWidth:(float)viewWidth andHeight:(float)viewHeight;
- (void) updateRenderingPrimitives;

方法finishOpenGLESCommands , freeOpenGLESResources分別對(duì)應(yīng)著結(jié)束OpenGL和釋放OpenGL的資源扔嵌。configureVideoBackgroundWithViewWidth:andHeight: , updateRenderingPrimitives和類SampleAppRenderer公開的方法名一樣,這里我猜測(cè)它們作用是一樣的夺颤。setOffTargetTrackingMode:方法作用目前還不是很清晰痢缎,需要去.mm文件中詳查。
??現(xiàn)在進(jìn)入實(shí)現(xiàn)文件中世澜,源碼中提到了關(guān)于OpenGL線程安全的問題独旷。iOS上的OpenGL ES是線程不安全的,在程序中Vuforia使用下面的方法來保證線程(OpenGL 上下文)安全:

  • a寥裂、在主線程中創(chuàng)建OpenGL ES上下文嵌洼。
  • b、Vuforia相機(jī)開始時(shí)抚恒,將其位于我們自己EAGLView視圖上咱台,并開啟renderer線程。
  • c俭驮、Vuforia會(huì)在renderer線程上回溺,定期調(diào)用我們的renderFrameVuforia(SampleAppRenderer類提到)方法。當(dāng)?shù)谝淮握{(diào)用該方法的時(shí)候混萝,defaultFramebuffer并不存在遗遵,調(diào)用createFramebuffer方法來創(chuàng)建它。createFramebuffer由主線程調(diào)用逸嘀,而與此同時(shí)renderer線程會(huì)被阻塞车要。因此確保OpenGL ES上下文不會(huì)被并行使用

在initWithFrame:appSession:的實(shí)現(xiàn)方法中會(huì)進(jìn)行session,OpenGL的context和Renderer的賦值崭倘,初始化和綁定工作翼岁。而方法configureVideoBackgroundWithViewWidth:andHeight: , updateRenderingPrimitives在其實(shí)現(xiàn)方法中的確只是簡(jiǎn)單的調(diào)用了一下SampleAppRenderer 類的實(shí)例方法类垫。
??現(xiàn)在主要來看看方法setOffTargetTrackingMode :,它的實(shí)現(xiàn)很簡(jiǎn)單只是對(duì)其私有成員變量NO琅坡。但是卻在協(xié)議方法renderFrameWithState中大量的使用悉患。該方法大部分是OpenGL相關(guān)的工作,我沒有深究下去榆俺,只整理出來一個(gè)工作流程圖:

圖-2

目前來看ImageTargetsEAGLView類的主要作用在于保證OpenGL在iOS中達(dá)到線程安全售躁,創(chuàng)建buffer和對(duì)buffer的管理,提供了對(duì)OpenGL的控制茴晋,而實(shí)際的渲染則由SampleAppRenderer來實(shí)現(xiàn)陪捷。

ImageTargetsViewController類

現(xiàn)在將目光回到ImageTargetsViewController類上面來。由于是一個(gè)控制器類诺擅,所以我直接從.mm文件中著手市袖。根據(jù)ViewController的加載順序來看具體的邏輯,首先查找loadView方法烁涌,如果沒有則查找viewDidLoad凌盯。源碼中,loadView方法主要?jiǎng)?chuàng)建了vapp烹玉,eaglView以及對(duì)vapp初始化了AR相關(guān)的事務(wù)(其他視圖和手勢(shì)等先忽略,只關(guān)心屬性vapp,eaglView相關(guān)的邏輯)阐滩,將ViewController的View設(shè)置為eaglView二打。
??在loadView中將vapp的代理設(shè)置為控制器自身,此時(shí)通過上面介紹__ SampleApplicationSession__時(shí)對(duì)應(yīng)的程序執(zhí)行流程掂榔,將目光放在對(duì)應(yīng)的部分協(xié)議方法上面继效。

@protocol SampleApplicationControl
- (void) onInitARDone:(NSError *)error;
- (bool) doInitTrackers;
- (bool) doLoadTrackersData;
- (bool) doStartTrackers;
@end

從圖-1可以看出是由doInitTrackers的返回值來判斷是否需要去加載tracker數(shù)據(jù)(doLoadTrachersData),最后在onInitARDone方法流程結(jié)束装获。通過這個(gè)就確定了我們的源碼查看順序:

/// doInitTrackers --> doLoadTrackersData --> onInitARDone

那么在ImageTargetsViewController類中瑞信,其流程圖如下:


圖-3

自此我們的源碼閱讀就告一段落,最后我們將要去實(shí)現(xiàn)開始提到的目的穴豫!

收尾

讀到這里凡简,自定義的數(shù)據(jù)集的切入點(diǎn)在方法doLoadTrackersData方法中,并且要doInitTrackers方法返回YES精肃。如果沒有執(zhí)行“安裝步驟”中的第5步的話秤涩,現(xiàn)在可以去做了!做完之后添加如下代碼到工程中:

///ImageTargetsViewController.mm -> doLoadTrackersData
dataSetCustom = [self loadObjectTrackerDataSet:@"WillDB_Device.xml"];/// 這個(gè)dataset為你自己的名字
if (dataSetCustom == NULL) {
    return NO;
}
if (! [self activateDataSet:dataSetCustom]) {
    return NO;
}

運(yùn)行程序司抱,掃描對(duì)應(yīng)的圖片發(fā)現(xiàn)是能夠成功掃描對(duì)應(yīng)的圖片的筐眷。但是系統(tǒng)的圖片能出來一個(gè)“茶壺”,而我們自己的圖片上面什么也沒有呢习柠?
在這里我不想又去使用這個(gè)煩人的“茶壺”O(jiān)penGL模型了匀谣,我選擇的是一個(gè)皮卡丘的原型(在文末我會(huì)將改造過的demo傳到Github可以去那里下載這個(gè)原型)照棋。

模型obj到opengl數(shù)據(jù)的轉(zhuǎn)換

就目前我知道的來說,在Xcode中無法使用.obj的模型數(shù)據(jù)的武翎。我在網(wǎng)上找到了一個(gè)工具obj2opengl烈炭,具體的使用方法見這里,我還是大體來說一下使用步驟:
將下載好的文件放到特定的文件夾中后频,然后把對(duì)應(yīng)的obj文件和它放在一起梳庆,使用終端進(jìn)入obj2opengl.pl文件所在文件夾之后,輸入如下命令:

./obj2opengl.pl yourobjfilename

成功后卑惜,它會(huì)生成一個(gè)頭文件膏执,這就是通過obj文件生成的紋理坐標(biāo)代碼,在該頭文件中有3個(gè)數(shù)組露久,這三個(gè)數(shù)組分別對(duì)應(yīng)著xxxVerts [], xxxNormals [], xxxTexCoords []更米,和一個(gè)xxxxNumVerts(xxx為你的obj文件名字),具體使用說明毫痕。

模型替換

通過前面的源碼閱讀征峦,我們知道ImageTargetsViewController類是用來加載tracker數(shù)據(jù)的,SampleAppRenderer類是做渲染相關(guān)的數(shù)據(jù)消请,SampleApplicationSession類是使用tracker數(shù)據(jù)并控制AR栏笆,最后只剩下一個(gè)ImageTargetsEAGLView類。在該類中會(huì)做如下操作:

  • 1臊泰、在textureFilenames數(shù)組中蛉加,添加一個(gè)新的紋理。這個(gè)自己選擇一個(gè)紋理圖片缸逃,我是隨便選的针饥,所以看起來會(huì)很丑。

  • 2需频、在ImageTargetsEAGLView類的頭文件中添加一個(gè)私有成員變量pikachuModel丁眼。用它來代替例子中的buildingModel。并在SampleApplication3DModel.h文件中添加方法pikachu_ReWrite昭殉,并在SampleApplication3DModel.m文件中添加如下代碼:

    - (void)pikachu_ReWrite{
    #if kUse3DModel == 1
      _numVertices = XY_PikachuMNumVerts;
      _vertices = XY_PikachuMVerts;
      _normals = XY_PikachuMNormals;
      _texCoords = XY_PikachuMTexCoords;
    #endif
    }
    
  • 3苞七、在ImageTargetsEAGLView.mm的方法loadBuildingsModel中添加如下代碼:

    pikachuModel = [[SampleApplication3DModel alloc] init];
    [pikachuModel pikachu_ReWrite];
    
  • 4、將ImageTargetsEAGLView.mm文件中所有的buildingModel替換為pikachuModel饲化,最后調(diào)節(jié)一下變量kObjectScaleOffTargetTracking的值莽鸭,這個(gè)值調(diào)節(jié)由自己決定。

上述的修改靈感大多是來自頭文件Teapot.h吃靠,但是我們使用obj2opengl時(shí)生成的文件中并沒有Teapot.h中teapotIndices對(duì)應(yīng)的數(shù)組硫眨。相反多了一個(gè)無符號(hào)的整形變量xxxNumVerts,所以除了上訴的方法以外還有另外一種方法,具體的代碼修改如下:

/// ImageTargetsEAGLView.mm -> renderFrameWithState方法中
glVertexPointer(3, GL_FLOAT, 0, XY_PikachuMVerts);
glNormalPointer(GL_FLOAT, 0, XY_PikachuMNormals);
glTexCoordPointer(2, GL_FLOAT, 0, XY_PikachuMTexCoords);

glDrawArrays(GL_TRIANGLES, 0, XY_PikachuMNumVerts);

在使用這個(gè)方法時(shí)其(用obj2opengl生成的頭文件的數(shù)組中的)數(shù)值比例是需要修改的礁阁,而且還需要對(duì)模型進(jìn)行翻轉(zhuǎn)巧号。這個(gè)方法具體見How do I replace the TeapotReplace the teapot model
在修改源碼時(shí)主要就是在修改方法renderFrameWithState姥闭,它在介紹ImageTargetsEAGLView類時(shí)在文件的最開頭就有提到丹鸿,它是在每捕捉到一次tracker之后就會(huì)運(yùn)行一次。
到這里一個(gè)很基本的Vuforia集成棚品,源碼的解讀以及自定義tracker和模型就算完成了靠欢,最后附上Demo地址

相關(guān)鏈接

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末铜跑,一起剝皮案震驚了整個(gè)濱河市门怪,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌锅纺,老刑警劉巖掷空,帶你破解...
    沈念sama閱讀 218,682評(píng)論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異囤锉,居然都是意外死亡坦弟,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,277評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門官地,熙熙樓的掌柜王于貴愁眉苦臉地迎上來酿傍,“玉大人,你說我怎么就攤上這事驱入∨》啵” “怎么了?”我有些...
    開封第一講書人閱讀 165,083評(píng)論 0 355
  • 文/不壞的土叔 我叫張陵沧侥,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我魄鸦,道長(zhǎng)宴杀,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,763評(píng)論 1 295
  • 正文 為了忘掉前任拾因,我火速辦了婚禮旺罢,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘绢记。我一直安慰自己扁达,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,785評(píng)論 6 392
  • 文/花漫 我一把揭開白布蠢熄。 她就那樣靜靜地躺著跪解,像睡著了一般。 火紅的嫁衣襯著肌膚如雪签孔。 梳的紋絲不亂的頭發(fā)上叉讥,一...
    開封第一講書人閱讀 51,624評(píng)論 1 305
  • 那天窘行,我揣著相機(jī)與錄音,去河邊找鬼图仓。 笑死罐盔,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的救崔。 我是一名探鬼主播惶看,決...
    沈念sama閱讀 40,358評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼六孵!你這毒婦竟也來了纬黎?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,261評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤狸臣,失蹤者是張志新(化名)和其女友劉穎莹桅,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體烛亦,經(jīng)...
    沈念sama閱讀 45,722評(píng)論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡诈泼,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,900評(píng)論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了煤禽。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片铐达。...
    茶點(diǎn)故事閱讀 40,030評(píng)論 1 350
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖檬果,靈堂內(nèi)的尸體忽然破棺而出瓮孙,到底是詐尸還是另有隱情,我是刑警寧澤选脊,帶...
    沈念sama閱讀 35,737評(píng)論 5 346
  • 正文 年R本政府宣布杭抠,位于F島的核電站,受9級(jí)特大地震影響恳啥,放射性物質(zhì)發(fā)生泄漏偏灿。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,360評(píng)論 3 330
  • 文/蒙蒙 一钝的、第九天 我趴在偏房一處隱蔽的房頂上張望翁垂。 院中可真熱鬧,春花似錦硝桩、人聲如沸沿猜。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,941評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽啼肩。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間疟游,已是汗流浹背呼畸。 一陣腳步聲響...
    開封第一講書人閱讀 33,057評(píng)論 1 270
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留颁虐,地道東北人蛮原。 一個(gè)月前我還...
    沈念sama閱讀 48,237評(píng)論 3 371
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像另绩,于是被迫代替她去往敵國和親儒陨。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,976評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容

  • *面試心聲:其實(shí)這些題本人都沒怎么背,但是在上海 兩周半 面了大約10家 收到差不多3個(gè)offer,總結(jié)起來就是把...
    Dove_iOS閱讀 27,146評(píng)論 30 470
  • Android 自定義View的各種姿勢(shì)1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 172,162評(píng)論 25 707
  • Morning┏ (^ω^)=今天會(huì)下雨哦記得帶傘出門笋籽。不要因?yàn)闊o人照顧你而失落蹦漠。自己一個(gè)人也要生活得很好。我們懷...
    嘿嚯喲閱讀 157評(píng)論 0 0
  • 一车海、這兩天過得很懶散笛园,但是也很輕松,也很自由侍芝,覺得身心的狀態(tài)研铆,得到了很好的調(diào)整。這兩天最要感謝老公的辛勤付出州叠,為我...
    南宮雨蓉之每天見閱讀 265評(píng)論 0 0
  • 2016年,一半高中致板,一半大學(xué)交煞,一半緊張,一半空閑斟或,鮮明的對(duì)比错敢。總是想說要讓自己的大學(xué)過得充實(shí)有意義缕粹,卻無奈抵不...
    閑雜人兒L閱讀 152評(píng)論 0 0