OpenglES2.0 for Android:纹理映射

利用android_ndk开发OpenGLES如何利用上层Bitmap生成纹理 在网上找了很多的资料,想利用android上层生成Bitmap,然后把Bitmap的pixel传递给JNI,然后再C++中生成纹理映射,但是结果都失败了。最后自己想得到了一个方法,在android上层直接生成纹理映射,然后把纹理映射的地址传递给JNI,这样就可以利用上层的Bitmap生成纹理映射了。当然这不是最好的方法,但是由于自己现在的能力有限,暂时只能依靠这个方法了,如果有人知道如何正确的利用 阅读详情

OpenglES2.0 for Android:纹理映射

前言 


纹理映射又叫做纹理贴图,是将纹理空间中的纹理像素映射到屏幕空间中的像素的过程。就是把一幅图像贴到三维物体的表面上来增强真实感,
可以和光照计算、图像混合等技术结合起来形成许多非常漂亮的效果 (百度百科)。简单来说,纹理就是一个图形或者照片,我们可以将它们
加载到Opengl中用以美化我们绘制的物体。

前期准备


我们现在准备实现这样一个功能:将一张图片贴到一个正方形中 。我们在以前画矩形的那节代码的基础上进行实现纹理贴图。这里我们新建一个项目
OpenglESRectangle ,然后将画矩形的相关代码copy过来~~,然后还记得我们绘制圆变成椭圆的问题吗,我们在这里给矩形也加入正交投影,以便来绘制
一个正方形。此时目录结构如下 :



因为加入了正交投影比起原先绘制矩形那一节的代码有些变动,发生变动的文件有 MyRender.java , Square.java  ,simple_vertex_shader.glsl ,此时这三个文件代码如下:

package com.cumt.shape;

import java.nio.ByteBuffer;  
import java.nio.ByteOrder;  
import java.nio.FloatBuffer;  
import com.cumt.openglesrectangle.R;
import com.cumt.utils.ShaderHelper;
import com.cumt.utils.TextResourceReader;
import android.content.Context;  
import android.opengl.GLES20;  
import android.opengl.Matrix;
  
public class Square {  
      
    private Context context;  
  
    //float类型的字节数  
    private static final int BYTES_PER_FLOAT = 4;  
    // 数组中每个顶点的坐标数  
    static final int COORDS_PER_VERTEX = 2;  
      
    /*------------------第一步: 修改顶点数据-------------------------*/  
    //矩形顶点坐标  
    static float squareCoords[] = { //以三角形扇的形式绘制
    	-0.5f,  0.5f ,   // top left  
        0.5f,  0.5f  , // top right  
        0.5f, -0.5f  , // bottom right  
       -0.5f, -0.5f  };  // bottom left  
      
    private FloatBuffer vertexBuffer;  
      
    //------------第一个是顶点着色器的变量名,第二个是片段着色器的变量名  
    private static final String A_POSITION = "a_Position";  
    private static final String U_COLOR = "u_Color";  
    private static final String U_MATRIX = "u_Matrix";
    //------------获得program的ID的含义类似的  
    private int uColorLocation;  
    private int aPositionLocation;  
    private int uMatrixLocation;  
    private int program;//保存program的id  
      
    /*------------------第二步: 修改顶点个数-------------------------*/  
    private static final int POSITION_COMPONENT_COUNT = 4;  
          
    float[] projectionMatrix = new float[16];//变换矩阵
      
    public Square(Context context) {  
        this.context = context;  
        vertexBuffer = ByteBuffer  
                .allocateDirect(squareCoords.length * BYTES_PER_FLOAT)  
                .order(ByteOrder.nativeOrder())  
                .asFloatBuffer();  
        // 把坐标们加入FloatBuffer中  
        vertexBuffer.put(squareCoords);  
        // 设置buffer,从第一个坐标开始读  
        vertexBuffer.position(0);  
          
        getProgram();  
          
        uColorLocation = GLES20.glGetUniformLocation(program, U_COLOR);  
        aPositionLocation = GLES20.glGetAttribLocation(program, A_POSITION);  
        uMatrixLocation = GLES20.glGetUniformLocation(program, U_MATRIX);
        
        GLES20.glVertexAttribPointer(aPositionLocation, COORDS_PER_VERTEX,  
                GLES20.GL_FLOAT, false, 0, vertexBuffer);  
        GLES20.glEnableVertexAttribArray(aPositionLocation);  
    }  
      
    //获取program  
    private void getProgram(){  
        //获取顶点着色器文本  
        String vertexShaderSource = TextResourceReader  
                .readTextFileFromResource(context, R.raw.simple_vertex_shader);  
        //获取片段着色器文本  
        String fragmentShaderSource = TextResourceReader  
                .readTextFileFromResource(context, R.raw.simple_fragment_shader);  
        //获取program的id  
        program = ShaderHelper.buildProgram(vertexShaderSource, fragmentShaderSource);  
        GLES20.glUseProgram(program);  
    }  
    
    //设置正交投影矩阵
    public void projectionMatrix(int width,int height){  
        final float aspectRatio = width > height ?  
                (float) width / (float) height :  
                (float) height / (float) width;  
        if(width > height){  
            Matrix.orthoM(projectionMatrix, 0, -aspectRatio, aspectRatio, -1f, 1f, -1f, 1f);  
        }else{  
            Matrix.orthoM(projectionMatrix, 0, -1f, 1f, -aspectRatio, aspectRatio, -1f, 1f);  
        }  
    }  
    
    //以GL_LINE_LOOP方式绘制  
    public void draw(){  
    	GLES20.glUniformMatrix4fv(uMatrixLocation, 1, false, projectionMatrix, 0);
        GLES20.glUniform4f(uColorLocation, 0.0f, 0.0f, 1.0f, 1.0f);       
        /*------------------第三步: 修改绘制方式-------------------------*/  
        GLES20.glDrawArrays(GLES20.GL_TRIANGLE_FAN, 0, POSITION_COMPONENT_COUNT);  
    }  
}

package com.cumt.render;
import javax.microedition.khronos.egl.EGLConfig;  
import javax.microedition.khronos.opengles.GL10;  
  
import com.cumt.shape.Square;  
import android.content.Context;  
import android.opengl.GLSurfaceView.Renderer;  
import android.util.Log;  
import static android.opengl.GLES20.glClear;  
import static android.opengl.GLES20.glClearColor;  
import static android.opengl.GLES20.glViewport;  
import static android.opengl.GLES20.GL_COLOR_BUFFER_BIT;  
  
public class MyRender implements Renderer {  
      
    private Context context;  
      
    public MyRender(Context context){  
        this.context = context;  
    }  
      
    //定义矩形对象  
    Square square;  
      
    public void onSurfaceCreated(GL10 gl, EGLConfig config) {  
        Log.w("MyRender","onSurfaceCreated");  
        // TODO Auto-generated method stub  
        //First:设置清空屏幕用的颜色,前三个参数对应红绿蓝,最后一个对应alpha  
        glClearColor(1.0f, 1.0f, 1.0f, 0.0f);
        square = new Square(context);  
    }  
  
    public void onSurfaceChanged(GL10 gl, int width, int height) {  
        Log.w("MyRender","onSurfaceChanged");  
        // TODO Auto-generated method stub  
        //Second:设置视口尺寸,即告诉opengl可以用来渲染的surface大小  
        glViewport(0,0,width,height);  
        square.projectionMatrix(width, height);
    }  
  
    public void onDrawFrame(GL10 gl) {  
        Log.w("MyRender","onDrawFrame");  
        // TODO Auto-generated method stub  
        //Third:清空屏幕,擦除屏幕上所有的颜色,并用之前glClearColor定义的颜色填充整个屏幕  
        glClear(GL_COLOR_BUFFER_BIT);  
        square.draw();  
    }  
}

//simple_vertex_shader.glsl
uniform mat4 u_Matrix;
attribute vec4 a_Position;   
  		
void main()                    
{                              
    gl_Position = u_Matrix * a_Position;
}   

此时运行效果如下 :

我们要贴的图如下 (512 * 512 ) 要注意opengl es2.0中纹理不必须是正方形,但每个纬度应该是2的幂 ):



我们要将该图片贴到上面的矩形中 

正式开始


下面让我们正式开始做纹理贴图 ,看下过程 :




纹理工具类 


package com.cumt.utils;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.opengl.GLES20;
import android.opengl.GLUtils;
import android.util.Log;

public class TextureHelper {
	
	public static final String TAG = "TextureHelper";
	
	public static int loadTexture(Context context,int resourceId){
		/*
		 * 第一步 : 创建纹理对象
		 */
		final int[] textureObjectId = new int[1];//用于存储返回的纹理对象ID
		GLES20.glGenTextures(1,textureObjectId, 0);
		if(textureObjectId[0] == 0){//若返回为0,,则创建失败
			if(LoggerConfig.ON){
				Log.w(TAG,"Could not generate a new Opengl texture object");
			}
			return 0;
		}
		/*
		 * 第二步: 加载位图数据并与纹理绑定
		 */
		final BitmapFactory.Options options = new BitmapFactory.Options();
		options.inScaled = false;//Opengl需要非压缩形式的原始数据
		final Bitmap bitmap = BitmapFactory.decodeResource(context.getResources(),resourceId, options);
		if(bitmap == null){
			if(LoggerConfig.ON){
				Log.w(TAG,"ResourceId:"+resourceId+"could not be decoded");
			}
			GLES20.glDeleteTextures(1, textureObjectId, 0);
			return 0;
		}
		GLES20.glBindTexture(GLES20.GL_TEXTURE_2D,textureObjectId[0]);//通过纹理ID进行绑定
		/*
		 * 第三步: 设置纹理过滤
		 */
		//设置缩小时为三线性过滤
		GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER,GLES20.GL_LINEAR_MIPMAP_LINEAR);
		//设置放大时为双线性过滤
		GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_LINEAR);
		/*
		 * 第四步: 加载纹理到Opengl并返回ID
		 */
		GLUtils.texImage2D(GLES20.GL_TEXTURE_2D, 0, bitmap, 0);
		bitmap.recycle();
		GLES20.glGenerateMipmap(GLES20.GL_TEXTURE_2D);
		return textureObjectId[0];
	}
}

这里要说下纹理过滤 的内容,纹理过滤应用通常有两种情况,一种是GL_TEXTURE_MIN_FILTER ,即纹理被缩小时,比如一个512 x 512的纹理贴到一个平行于xy平面的正方形上,最后该正方形在屏幕上只占256 x 256的像素矩阵,这种情况下一个象素对应着多个纹理单元。另一种是GL_TEXTURE_MAG_FILTER,即纹理被放大时。下面简要说下Opengl的纹理过滤模式 , Opengl纹理过滤模式如下 :
----------------------------------------------------------------------------------------------------------------------------------------------------------------
GL_NEAREST      最近邻过滤
   GL_NEAREST_MIPMAP_NEAREST  使用MIP贴图的最近邻过滤
GL_NEAREST_MIPMAP_LINEAR    使用MIP贴图级别之间插值的最近邻过滤
GL_LINEAR  双线性过滤
GL_LINEAR_MIPMAP_NEAREST    使用MIP贴图的双线性过滤
GL_LINEAR_MIPMAP_LINEAR    三线性过滤 (使用MIP贴图级别之间插值的双线性过滤 )
---------------------------------------------------------------------------------------------------------------------------------------------------------------
在缩小和放大情况下,Opengl支持不同的过滤模式,如下所示:
---------------------------------------------------------------------------------------------------------------------------------------------------------------
缩小情况:
GL_NEAREST 
GL_NEAREST_MIPMAP_NEAREST 
GL_NEAREST_MIPMAP_LINEAR 
GL_LINEAR 
GL_LINEAR_MIPMAP_NEAREST 
GL_LINEAR_MIPMAP_LINEAR 
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
放大 情况 :
GL_NEAREST
GL_LINEAR 
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
最近邻过滤:这个比较简单,每个像素的纹理坐标,并不是刚好对应一个采样点时,按照最接近的采样点进行采样。当放大纹理时,锯齿会比较明显,
每个纹理单元都显示为一个小方块。当缩小时,会丢失许多细节。
双线性过滤:使用双线性插值平滑像素之间的过渡。放大时,锯齿看起来会比最近邻过滤少许多,看起来更加平滑。
MIP贴图 :当缩小到一定程度时,使用双线性过滤会失去太多细节,还可能引起噪声以及物体移动过程中的闪烁,为了克服这些问题就有了MIP贴图技术。
    关于MIP贴图 ,维基上有更详细解释 :https://en.wikipedia.org/wiki/Mipmap
三线性过滤 :用于消除每个MIP贴图级别之间的过渡,得到一个更为平滑的图像。

新的着色器 


在创建新的着色器之前,我们先明确一下Opengl的二维纹理坐标


对于一个二维的纹理,它有着自己的坐标空间,如上图所示。其有两个维度,S 与 T ,范围都是 0 到 1 。

顶点着色器代码如下 :
//texture_vertex_shader.glsl
uniform mat4 u_Matrix;
attribute vec4 a_Position;  
attribute vec2 a_TextureCoordinates;

varying vec2 v_TextureCoordinates;

void main()                    
{                            
    v_TextureCoordinates = a_TextureCoordinates;	  	  
    gl_Position = u_Matrix * a_Position;    
} 
其中 a_TextureCoordinates 用于接收纹理的坐标数据,v_TextureCoordinates用于将纹理数据传递给片段着色器,因为纹理有两个分量 S与 T 所以使用vec2类型。

片段着色器如下:
//texture_fragment_shader.glsl
precision mediump float;       	 				
uniform sampler2D u_TextureUnit;      	 								
varying vec2 v_TextureCoordinates;      	   								
  
void main()                    		
{                              	
    gl_FragColor = texture2D(u_TextureUnit, v_TextureCoordinates);                           		
}

texture2D是着色器语言内置的纹理采样函数,用于根据指定的纹理坐标就行纹理采样,返回值类型为vec4 。


纹理坐标 


//矩形顶点坐标  与 纹理坐标
    static float squareCoords[] = { //以三角形扇的形式绘制
    	//x     y       s   t
    	-0.5f,  0.5f ,  0 , 0 , // top left  
        0.5f,  0.5f  ,  1 , 0 ,// top right  
        0.5f, -0.5f  ,  1 , 1 ,// bottom right  
       -0.5f, -0.5f  ,  0 , 1};  // bottom left  

我们绘制的矩形的左上角对应着纹理的 (0,0 )  大家注意这个映射关系,也就是我们拿出一张图其左上角的纹理坐标为 (0,0)而不是 (0,1)。
前面我们已经完成了纹理工具类,下面只需要使用它,然互将数据传入着色器。此时Square类代码如下 (Square.java):

package com.cumt.shape;

import static android.opengl.GLES20.GL_TEXTURE0;
import static android.opengl.GLES20.GL_TEXTURE_2D;
import static android.opengl.GLES20.glActiveTexture;
import static android.opengl.GLES20.glBindTexture;
import static android.opengl.GLES20.glUniform1i;
import java.nio.ByteBuffer;  
import java.nio.ByteOrder;  
import java.nio.FloatBuffer;  
import com.cumt.openglesrectangle.R;
import com.cumt.utils.ShaderHelper;
import com.cumt.utils.TextResourceReader;
import com.cumt.utils.TextureHelper;
import android.content.Context;  
import android.opengl.GLES20;  
import android.opengl.Matrix;
  
public class Square {  
      
    private Context context;  
  
    //float类型的字节数  
    private static final int BYTES_PER_FLOAT = 4;  
    // 数组中每个顶点的坐标数  
    static final int COORDS_PER_VERTEX = 2;  
      
    /*------------------修改顶点数据 ,加入顶点对应的纹理坐标-------------------------*/  
    //矩形顶点坐标  与 纹理坐标
    static float squareCoords[] = { //以三角形扇的形式绘制
    	//x     y       s   t
    	-0.5f,  0.5f ,  0 , 0 , // top left  
        0.5f,  0.5f  ,  1 , 0 ,// top right  
        0.5f, -0.5f  ,  1 , 1 ,// bottom right  
       -0.5f, -0.5f  ,  0 , 1};  // bottom left  
      
    private FloatBuffer vertexBuffer;  
    private static final int VERTEX_COUNTS = 4;//顶点坐标数
    private static final int POSITION_COMPONENT_COUNT = 2;  //一个顶点坐标含有的元素个数
    private static final int TEXTURE_COORDIANTES_COMPONENT_COUNT = 2; //一个纹理坐标含有的元素个数
    //因为我们的顶点数据和纹理坐标数据放在了一起 ,所以在使用glVertexAttribPointer等函数时,其中的stride参数就需要传入了,
    //用于高速着色器应该如何读取坐标值 ,比如这里我们的着色器读取坐标时,设置从位置 0开始读,读取x , y后就会跳过 s t 接着读取 x y
    //这就是通过传入stride参数实现的
	private static final int STRIDE = (POSITION_COMPONENT_COUNT + TEXTURE_COORDIANTES_COMPONENT_COUNT)
			* BYTES_PER_FLOAT;
    //------------第一个是顶点着色器的变量名,第二个是片段着色器的变量名  
    private static final String A_POSITION = "a_Position";  
    private static final String U_MATRIX = "u_Matrix";
    private static final String A_TEXTURE_COORDINATES = "a_TextureCoordinates";//纹理
	private static final String U_TEXTURE_UNIT = "u_TextureUnit";//纹理
	
    private int aPositionLocation;  
    private int uMatrixLocation;  
    private int uTextureUnitLocation;
    private int aTextureCoordinates;
    private int program;//保存program的id  
    private int texture;
    
    float[] projectionMatrix = new float[16];//变换矩阵
      
    public Square(Context context) {  
        this.context = context;  
        vertexBuffer = ByteBuffer  
                .allocateDirect(squareCoords.length * BYTES_PER_FLOAT)  
                .order(ByteOrder.nativeOrder())  
                .asFloatBuffer();  
        // 把坐标们加入FloatBuffer中  
        vertexBuffer.put(squareCoords);  
        // 设置buffer,从第一个坐标开始读  
        vertexBuffer.position(0);  
          
        getProgram();  
          
        aPositionLocation = GLES20.glGetAttribLocation(program, A_POSITION);  
        uMatrixLocation = GLES20.glGetUniformLocation(program, U_MATRIX);
        aTextureCoordinates = GLES20.glGetAttribLocation(program, A_TEXTURE_COORDINATES);
		uTextureUnitLocation = GLES20.glGetAttribLocation(program, U_TEXTURE_UNIT);
		texture = TextureHelper.loadTexture(context, R.drawable.umei);
		// Set the active texture unit to texture unit 0.
        glActiveTexture(GL_TEXTURE0);
        // Bind the texture to this unit.
        glBindTexture(GL_TEXTURE_2D, texture);
        // Tell the texture uniform sampler to use this texture in the shader by
        // telling it to read from texture unit 0.
        glUniform1i(uTextureUnitLocation, 0);
        //传入顶点坐标和纹理坐标
        GLES20.glVertexAttribPointer(aPositionLocation, POSITION_COMPONENT_COUNT,
				GLES20.GL_FLOAT, false, STRIDE, vertexBuffer);
		GLES20.glEnableVertexAttribArray(aPositionLocation);
		//设置从第二个元素开始读取,因为从第二个元素开始才是纹理坐标
		vertexBuffer.position(POSITION_COMPONENT_COUNT);
		GLES20.glVertexAttribPointer(aTextureCoordinates, TEXTURE_COORDIANTES_COMPONENT_COUNT,
				GLES20.GL_FLOAT, false, STRIDE, vertexBuffer);
		GLES20.glEnableVertexAttribArray(aTextureCoordinates);
    }  
      
    //获取program  
    private void getProgram(){  
        //获取顶点着色器文本  
        String vertexShaderSource = TextResourceReader  
                .readTextFileFromResource(context, R.raw.texture_vertex_shader);  
        //获取片段着色器文本  
        String fragmentShaderSource = TextResourceReader  
                .readTextFileFromResource(context, R.raw.texture_fragment_shader);  
        //获取program的id  
        program = ShaderHelper.buildProgram(vertexShaderSource, fragmentShaderSource);  
        GLES20.glUseProgram(program);  
    }  
    
    //设置正交投影矩阵
    public void projectionMatrix(int width,int height){  
        final float aspectRatio = width > height ?  
                (float) width / (float) height :  
                (float) height / (float) width;  
        if(width > height){  
            Matrix.orthoM(projectionMatrix, 0, -aspectRatio, aspectRatio, -1f, 1f, -1f, 1f);  
        }else{  
            Matrix.orthoM(projectionMatrix, 0, -1f, 1f, -aspectRatio, aspectRatio, -1f, 1f);  
        }  
    }  
    
    //以GL_LINE_LOOP方式绘制  
    public void draw(){  
    	GLES20.glUniformMatrix4fv(uMatrixLocation, 1, false, projectionMatrix, 0);
        GLES20.glDrawArrays(GLES20.GL_TRIANGLE_FAN, 0, VERTEX_COUNTS);  
    }  
}

为了方便观察,将MyRender类onSurfaceCreated方法中设置的颜色更改为 glClearColor(0.5f,0.5f,0.5f, 1.0f);    

运行一下 :















OpenGL ES 正交投影与透视投影 正交投影与透视投影的源码; 该源码是 OpenGL 示例源码集合. OpenGL 需要依赖 v7 包 立即下载

相关推荐

OpenGLES demo - 11. 透视投影变换

Opengles 入门教程中的第11章,讲解透视投影变换的示例代码

OpenGL ES学习(6)——认识纹理

想要实现更加绚丽的真实世界,需要用到纹理。本文章介绍OpenGL ES 2.0下纹理映射原理,纹理拉伸和采样、Mipmap纹理...

ITMonkeyKing的博客 1098

Android平台下的全景视频播放器配套教程——1.3 用OpenGL ES 2.0显示一张图片

Android平台下的全景视频播放器配套教程——1.3 用OpenGL ES 2.0显示一张图片

【OpenGL ES】立方体贴图(6张图)

1 前言 本文通过一个立方体贴图的例子,讲解三维纹理贴图的应用,案例中使用 6 张不同的图片给立方体贴图。本文涉及到的知识点主要包含:三维绘图、MVP 矩阵变换、纹理贴图,读者如果对 OpenGL ES 不太熟悉,请回顾以下内容: 绘制立方体 MVP矩阵变换 纹理贴图 项目目录如下: 2 案例 MainActivity.java package com.zhyan8.texture3d; import android.opengl....

little_fat_sheep 3669

Atlas 300I Pro推理卡性能深度测试:对比业界同类产品的能效比与算力表现

本文对昇腾Atlas 300I Pro推理卡进行了深度性能评测,重点对比了其与业界同类产品的能效比与算力表现。实测数据显示,该卡在运行BERT等模型时展现出高达39.6句子/秒/瓦的卓越能效比,电力成本可降低40%以上,同时其达芬奇架构和硬件加速特征检索能力,为高密度在线推理和向量检索场景提供了强大支撑。

weixin_29031161的博客 578

Cesium生态盘点:超图、火星3D等15个二次开发框架对比

本文深入解析Cesium生态中的15个二次开发框架,包括超图、火星3D等主流选择,帮助开发者根据项目需求进行精准选型。从性能表现、功能完备性、开发友好度等维度进行对比,特别适合需要处理地理空间数据和构建三维可视化的JavaScript开发者。

weixin_28197941的博客 497

计算机图形学头歌实训平台纹理映射答案

【代码】计算机图形学头歌实训平台纹理映射答案。

m0_74822776的博客 761

SPSSAU 中介效应分析实战:Bootstrap 95%置信区间解读的3个关键步骤

本文详细解析了SPSSAU中介效应分析中Bootstrap 95%置信区间的解读方法,涵盖三种典型场景的判别标准与应对策略。通过实战操作指南,帮助研究者准确判断中介效应显著性,特别针对边界模糊和小样本情况提供专业建议,提升统计分析结果的可靠性。

weixin_33691817的博客 498

OpenglES2.0 for Android:再谈纹理映射

OpenglES2.0 for Android:再谈纹理映射 上一节我们实现了一个简单的纹理映射的例子——一个简单的贴图,这节我们来做一些稍微复杂一点的例子,最后再使用我们前面实现的立方体来做一个骰子。 纹理拉伸  重复拉伸方式 这种是经常使用的一张纹理拉伸方式,常用于绘制一些重复的元素,比如我们在游戏绘制一幅方格式的地图时。使用重复拉伸方式

cassiePython的专栏 8027

AT32串口打印全攻略:从零搭建到printf重定向(GCC版)

本文详细介绍了在GCC编译环境下为AT32系列MCU实现串口打印与printf重定向的完整方案。针对从Keil MDK迁移到GCC工具链时常见的串口无输出问题,文章从环境搭建、USART配置入手,重点剖析了GCC下printf重定向的核心原理——通过重写_write()函数,并提供了经过验证的代码实现、常见问题排查及性能优化建议。

weixin_29163797的博客 264

团结引擎+OpenHarmony 记录 (持续更新中)

获取不到的原因是因为二者不在同一个线程中,所以数据没有同步。而 globalThis.context 数据进行了同步。(TuanjieMainWorkerHandler.ts中可以看到)在进行绘制 UI 的时候 ,如果组件有 Native API 就可能不会显示出来,例如 web 控件就不能展示出来,刚加上权限的时候 会报错 因为缺少 reason ,添加上就不会报错了。只有纯 UI 控件是可以展示出来的,注释掉 web控件后就可以。

m_cainiaokuaifei的博客 1490

Android OpenGLES2.0开发(七):纹理贴图之显示图片

本文讲解了纹理贴图的基本用法,纹理坐标和OpenGL ES坐标系的不同

xiaozhiwz的专栏 1923

多 Agent 之间如何通信和协调?OpenClaw 的 Gateway 在其中扮演什么角色?

多 Agent 之间如何通信和协调?OpenClaw 的 Gateway 在其中扮演什么角色?

我哎GIS博客 1665

OpenglES2.0 for Android:来做个地球吧

OpenglES2.0 for Android:来做个地球吧 上两节中我们说了纹理映射,也利用纹理给我们的平面图形以及立方体穿上了漂亮的衣服,在继续学习其他知识之前,让我们先来用纹理映射以及我们前面做的球 来实现一个地球的贴图。整体效果如下 图所示: 贴图所需要的图片素材如下 : 素材  " 窃取 ” 了csdn另一位网友的

cassiePython的专栏 3732

【ATC/DTC方法第一期】经典平均/昼夜温度周期ATC/DTC方法介绍(含Python代码实现)

【ATC/DTC方法第一期】经典平均/昼夜温度周期ATC/DTC方法介绍(含Python代码实现)

WW、forever的博客 484

无人机——电机篇(一)

1. 电机的定义 电机俗称“马达”,是无人机的动力来源,无人机通过改变电机的转速来改变无人机的飞行状态。即改变每个电机的速度,使得无人机能够盘旋空中,上升或下降,或向各个方向移动。2. 电机的分类 电机分为:“无刷电机”和“有刷电机” - 无刷电机:是采用半导体开关器件来实现电子换向,具有可靠性高、低干扰、低噪声低、寿命长等优点。一般应用在稍大型的飞行器,载重大,可以有更广泛的用途。 - 有刷电机:是内含电刷装置的将电能转换成机械能(电动机)或将机械能转换成电能(发电机)的旋转电机。有刷电机是所有电机的基

weixin_46066938的博客 1万+

Android OpenGLES2.0(八)——纹理贴图之显示图片

前面几篇博客,我们将了Android中利用OpenGL ES 2.0绘制各种形体,并在上一篇博客中专门讲了GLSL语言。但是我们看到的基于OpenGL开发的应用和游戏,可不仅仅是那些规则形体和一些简单的色彩构成,而是各种不规则的形体构成了现实世界或者卡通世界的人和事物,他们都是外面穿着漂亮“衣服”的。本篇博客就是来讲解这些“衣服”的基础的。这些衣服就是纹理贴图。什么是纹理贴图 一般说来,纹理是表

偶尔记录的一些学习笔记 3万+

大中型超市收银系统(可直接运行)

光步前台收银系统系统功能:商品销售、商品退货、挂单、收银员权限、会员销售、单品取消、整单取消、商品查询、脱机销售、脱机数据上传,基本资料下载,开钱箱、小票打印、收款结算,支持多币种付款方式(现金、储值卡、礼券、微信等),支持多种促销。运行环境:.net 4.0登陆信息用户名:1001 密码:123456内置商品信息,商品编码可输入00001000 - 00010000,测试效果相关功能键F5 结算 F9挂单 F11商品查询 F8退货 Insert单品取消 Del整单取消 F12开钱箱F2 会员 Ctrl+Z退出系统 Home 锁屏 相关源码待公开

Android OpenGLES2.0(一)OpenGLES2.0基础介绍

Andoid OpenGlES基础认识,OpenGL在不同的平台上有不同的实现,但是它定义好了专业的程序接口,不同的平台都是遵照该接口来进行实现的,思想完全相同,方法名也是一致的,所以使用时也基本一致,只需要根据不同的语言环境稍有不同而已。OpenGL这套3D图形API从1992年发布的1.0版本到目前最新2014年发布的4.5版本,在众多平台上多有着广泛的使用。...

主要记录一些问题处理记录,部分是作为知识库使用 2400

C# WinForm 基于DirectShow.dll编写的程序,可边预览边保存视频,音频和图片

基于微软的DirectShow.dll的二次开发1.自动识别连接的摄像头跟麦克风且可以对其进行选择(默认选中第一个)2.可录制wmv和avi两种格式的视频并且都带有音频,avi可以录制的分辨率和帧数进行选择,wmv默认进行了淸晰度优化如不喜欢可去除代码中有相关提示3.可在预览点开之后进行拍照,也可边录制视频边拍照4.添加了视频和音频的压缩功能(酌情使用)这次二次开发发现C#对DirectShow的相关信息太少,这次做完也不敢藏私共享出来,还望大家指正

WINCC7.3破解文件

WINCC7.3硬件够破解文件,有需要的下载!WINCC7.3硬件够破解文件,有需要的下载!

OpenGL ES 2.0 for Android教程(七):使用纹理添加细节

我们已经设法用简单的形状和颜色完成了很多工作。不过,我们缺少了一些东西:如果我们希望在图形上绘画,并添加精致的细节呢?像艺术家一样,我们可以从基本图形和颜色开始,通过使用纹理在表面上添加额外的细节。简单来说,纹理就是可以加载到OpenGL上的图像或图片。 我们可以通过纹理(Texture)添加大量细节。想想你最近可能玩过的一款精美的3D游戏,这些游戏的本质也只是使用点、线和三角形,就像其他3D程序一样。然而,通过纹理添加的细节和艺术家的加工,这些三角形可以用纹理构建美丽的3D场景。 一旦我们开始使用纹理

重来的博客 9472

OV9734 DATASHEET,完整规格书

OV9734完整规格书,包括电气参数,尺寸规格,寄存器配置表等

Android OpenGLES2.0(一)——了解OpenGLES2.0

什么是OpenGL ES? OpenGL(全写Open Graphics Library)是指定义了一个跨编程语言、跨平台的编程接口规格的专业的图形程序接口。它用于三维图像(二维的亦可),是一个功能强大,调用方便的底层图形库。 OpenGL在不同的平台上有不同的实现,但是它定义好了专业的程序接口,不同的平台都是遵照该接口来进行实现的,思想完全相同,方法名也是一致的,所以使用时也基本一致,只需要根

偶尔记录的一些学习笔记 3万+

LearnOpenGL - Android OpenGL ES 3.0 绘制纹理

在LearnOpenGL - Android OpenGL ES 3.0 绘制三角形中我们学会了如何在 Android 下搭建 GLES 环境,并绘制三角形。本文我们将讨论如何绘制纹理。本文代码在顶点着色器: 执行次数与顶点数量相同,每个顶点执行一次。片元着色器: 执行次数与片元(像素)数量相同,每个片元执行一次。因此,片元着色器的执行次数通常远多于顶点着色器的执行次数,因为片元数量通常大于顶点数量。具体执行次数取决于渲染的几何图形在屏幕上的覆盖范围。

记录学习的过程 1337

(转)使用OpenGL显示图像(七)Android OpenGLES2.0——纹理贴图之显示图片

转:http://blog.csdn.net/junzia/article/details/52842816 前面几篇博客,我们将了Android中利用OpenGL ES 2.0绘制各种形体,并在上一篇博客中专门讲了GLSL语言。但是我们看到的基于OpenGL开发的应用和游戏,可不仅仅是那些规则形体和一些简单的色彩构成,而是各种不规则的形体构成了现实世界或者卡通世界的人和事物,他们都是...

828
上一篇: OpenglES2.0 for Android:来画个球吧
下一篇: OpenglES2.0 for Android:再谈纹理映射
cassiePython
博客等级 码龄12年 303粉丝 135原创
评论 2
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值