通过Three.js也许可以很方便的展示出3D模型,但是你知道它是怎么一步一步从构建网格到贴图到最终渲染出3D模型的吗?现在我们直接使用底层的webgl加上一点点的数学知识就可以实现它。

本节实现的效果: WebGL三维地球

内容大纲

  1. 构建网格

  2. 编写着色器

  3. 实现3D地球

构建网格

首先我们要建立球体的三维模型,三维网格模型包括如下属性(不熟悉请复习webgl教程):

  • 顶点(position)
  • 法线(normal)
  • 贴图坐标(uv)
  • 顶点索引(indices)

最后要构建出如下所示的经纬球模型

首先可以从xy平面构建圆形,接着再从xz平面将圆形转化为圆球,这其中只需使用到三角函数而已,是不是非常简单。

  • 法线使用的是顶点坐标,因为法线与顶点其实方向是一致的
  • 顶点索引为6个点,是因为每个面由两个三角形构成
  • 贴图uv坐标不需要深度信息,它对应上贴图的xy坐标即可

下面就是构建网格模型的基本逻辑:

const radius = 8;//半径
const n = 20;//经纬度格数
const position = [];//顶点
const normal = [];//法线
const texcoord = [];//uv坐标
const indices = [];//顶点索引
let x, y, z; for (let i = 0; i < n; i++) {
const rad = Math.PI / n * i - Math.PI / 2;//从-90度开始计算
const r = radius * Math.cos(rad);
y = radius * Math.sin(rad);
for (let j = 0; j < n; j++) {
x = r * Math.sin(xRadian * j);
z = r * Math.cos(xRadian * j);
position.push(x, y, z);
texcoord.push(j / n, i / n);
normal.push(x, y, z); //顶点作为法线,法线从圆心360度放射
const c = i * (n + 1) + j
indices.push(c, c + 1, c + l + 1, c, c + l + 1, c + l);//平面的索引
}
}

编写着色器

和普通着色器相比,只是增加了uv坐标,uv直接通过顶点着色器差值透传到片段着色器即可,在片段着色器使用texture2D函数获取uv坐标对应的颜色,整体上也是比较基础。

// 顶点着色器
attribute vec4 aPosition;
attribute vec4 aNormal;
attribute vec2 aTexcoord;
uniform mat4 modelMatrix;
uniform mat4 vpMatrix;
varying vec3 fragPos;
varying vec3 fragNor;
varying vec2 texcoord; void main() {
gl_Position = vpMatrix * modelMatrix * aPosition;
fragPos= vec3(modelMatrix * aPosition);
fragNor = vec3(modelMatrix * aNormal);
texcoord = aTexcoord;
} // 片段着色器
precision mediump float;
uniform vec3 viewPos;
uniform vec3 lightPos;
uniform vec3 lightColor;
uniform vec3 ambientColor;
uniform sampler2D diffMap;
varying vec3 fragPos;
varying vec3 fragNor;
varying vec2 texcoord; void main() {
vec3 normal = normalize(fragNor);
vec3 color = texture2D(diffMap, texcoord).rgb; // 光线方向
vec3 lightDir = normalize(lightPos - fragPos);
// 光线方向和法向量夹角
float cosTheta = max(dot(lightDir, normal), 0.0);
// 漫反射
vec3 diffuse = lightColor * color * cosTheta; // 环境光
// ...
// 高光
// ... gl_FragColor = vec4(ambient + diffuse + specular, 1.0);
}

实现3D地球

最后实现部分就和之前的webgl基本逻辑一致,不过要准备好地球贴图

图片加载完将构建好的贴图sampler传入着色器即可,其他都是基础业务逻辑,不再详述,这样我们就将三维地球实现了

//...
const vpMatrix = m4.identity();
const uniforms = {
modelMatrix: m4.identity(),
lightPos: [20, 0, -20],
lightColor: [1, 1, 1],
ambientColor: [0.5, 0.5, 0.5],
}; gl.clearColor(0.1, 0.1, 0.1, 1);
gl.enable(gl.DEPTH_TEST);//深度测试
gl.enable(gl.CULL_FACE);//背面剔除
gl.viewport(0, 0, canvas.width, canvas.height); //设置绘图区域
gl.useProgram(program.program); function animate() {
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
m4.multiply(projection, m4.inverse(m4.lookAt(eye, [0, 0, 0], [0, 1, 0])), vpMatrix);
setBuffersAndAttributes(gl, vao);
setUniforms(program, { vpMatrix });
drawBufferInfo(gl, vao);
gl.bindVertexArray(null); requestAnimationFrame(animate);
}; //加载贴图后执行
createTexture(gl, { src: '/img/earth.jpg', flipY: true }, texture => {
uniforms.diffMap = texture;
setUniforms(program, uniforms );
animate();
});

WebGL之绘制三维地球的更多相关文章

  1. 无插件,跨平台,基于WebGL的三维地球来了!!!

    用户通过浏览器即可递交数据到同一个地理信息系统中,操作简单,跨平台 ,无插件,可扩展,高效共享 ,完美匹配超大数据量发布! 近年来,随着计算机图形学.虚拟现实.卫星遥感.航空摄影.激光雷达等技术的迅猛 ...

  2. 开源三维地球GIS引擎Cesium常用功能的开发

    Cesium是一个非常优秀的三维地球GIS引擎(开源且免费).能够加载各种符合标准的地图图层,瓦片图.矢量图等都支持.支持3DMax等建模软件生成的obj文件,支持通用的GIS计算:支持DEM高程图. ...

  3. [js] webgl 初探 - 绘制三角形

    摘要: 1. webgl 概念挺多的, 顶点着色器.片段着色器, 坐标 2. 绘制前期准备工作好多 目前看的比较好的教材: https://developer.mozilla.org/zh-CN/do ...

  4. matlab绘制三维图形

    原文地址:种三维曲面图. 程序如下: [x,y]=meshgrid(-8:0.5:8); z=sin(sqrt(x.^2+y.^2))./sqrt(x.^2+y.^2+eps); subplot(2, ...

  5. Python学习(一) —— matplotlib绘制三维轨迹图

    在研究SLAM时常常需要对其输出的位姿进行复现以检测算法效果,在ubuntu系统中使用Python可以很好的完成相关的工作. 一. Ubuntu下Python的使用 在Ubuntu下使用Python有 ...

  6. Matlab绘图基础——绘制三维表面

    %绘制三维表面 ------------------------------------- %1.绘制线框图:mesh:每一条曲线称为mesh line %首先利用meshgrid函数产生平面区域内的 ...

  7. Matlab绘图基础——绘制三维曲线

    %% 绘制三维曲线 %plot3函数,其中每一组x,y,z组成一组曲线的坐标参数,选项的定义和plot函数相同. %1.当x,y,z是同维向量时,则x,y,z 对应元素构成一条三维曲线. x0 = 0 ...

  8. Matlab绘制三维曲面(以二维高斯函数为例)

    原文地址为:Matlab绘制三维曲面(以二维高斯函数为例) 寒假学习了一下Python下的NumPy和pymatlab,感觉不是很容易上手.来学校之后,决定继续看完数字图像处理一书.还是想按照上学期的 ...

  9. Python使用matplotlib绘制三维曲线

    本文主要演示如何使用matplotlib绘制三维图形 代码如下: # -*- coding: UTF-8 -*- import matplotlib as mpl from mpl_toolkits. ...

随机推荐

  1. jdbc连接数据库(oracle、mysql)

    很简单,直接贴代码吧!代码注释自认为足够理解! 第一步创建数据库连接类,数据库连接地址.数据库驱动.用户名.密码建议创建为公共变量,方便修改,一目了然. package db; import java ...

  2. 前端传数据到后台,后台用实体类接收不到引发的思考----Java bean中字段命名潜规则

    1.按照Java语法规范,通常在实体类中的属性,首字母都是小写的.这是由于JavaBean的规范导致的.一般JavaBean属性都是首字母小写,以驼峰命名格式命名,相应的 getter/setter ...

  3. SpringBoot Test 多线程报错:dataSource already closed

    1:前言 最近在项目中使用多线程对大任务拆分处理时,进行数据库操作的时候报错了. 业务代码大概是这样的: @Service public calss TestServiceImpl implement ...

  4. 采用lua脚本获取mysql、redis数据以及jwt的校验

    一.安装配置Openresty 1,安装 wget https://openresty.org/download/ngx_openresty-1.9.7.1.tar.gz # 下载 tar xzvf ...

  5. spring boot +dubbo 踩坑记录

    今天初次搭建spring boot +duboo的demo.记录一下踩坑记录. 首先搭建3个小demo,一个maven项目,两个spring boot (服务提供者和服务消费者)项目. 两 sprin ...

  6. 你们一般都是怎么进行SQL调优的?MySQL在执行时是如何选择索引的?

    前言 过年回来的第二周了,终于有时间继续总结知识了.这次来看一下SQL调优的知识,这类问题基本上面试的时候都会被问到,无论你的岗位是后端,运维,测试等等. 像本文标题中的两个问题,就是我在实际面试过程 ...

  7. 阿里巴巴Druid,轻松实现MySQL数据库连接加密!

    为什么要加密? 现在的开发习惯,无论是公司的项目还是个人的项目,都会选择将源码上传到 Git 服务器(GitHub.Gitee 或是自建服务器),但只要将源码提交到公网服务器就会存在源码泄漏的风险,而 ...

  8. 《C++ Primer》笔记 第7章 类

    成员函数的声明必须在类的内部,它的定义则既可以在类的内部也可以在类的外部.作为接口组成部分的非成员函数,它们的定义和声明都在类的外部. 定义在类内部的函数是隐式的inline函数. 成员函数通过一个名 ...

  9. 使用CSS计数器美化数字有序列表

    在web设计中,使用一种井井有条的方法来展示数据是十分重要的,这样用户就可以很清晰的理解网站所展示的数据结构和内容,使用有序列表就是实现数据有组织的展示的一种简单方法. 如果你需要更加深入地控制有序列 ...

  10. [个人总结]利用grad-cam实现人民币分类

    # -*- coding:utf-8 -*- import os import numpy as np import torch import cv2 import torch.nn as nn fr ...