C++模拟OpenGL库——图片处理及纹理系统(四):UV纹理坐标

news2024/10/6 16:31:52

目录

引入UV纹理坐标及三角形绘制设置

纹理过滤


引入UV纹理坐标及三角形绘制设置

 上图其实不是很直观。

UV坐标要解决的问题就是:

假设我有一张500×500的纹理图片;

我要把它映射到一张200×200的图片中;

这个问题要怎么去解决。

这里提出的UV坐标,就是一种”比例“,用(u,v)直接乘以原图的像素坐标(x,y),那么我们就可以直接获得原像素的颜色值,从而映射到目标图片中。

我们在Canvas画布类中添加纹理相关的属性与方法:

同理的,绘制中颜色既然要插值,uv坐标同样需要插值:

void Canvas::drawTriange(Point p1, Point p2, Point p3){
    ...
    float s = (float)(newPoint.m_y - ptMin.m_y) / (float)(ptMax.m_y - ptMin.m_y);
	newPoint.m_color = colorLerp(ptMin.m_color, ptMax.m_color, s);
	newPoint.m_uv = uvLerp(ptMin.m_uv, ptMax.m_uv, s);
    ...
}
	void Canvas::drawTriangeFlat(Point pFlat1, Point pFlat2, Point pt) {
		//两边直线斜率
		float k1 = 0.0;
		float k2 = 0.0;

		if (pFlat1.m_x != pt.m_x) {
			k1 = (float)(pFlat1.m_y - pt.m_y) / (float)(pFlat1.m_x - pt.m_x);
		}
		if (pFlat2.m_x != pt.m_x) {
			k2 = (float)(pFlat2.m_y - pt.m_y) / (float)(pFlat2.m_x - pt.m_x);
		}

		//两直线b值
		float b1 = (float)pt.m_y - (float)pt.m_x * k1;
		float b2 = (float)pt.m_y - (float)pt.m_x * k2;

		//做垂线
		int yStart = MIN(pt.m_y, pFlat1.m_y);
		int yEnd = MAX(pt.m_y, pFlat1.m_y);
		if (yStart < 0)yStart = 0;
		if (yEnd > m_height)yEnd = m_height - 1;


		//颜色插值相关
		RGBA colorStart1, colorEnd1;
		RGBA colorStart2, colorEnd2;

		floatV2 uvStart1, uvEnd1;
		floatV2 uvStart2, uvEnd2;

		if (pt.m_y < pFlat1.m_y) {
			yStart = pt.m_y;
			yEnd = pFlat1.m_y;

			colorStart1 = pt.m_color;
			colorEnd1 = pFlat1.m_color;
			colorStart2 = pt.m_color;
			colorEnd2 = pFlat2.m_color;

			uvStart1 = pt.m_uv;
			uvEnd1 = pFlat1.m_uv;
			uvStart2 = pt.m_uv;
			uvEnd2 = pFlat2.m_uv;
		}
		else {
			yStart = pFlat1.m_y;
			yEnd = pt.m_y;

			colorStart1 = pFlat1.m_color;
			colorEnd1 = pt.m_color;
			colorStart2 = pFlat2.m_color;
			colorEnd2 = pt.m_color;

			uvStart1 = pFlat1.m_uv;
			uvEnd1 = pt.m_uv;
			uvStart2 = pFlat2.m_uv;
			uvEnd2 = pt.m_uv;
		}
		float yColorStep = 1.0 / ((float)(yEnd - yStart));
		int yColorStart = yStart;


		for (int y = yStart; y <= yEnd; ++y) {
			int x1 = 0;
			//判断是否为直角三角形
			if (k1 == 0) {
				x1 = pFlat1.m_x;
			}
			else {
				x1 = ((float)y - b1) / k1;
			}
			//剪裁
			if (x1 < 0)x1 = 0;
			if (x1 > m_width)x1 = m_width - 1;

			int x2 = 0;
			//判断是否为直角三角形
			if (k2 == 0) {
				x2 = pFlat2.m_x;
			}
			else {
				x2 = ((float)y - b2) / k2;
			}
			//剪裁
			if (x2 < 0)x2 = 0;
			if (x2 > m_width)x2 = m_width - 1;

			//构建这两个点
			float s1 = (float)(y - yColorStart) * yColorStep;
			RGBA _color1 = colorLerp(colorStart1, colorEnd1, s1);
			RGBA _color2 = colorLerp(colorStart2, colorEnd2, s1);

			floatV2 _uv1 = uvLerp(uvStart1, uvEnd1, s1);
			floatV2 _uv2 = uvLerp(uvStart2, uvEnd2, s1);

			Point pt1(x1, y, _color1, _uv1);
			Point pt2(x2, y, _color2, _uv2);

			//绘制直线
			drawLine(pt1, pt2);
		}
	}
	void GT::Canvas::drawLine(Point pt1, Point pt2) {
		int disX = abs(pt2.m_x - pt1.m_x);
		int disY = abs(pt2.m_y - pt1.m_y);

		int xNow = pt1.m_x;
		int yNow = pt1.m_y;

		int stepX = 0;
		int stepY = 0;

		//判断两个方向步进的正负
		stepX = pt1.m_x < pt2.m_x ? 1 : -1;
		stepY = pt1.m_y < pt2.m_y ? 1 : -1;

		//对比xy偏移量,决定步进方向选取x or y
		int sumStep = disX;
		bool useXStep = true;
		if (disX < disY) {
			sumStep = disY;
			useXStep = false;
			SWAP_INT(disX, disY);
		}

		//初始化P
		int p = 2 * disY - disX;
		RGBA _color;
		for (int i = 0; i <= sumStep; ++i) {
			
			float _scale = 0;
			if (useXStep) {
				if (pt2.m_x == pt1.m_x)
					_scale = 0;
				else
					_scale = (float)(xNow - pt1.m_x) / (float)(pt2.m_x - pt1.m_x);
			}
			else {
				if (pt1.m_y == pt2.m_y)
					_scale = 0;
				else
					_scale = (float)(yNow - pt1.m_y) / (float)(pt2.m_y - pt1.m_y);
			}

			//启用纹理
			if (m_enableTexture) {
				floatV2 _uv = uvLerp(pt1.m_uv, pt2.m_uv, _scale);
				if (m_texture) {
					_color = m_texture->getColorbyUV(_uv.x, _uv.y);
				}
				else {
					_color = colorLerp(pt1.m_color, pt2.m_color, _scale);
				}
			}
			else {
				_color = colorLerp(pt1.m_color, pt2.m_color, _scale);
			}
			drawPoint(xNow, yNow, _color);

			if (p >= 0) {
				if (useXStep) {
					yNow += stepY;
				}
				else {
					xNow += stepX;
				}
				p = p - 2 * disX;
			}
			//步进主坐标
			if (useXStep) {
				xNow += stepX;
			}
			else {
				yNow += stepY;
			}
			p = p + 2 * disY;
		}
	}

测试一下:

//===========================Render==================================================
void Render() {
    _canvas->clear();

    GT::Point ptArray[] = {
        {0,0,GT::RGBA(255,0,0),GT::floatV2(0,0)},
        {500,0,GT::RGBA(255,0,0),GT::floatV2(1.0,0)},
        {250,300,GT::RGBA(255,0,0),GT::floatV2(0.5,1.0)}
    };

    _canvas->enableTexture(true);
    _canvas->bindTexture(_bkImage);
    _canvas->drawTriange(ptArray[0], ptArray[1], ptArray[2]);

    //在这里画到设备上,hMem相当于缓冲区
    BitBlt(hDC, 0, 0, wWidth, wHeight, hMem, 0, 0, SRCCOPY);
}

纹理过滤

直接上代码看效果。其实就是OpenGL里的纹理过滤:纹理 - LearnOpenGL CN (learnopengl-cn.github.io)

 

void Render() {
    _canvas->clear();

    GT::Point ptArray[] = {
        {0,0,       GT::RGBA(255,0,0),GT::floatV2(0,0)},
        {500,0,     GT::RGBA(255,0,0),GT::floatV2(1.0,0)},
        {500,300,   GT::RGBA(255,0,0),GT::floatV2(1.0,1.0)}
    };

    GT::Point ptArray1[] = {
        {0,0,       GT::RGBA(255,0,0),GT::floatV2(0,0)},
        {0,300,     GT::RGBA(255,0,0),GT::floatV2(0.0,1.0)},
        {500,300,   GT::RGBA(255,0,0),GT::floatV2(1.0,1.0)}
    };

    for (int i = 0; i < 3; i++) {
        ptArray[i].m_uv.x += 0.5;
        ptArray1[i].m_uv.x += 0.5;
    }

    _canvas->enableTexture(true);
    _canvas->bindTexture(_bkImage);
    _canvas->setTextureType(GT::Image::TX_REPEAT);
    _canvas->drawTriange(ptArray[0], ptArray[1], ptArray[2]);
    _canvas->drawTriange(ptArray1[0], ptArray1[1], ptArray1[2]);

    //在这里画到设备上,hMem相当于缓冲区
    BitBlt(hDC, 0, 0, wWidth, wHeight, hMem, 0, 0, SRCCOPY);
}

TX_REPEAT过滤: 

TX_CLAMP_TO_EDGE过滤

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/20224.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【附源码】Python计算机毕业设计网络考试系统设计

项目运行 环境配置&#xff1a; Pychram社区版 python3.7.7 Mysql5.7 HBuilderXlist pipNavicat11Djangonodejs。 项目技术&#xff1a; django python Vue 等等组成&#xff0c;B/S模式 pychram管理等等。 环境需要 1.运行环境&#xff1a;最好是python3.7.7&#xff0c;…

百度第三季度财报前瞻:财务业绩预计将超预期

来源&#xff1a;猛兽财经 作者&#xff1a;猛兽财经 百度&#xff08;BIDU&#xff09;此前于2022年11月8日发布了一份媒体新闻稿&#xff0c;强调其将在2022年11月22日公布其第三季度财报。 分析师预计百度第三季度的财务业绩将有所改善 根据卖方分析师对百度的一致财务预测&…

基于GPU的kokkos加速安装

基于GPU的kokkos加速安装基于GPU的kokkos加速安装1. 安装lammps2. 安装cmake3. cmake相关文件修改4. cmake编译5. 测试安装lammps及相关库的步骤网上很多&#xff0c;这里介绍在前期步骤准备好的情况下&#xff0c;如果in文件中包含反应力 场以及需要通过voronoi库计算应力&…

【文本分类】《融合知识感知与双重注意力的短文本分类模型》

阅读摘要&#xff1a;   本文主要提出基于TextRCNN模型使用知识图谱、双重注意力感知来改进短文本分类&#xff0c;最终提高了精度。 参考文献&#xff1a;   [1] 融合知识感知与双重注意力的短文本分类模型 参考论文信息 &#xff08;很牛&#xff09; 论文名称&#xff1…

算法课实验报告解析(4班供参考)

有两个题1.第一题2.第二题1.第一题 &#x1f60b;题目描述&#xff1a; 给定一个整数数组A(ao&#xff0c;a1&#xff0c;…,an-1),若岗且ai>aj&#xff0c;则<ai.aj>就为一个逆序对。例如数组&#xff08;3,1,4,5,2,&#xff09;的逆序对有<3,1>、< 3,2>…

C++STL-string类的实现(上)

在上一篇中&#xff0c;我们知道了string类的一些基本使用&#xff0c;这一篇我们就说一下string类的具体的底层实现。 文章目录1.预前准备1.1 初步的构造和析构1.2 下标的运算符重载2. 深浅拷贝2.1 拷贝构造函数2.2 运算符重载3. 完善前面写的函数3.1 完善构造函数和析构函数…

【自用】Linux服务器部署Oracle并使用数据库管理工具Navicat远程连接(包含远程Navicat配置)

一、服务器端 配置 0.传输oracle安装包和依赖 1.更新依赖 yum update2.检测oracle依赖 rpm -ivh oracle-database-preinstall-19c-1.0-1.el7.x86_64.rpm # 请根据版本选择3.yum安装oracle-database-preinstall yum install oracle-database-preinstall-19c-1.0-1.el7.x86_6…

Azide-PEG-Cholesterol,N3-PEG-Cholesterol,叠氮-PEG-胆固醇PEG试剂供应

化学试剂胆固醇-聚乙二醇-叠氮,其英文名为Cholesterol-PEG-Azide&#xff08;Cholesterol-PEG-N3&#xff09;&#xff0c;它所属分类为DSPE PEG Azide PEG。 试剂胆固醇PEG叠氮的分子量均可定制&#xff0c;有&#xff1a;Cholesterol-PEG 2k-Azide、胆固醇-聚乙二醇 3.4k-叠…

SMBMS系统_准备工作

构建项目Maven/jar 初次构建项目时&#xff0c;思考是不是通过maven创建&#xff0c;使用maven的化需要导入那些依赖&#xff1b; 如果不是使用maven创建项目的话&#xff0c;使用哪些些jar包。 检测验证项目 选择使用maven创建项目完成&#xff0c;可以使用模板&#xff0c…

嵌入式分享合集106

一、可控硅控制电路实例 可控硅是可控硅整流器的简称。可控硅有单向、双向、可关断和光控几种类型。它具有体积小、重量轻、效率高、寿命长、控制方便等优点&#xff0c;被广泛用于可控整流、调压、逆变以及无触点开关等各种自动控制和大功率的电能转换的场合。 单向可控硅是一…

【CloudCompare教程】001:CloudCompare中文版下载与安装图文教程

CloudCompare是一款功能强大的点云后处理软件,本文讲解CloudCompare中文版下载与安装方法。 文章目录 一、CloudCompare下载地址二、CloudCompare安装教程三、CloudCompare中文设置一、CloudCompare下载地址 官方下载地址:http://www.danielgm.net/cc/release/ 二、CloudComp…

vue中使用wangeditor富文本编辑器

官方文档 项目中要求实现富文本编辑器取编辑内容 这种编辑器有好多选择了wangeditor富文本编辑器 首先根据文档安装 yarn add wangeditor/editor # 或者 npm install wangeditor/editor --saveyarn add wangeditor/editor-for-vuenext # 或者 npm install wangeditor/edit…

MySQL进阶实战8,分区表详解

目录一、分区表二、分区的作用三、分区的一些限制四、分区表的增删改查1、select2、insert3、delete4、update五、分区表的类型六、如何使用分区表七、分区表会有哪些问题&#xff1f;1、分区列和索引列不匹配2、选择分区的成本可能很高3、打开并锁住所有底层表的成本可能会很高…

统计信号处理基础 习题解答6-9

题目&#xff1a; 在开关键控&#xff08;OOK&#xff09;的通信系统中&#xff0c;我们发射两个信号中的一个&#xff0c;即 表示bit0&#xff0c;而 表示bit1。假定幅度是正的&#xff0c;为了确定发射的是哪个bit&#xff0c;我们对接收机的波形在符号周期内 进行采样&…

深入了解快速排序和归并排序

作者&#xff1a;~小明学编程 文章专栏&#xff1a;Java数据结构 格言&#xff1a;目之所及皆为回忆&#xff0c;心之所想皆为过往 快速排序和归并排序作为排序中的两个重点&#xff0c;也是面试中最常考的两个知识点&#xff0c;这里带大家详解的了解这两个排序。 目录 快速…

DSPE-PEG-TPP;磷脂-聚乙二醇-磷酸三苯酯;(阻燃剂TPP)是种含磷元素的化合物,可用作无卤环保型阻燃剂

中文名称&#xff1a; 二硬脂酰基磷脂酰乙醇胺-聚乙二醇-磷酸三苯酯&#xff1b;三苯基磷聚乙二醇磷脂 英文简称&#xff1a; DSPE-PEG-TPP,TPP-PEG-DSPE 分子量&#xff1a; 2000,3400,5000等 溶剂: 溶于部分有机溶剂 磷酸三苯酯为无味、无臭的白色结…

JDK8 连接Access数据库

JDK8 连接Access数据库1. 安装JDK82. 下载配置文件3. 源码设置前面我们讲了如何使用Java连接ODBC并配置Access数据库&#xff0c; 参考连接&#xff1a;https://jackwei.blog.csdn.net/article/details/86285822 可以知道JDK8之后已经不支持jdbc-odbc桥接了&#xff0c;如果你可…

windows10上运行magic keyboard和magic mouse

windows10上运行magic keyboard和magic mouse并保持你的mac习惯 所有需要的软件和插件都可以在这里寻找到链接&#xff1a;https://pan.baidu.com/s/1Y8vjRnznqKP7f8dFFrHoGw?pwdvpsy 提取码&#xff1a;vpsy 安装蓝牙 你的windows电脑可能自带了蓝牙&#xff0c;那你直接…

保姆级教程带你从0到1实现基于bitcask的kv存储引擎

愿景 ​ 今年大部分业余时间都在nutsdb的开源贡献上&#xff0c;nutsdb是基于bitcask模型实现的持久化存储引擎&#xff0c;提供了诸如list&#xff0c;set等多种丰富的数据结构。近来很多小伙伴&#xff0c;其中也有一些我的好朋友陆陆续续加入到这个项目上来。为了帮助小伙伴…

tensorflow2 SqueezeNet

前面学习了通过加深网络和加宽网络来改进模型质量&#xff0c;提高模型精度的深度学习backbone模型&#xff08;LeNet,VGGNet,AlexNet,GoogleNet,ResNet),这里介绍如何使网络更快&#xff0c;结构更轻量化的改进深度神经网络模型之一————SqueezeNet&#xff0c;它能够在Ima…