OpenGLES-07 紋理

前面的文章都是繪制實實在在的圖形的娶靡,在OpenGL中牧牢,我們還可以使用紋理圖片來渲染圖形,使用圖片可以讓描繪出來的物體更加真實也可以讓我們的開發(fā)更加簡單姿锭。

資料:http://learnopengl-cn.readthedocs.io/zh/latest/01%20Getting%20started/06%20Textures/ 塔鳍。

接下來我們直接開始代碼書寫:

1.開始之前,我們把工具類GLESUtils優(yōu)化一下呻此,使之能直接返回我們需要的program轮纫。用了這么久,希望你自己也能封裝焚鲜。

修改.h

#import <Foundation/Foundation.h>
#include <OpenGLES/ES3/gl.h>

@interface GLESUtils : NSObject

// Create a shader object, load the shader source string, and compile the shader.
//
+(GLuint)loadShader:(GLenum)type withString:(NSString *)shaderString;

+(GLuint)loadShader:(GLenum)type withFilepath:(NSString *)shaderFilepath;

//直接返回program
+(GLuint)loadProgram:(NSString *)vertexShaderFilepath withFragmentShaderFilepath:(NSString *)fragmentShaderFilepath;

@end

修改.m

#import "GLESUtils.h"

@implementation GLESUtils

+(GLuint)loadShader:(GLenum)type withFilepath:(NSString *)shaderFilepath
{
    NSError* error;
    NSString* shaderString = [NSString stringWithContentsOfFile:shaderFilepath 
                                                       encoding:NSUTF8StringEncoding
                                                          error:&error];
    if (!shaderString) {
        NSLog(@"Error: loading shader file: %@ %@", shaderFilepath, error.localizedDescription);
        return 0;
    }
    
    return [self loadShader:type withString:shaderString];
}

+(GLuint)loadShader:(GLenum)type withString:(NSString *)shaderString
{   
    // Create the shader object
    GLuint shader = glCreateShader(type);
    if (shader == 0) {
        NSLog(@"Error: failed to create shader.");
        return 0;
    }
    
    // Load the shader source
    const char * shaderStringUTF8 = [shaderString UTF8String];
    glShaderSource(shader, 1, &shaderStringUTF8, NULL);
    
    // Compile the shader
    glCompileShader(shader);
    
    // Check the compile status
    GLint compiled = 0;
    glGetShaderiv(shader, GL_COMPILE_STATUS, &compiled);
    
    if (!compiled) {
        GLint infoLen = 0;
        glGetShaderiv ( shader, GL_INFO_LOG_LENGTH, &infoLen );
        
        if (infoLen > 1) {
            char * infoLog = malloc(sizeof(char) * infoLen);
            glGetShaderInfoLog (shader, infoLen, NULL, infoLog);
            NSLog(@"Error compiling shader:\n%s\n", infoLog );            
            
            free(infoLog);
        }
        
        glDeleteShader(shader);
        return 0;
    }

    return shader;
}

+(GLuint)loadProgram:(NSString *)vertexShaderFilepath withFragmentShaderFilepath:(NSString *)fragmentShaderFilepath
{
    // Load the vertex/fragment shaders
    GLuint vertexShader = [self loadShader:GL_VERTEX_SHADER
                              withFilepath:vertexShaderFilepath];
    if (vertexShader == 0)
        return 0;
    
    GLuint fragmentShader = [self loadShader:GL_FRAGMENT_SHADER
                                withFilepath:fragmentShaderFilepath];
    if (fragmentShader == 0) {
        glDeleteShader(vertexShader);
        return 0;
    }
    
    // Create the program object
    GLuint programHandle = glCreateProgram();
    if (programHandle == 0)
        return 0;
    
    glAttachShader(programHandle, vertexShader);
    glAttachShader(programHandle, fragmentShader);
    
    // Link the program
    glLinkProgram(programHandle);
    
    // Check the link status
    Glint linked;
    glGetProgramiv(programHandle, GL_LINK_STATUS, &linked);
    
    if (!linked) {
        GLint infoLen = 0;
        glGetProgramiv(programHandle, GL_INFO_LOG_LENGTH, &infoLen);
        
        if (infoLen > 1){
            char * infoLog = malloc(sizeof(char) * infoLen);
            glGetProgramInfoLog(programHandle, infoLen, NULL, infoLog);

            NSLog(@"Error linking program:\n%s\n", infoLog);            
            
            free(infoLog);
        }
        
        glDeleteProgram(programHandle );
        return 0;
    }
    
    // Free up no longer needed shader resources
    glDeleteShader(vertexShader);
    glDeleteShader(fragmentShader);
    
    return programHandle;
}

2.我們的項目需要返璞歸真掌唾,重新寫一個
1).創(chuàng)建項目
2).新建MyGLView(實現(xiàn)layerClass放前、initWithFrame、setupLayer郑兴、setupContext犀斋、setupRenderBuffer、setupFrameBuffer情连、setupProgram叽粹、render這些函數(shù))
做完,.m應該是這樣的:

#import "MyGLView.h"
#import "GLESUtils.h"
#import <OpenGLES/ES3/gl.h>

@interface MyGLView ()
{
    CAEAGLLayer *_eaglLayer;  //OpenGL內容只會在此類layer上描繪
    EAGLContext *_context;    //OpenGL渲染上下文
    GLuint _renderBuffer;     //
    GLuint _frameBuffer;      //

    GLuint _programHandle;
    GLuint _positionSlot; //頂點槽位
    GLuint _colorSlot;   //顏色槽位
    
}

@end

@implementation MyGLView

+(Class)layerClass{
    //OpenGL內容只會在此類layer上描繪
    return [CAEAGLLayer class];
}

-(instancetype)initWithFrame:(CGRect)frame{
    if (self==[super initWithFrame:frame]) {
        [self setupLayer];
        [self setupContext];
        
        [self setupRenderBuffer];
        [self setupFrameBuffer];
        [self setupProgram];  //配置program
        [self render];
    }
    
    return self;
}

- (void)setupLayer
{
    _eaglLayer = (CAEAGLLayer*) self.layer;
    
    // CALayer 默認是透明的却舀,必須將它設為不透明才能讓其可見,性能最好
    _eaglLayer.opaque = YES;
    
    // 設置描繪屬性虫几,在這里設置不維持渲染內容以及顏色格式為 RGBA8
    _eaglLayer.drawableProperties = [NSDictionary dictionaryWithObjectsAndKeys:
                                     [NSNumber numberWithBool:NO], kEAGLDrawablePropertyRetainedBacking, kEAGLColorFormatRGBA8, kEAGLDrawablePropertyColorFormat, nil];
}

- (void)setupContext {
    // 指定 OpenGLES 渲染API的版本,在這里我們使用OpenGLES 3.0挽拔,由于3.0兼容2.0并且功能更強辆脸,為何不用更好的呢
    EAGLRenderingAPI api = kEAGLRenderingAPIOpenGLES3;
    _context = [[EAGLContext alloc] initWithAPI:api];
    if (!_context) {
        NSLog(@"Failed to initialize OpenGLES 3.0 context");
    }
    
    // 設置為當前上下文
    [EAGLContext setCurrentContext:_context];
}

-(void)setupRenderBuffer{
    glGenRenderbuffers(1, &_renderBuffer); //生成和綁定render buffer的API函數(shù)
    glBindRenderbuffer(GL_RENDERBUFFER, _renderBuffer);
    //為其分配空間
    [_context renderbufferStorage:GL_RENDERBUFFER fromDrawable:_eaglLayer];
}

-(void)setupFrameBuffer{
    glGenFramebuffers(1, &_frameBuffer);   //生成和綁定frame buffer的API函數(shù)
    glBindFramebuffer(GL_FRAMEBUFFER, _frameBuffer);
    //將renderbuffer跟framebuffer進行綁定
    glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, _renderBuffer);
}

- (void)setupProgram
{
    // Load shaders
    //
    NSString * vertexShaderPath = [[NSBundle mainBundle] pathForResource:@"VertexShader"
                                                                  ofType:@"gals"];
    NSString * fragmentShaderPath = [[NSBundle mainBundle] pathForResource:@"FragmentShader"
                                                                    ofType:@"gals"];

    _programHandle = [GLESUtils loadProgram:vertexShaderPath withFragmentShaderFilepath:fragmentShaderPath];
    glUseProgram(_programHandle);
    
    // Get attribute slot from program
    //
    _positionSlot = glGetAttribLocation(_programHandle, "vPosition");
    
}

-(void)render
{
    //設置清屏顏色,默認是黑色,如果你的運行結果是黑色螃诅,問題就可能在這兒
    glClearColor(0.3, 0.5, 0.8, 1.0);
    /*
    glClear指定清除的buffer
    共可設置三個選項GL_COLOR_BUFFER_BIT啡氢,GL_DEPTH_BUFFER_BIT和GL_STENCIL_BUFFER_BIT
    也可組合如:glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    這里我們只用了color buffer,所以只需清除GL_COLOR_BUFFER_BIT
     */
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    glEnable(GL_DEPTH_TEST);  //添加
    
    // Setup viewport
    glViewport(0, 0, self.frame.size.width, self.frame.size.height);
    

    
    [_context presentRenderbuffer:_renderBuffer];
    
}

@end

3).創(chuàng)建頂點和片元著色器腳本文件术裸。
由于要使用紋理,我們頂點著色器腳本VertexShader.glsl需改寫為:

attribute vec4 vPosition;

attribute vec2 TexCoordIn;
varying vec2 TexCoordOut;

void main(void)
{
    gl_Position = vPosition; 
    TexCoordOut = TexCoordIn;
}

其中TexCoordIn為傳入進來的紋理坐標倘是,TexCoordOut為要傳入到片元著色器中的紋理坐標。也就是把傳入進來的紋理坐標TexCoordIn傳入到片元著色器以供處理袭艺。

FragmentShader.glsl改為:

uniform sampler2D ourTexture;

varying lowp vec2 TexCoordOut;

void main()
{
    gl_FragColor = texture2D(ourTexture, TexCoordOut);
}

以上varying的使用就是保證TexCoordOut的唯一性搀崭,有前面的基礎應該很容易理解

uniform sampler2D ourTexture; //這句代碼的意義是鏈接的采樣紋理常量
gl_FragColor = texture2D(ourTexture, TexCoordOut); //這句代碼表示以紋理坐標TexCoordOut來采樣ourTexture當做像素的顏色

4).使用紋理
根據(jù)我們glsl腳本,我們在項目中需要新定義兩個新變量:
GLuint _texCoordSlot; //紋理坐標槽位
GLuint _ourTextureSlot; //紋理對象槽位
在MyGLView.m里

@interface MyGLView ()
{
    CAEAGLLayer *_eaglLayer;  //OpenGL內容只會在此類layer上描繪
    EAGLContext *_context;    //OpenGL渲染上下文
    GLuint _renderBuffer;     //
    GLuint _frameBuffer;      //

    GLuint _programHandle;
    GLuint _positionSlot; //頂點槽位
    GLuint _texCoordSlot;   //紋理坐標槽位
    GLuint _ourTextureSlot; //紋理對象槽位
}

然后我們在設置著色器程序- (void)setupProgram()方法里獲取槽位值:

- (void)setupProgram
{
    // Load shaders
    //
    NSString * vertexShaderPath = [[NSBundle mainBundle] pathForResource:@"VertexShader"
                                                                  ofType:@"gals"];
    NSString * fragmentShaderPath = [[NSBundle mainBundle] pathForResource:@"FragmentShader"
                                                                    ofType:@"gals"];

    _programHandle = [GLESUtils loadProgram:vertexShaderPath withFragmentShaderFilepath:fragmentShaderPath];
    glUseProgram(_programHandle);
    
    // Get attribute slot from program
    //
    _positionSlot   = glGetAttribLocation(_programHandle, "vPosition");
    glEnableVertexAttribArray(_positionSlot);
    
    //獲取紋理相關槽位,請注意glGetAttribLocation和glGetUniformLocation的區(qū)別
    _texCoordSlot   = glGetAttribLocation(_programHandle, "TexCoordIn");
    glEnableVertexAttribArray(_texCoordSlot);
    
    _ourTextureSlot = glGetUniformLocation(_programHandle, "ourTexture");
}

5).紋理工具類TextureManager
到目前為止猾编,我們嗨沒有真正使用到紋理瘤睹,要真正使用紋理,我們需要紋理圖片和把紋理圖片轉成紋理對象的方法答倡。
關于紋理圖片的話轰传,不用說啦,隨便找一張:


timg.jpg

關于把紋理圖片轉成紋理對象的方法瘪撇,我們封裝成一個專門的類TextureManager來干這種事:
新建TextureManager類繼承NSObject获茬,在.h里

#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>

@interface TextureManager : NSObject

/*
 *  通過UIImage的方式獲取紋理對象
 */
+ (GLuint)getTextureImage:(UIImage *)image;

@end

在.m中實現(xiàn)對應功能,代碼中給出了相應解釋:

#import "TextureManager.h"
#import <OpenGLES/ES3/gl.h>

@implementation TextureManager

/*
 *  通過UIImage的方式獲取紋理對象
 */
+ (GLuint)getTextureImage:(UIImage *)image {
    
    // 獲取UIImage并轉換成CGImage
    CGImageRef spriteImage = image.CGImage;
    
    if(!spriteImage) {
        return 0;
    }
    
    // 獲取圖片的大小
    GLsizei width  = (GLsizei)CGImageGetWidth(spriteImage);
    GLsizei height = (GLsizei)CGImageGetHeight(spriteImage);
    
    
    // 分配內存,并初始化該內存空間為零, 因為一個像素有4個通道(RGBA)所以乘4
    GLubyte * spriteData = (GLubyte *)calloc(width * height * 4, sizeof(GLubyte));
    
    /*
     *  創(chuàng)建位圖上下文
     */
    CGContextRef spriteContext = CGBitmapContextCreate(spriteData, width, height, 8, width*4,
                                                       CGImageGetColorSpace(spriteImage), kCGImageAlphaPremultipliedLast);
    
    // 在上下文中繪制圖片
    CGContextDrawImage(spriteContext, CGRectMake(0, 0, width, height), spriteImage);
    // 釋放上下文
    CGContextRelease(spriteContext);
    
    // 創(chuàng)建紋理對象并且綁定, 紋理對象用無符號整數(shù)表示, 這個紋理對象相當于我們在C語言文件操作里面的句柄
    GLuint texName;
    glGenTextures(1, &texName);
    glBindTexture(GL_TEXTURE_2D, texName);
    
    //設置紋理循環(huán)模式
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);

    //設置紋理過濾模式
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    
    // 加載圖像數(shù)據(jù), 并上傳紋理
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, spriteData);
    
    // 解綁紋理對象(在本文這里解不解綁都一樣设江,因為后面還是要綁定)
    glBindTexture(GL_TEXTURE_2D, 0);
    // 釋放分配的內存空間
    free(spriteData);
    
    return texName;
}

@end

這里面值得注意的是紋理的創(chuàng)建過程和紋理的循環(huán)和過濾模式,對紋理循環(huán)和過濾模式不清晰請繼續(xù)回到 http://learnopengl-cn.readthedocs.io/zh/latest/01%20Getting%20started/06%20Textures/
這里也稍稍提一下多級漸遠紋理,上面鏈接中對多級漸遠紋理的解釋很詳細攘轩,我們在iOS端使用的時候最簡單的只需要調用

glGenerateMipmap(GL_TEXTURE_2D);

然后設置紋理縮小時的過濾模式為多級漸遠紋理過濾就行:
舉例:

 //設置紋理過濾模式
    glGenerateMipmap(GL_TEXTURE_2D);  //自動生成多級漸遠紋理
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);  //多級漸遠紋理過濾模式
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    
    // 加載圖像數(shù)據(jù), 并上傳紋理
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, spriteData);
注意:一個常見的錯誤是叉存,將放大過濾的選項設置為多級漸遠紋理過濾選項之一。這樣沒有任何效果度帮,因為多級漸遠紋理主要是使用在紋理被縮小的情況下的:紋理放大不會使用多級漸遠紋理歼捏。

6).渲染紋理
圖片咱有了稿存,轉紋理對象方法也有了,接下來咱們開始渲染紋理瞳秽。
首先在.m里新增一個紋理對象變量

GLuint _textureID;  //紋理對象

然后我們在- (void)setupProgram()方法最后獲取紋理對象

//獲取紋理對象
    _textureID = [TextureManager getTextureImage:[UIImage imageNamed:@"timg.jpg"]];

最后就是render了瓣履,render前我們先構造紋理的坐標數(shù)據(jù):

//4個頂點(分別表示xyz軸)
    GLfloat vertices[] = {
     //   x    y    z
        -0.5, -0.5, 0,  //左下
         0.5, -0.5, 0,  //右下
        -0.5,  0.5, 0,  //左上
         0.5,  0.5, 0,  //右上
    };
    
    //4個頂點對應紋理坐標
    GLfloat textureCoord[] = {
        
        0, 0,
        1, 0,
        0, 1,
        1, 1,
    };

整個render方法如下:

-(void)render
{
    //設置清屏顏色,默認是黑色,如果你的運行結果是黑色练俐,問題就可能在這兒
    glClearColor(0.3, 0.5, 0.8, 1.0);
    /*
    glClear指定清除的buffer
    共可設置三個選項GL_COLOR_BUFFER_BIT袖迎,GL_DEPTH_BUFFER_BIT和GL_STENCIL_BUFFER_BIT
    也可組合如:glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    這里我們只用了color buffer,所以只需清除GL_COLOR_BUFFER_BIT
     */
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    glEnable(GL_DEPTH_TEST);  //添加
    
    // Setup viewport
    glViewport(0, 0, self.frame.size.width, self.frame.size.height);
    
    //4個頂點(分別表示xyz軸)
    GLfloat vertices[] = {
     //   x    y    z
        -0.5, -0.5, 0,  //左下
         0.5, -0.5, 0,  //右下
        -0.5,  0.5, 0,  //左上
         0.5,  0.5, 0,  //右上
    };
    
    //4個頂點對應紋理坐標
    GLfloat textureCoord[] = {
        
        0, 0,
        1, 0,
        0, 1,
        1, 1,
    };

    glVertexAttribPointer(_positionSlot, 3, GL_FLOAT, GL_FALSE, 0, vertices);
    glVertexAttribPointer(_texCoordSlot, 2, GL_FLOAT, GL_FALSE, 0, textureCoord);
    
    //使用紋理單元
    glActiveTexture(GL_TEXTURE0);
    glBindTexture(GL_TEXTURE_2D, _textureID);
    glUniform1i(_ourTextureSlot, 0);
    
    glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
    [_context presentRenderbuffer:_renderBuffer];
}

所有做完我們運行查看一下結果:


結果.png

唉腺晾,這個圖片怎么反了把嘧丁?
原因就是紋理坐標的原點在左下角悯蝉,x,y正方向為往右往上


tex_coords.png

而我們openGL坐標系原點在屏幕中心归形,x正方向與紋理x正方向相同,但y正方向與紋理相反鼻由,這樣的話暇榴,解決辦法可以修改我們頂點數(shù)據(jù)對應的紋理坐標,也可以在VertexShader.glsl文件里把:TexCoordOut = TexCoordIn;改為TexCoordOut = vec2(TexCoordIn.x, 1.0-TexCoordIn.y);

attribute vec4 vPosition;

attribute vec2 TexCoordIn;
varying vec2 TexCoordOut;

void main(void)
{
    gl_Position = vPosition; 
//    TexCoordOut = TexCoordIn;
    TexCoordOut = vec2(TexCoordIn.x, 1.0-TexCoordIn.y);
}

這個時候圖片方向就對了蕉世,我們運行一下:


正確結果.png

所有教程代碼在此 : https://github.com/qingmomo/iOS-OpenGLES-

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末蔼紧,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子讨彼,更是在濱河造成了極大的恐慌歉井,老刑警劉巖,帶你破解...
    沈念sama閱讀 217,542評論 6 504
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件哈误,死亡現(xiàn)場離奇詭異哩至,居然都是意外死亡,警方通過查閱死者的電腦和手機蜜自,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,822評論 3 394
  • 文/潘曉璐 我一進店門菩貌,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人重荠,你說我怎么就攤上這事箭阶。” “怎么了戈鲁?”我有些...
    開封第一講書人閱讀 163,912評論 0 354
  • 文/不壞的土叔 我叫張陵仇参,是天一觀的道長。 經(jīng)常有香客問我婆殿,道長诈乒,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,449評論 1 293
  • 正文 為了忘掉前任婆芦,我火速辦了婚禮怕磨,結果婚禮上喂饥,老公的妹妹穿的比我還像新娘。我一直安慰自己肠鲫,他們只是感情好员帮,可當我...
    茶點故事閱讀 67,500評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著导饲,像睡著了一般捞高。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上帜消,一...
    開封第一講書人閱讀 51,370評論 1 302
  • 那天棠枉,我揣著相機與錄音,去河邊找鬼泡挺。 笑死辈讶,一個胖子當著我的面吹牛,可吹牛的內容都是我干的娄猫。 我是一名探鬼主播贱除,決...
    沈念sama閱讀 40,193評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼媳溺!你這毒婦竟也來了月幌?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 39,074評論 0 276
  • 序言:老撾萬榮一對情侶失蹤悬蔽,失蹤者是張志新(化名)和其女友劉穎扯躺,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體蝎困,經(jīng)...
    沈念sama閱讀 45,505評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡录语,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 37,722評論 3 335
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了禾乘。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片澎埠。...
    茶點故事閱讀 39,841評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖始藕,靈堂內的尸體忽然破棺而出蒲稳,到底是詐尸還是另有隱情,我是刑警寧澤伍派,帶...
    沈念sama閱讀 35,569評論 5 345
  • 正文 年R本政府宣布江耀,位于F島的核電站,受9級特大地震影響诉植,放射性物質發(fā)生泄漏祥国。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,168評論 3 328
  • 文/蒙蒙 一倍踪、第九天 我趴在偏房一處隱蔽的房頂上張望系宫。 院中可真熱鬧,春花似錦建车、人聲如沸扩借。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,783評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽潮罪。三九已至,卻和暖如春领斥,著一層夾襖步出監(jiān)牢的瞬間嫉到,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,918評論 1 269
  • 我被黑心中介騙來泰國打工月洛, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留何恶,地道東北人。 一個月前我還...
    沈念sama閱讀 47,962評論 2 370
  • 正文 我出身青樓嚼黔,卻偏偏與公主長得像细层,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子唬涧,可洞房花燭夜當晚...
    茶點故事閱讀 44,781評論 2 354

推薦閱讀更多精彩內容