OpenGL南邮计算机图形学实验报告三——实现类似地月系统的两物体环绕移动

OpenGL南邮计算机图形学实验报告三——实现类似地月系统的两物体环绕移动

计算机图形学的题目要求

OpenGL配置参考:
南邮老前辈wonz哥的OpenGL配置(Shader.h始终不用改)、SOIL2 环境配置、GLM 环境配置

学习网站:LearnOpenGL CN

思路:

本次新增了镜头camera
由于课上讲了制作一个环绕移动的光源,只要讲运动圆心设为中心体的中心即可(初始化的时候设置就行),并将旋转设置为对应的轴(我选择了z轴)
谁发光谁不发光就不管了,嘿嘿
代码较前面几个实验修改的地方看下面:

glm::vec3 lightPos = glm::vec3(1.0f, 1.0f, 0.0f);
/*
*
*
*/
lightPos = glm::rotate(lightPos, glm::radians(0.1f), glm::vec3(0.0f, 0.0f, 1.0f));

效果图如下:
在这里插入图片描述
在这里插入图片描述

话不多说上代码:

main.cpp 文件
(135行有误,勘正在评论区)

#include<iostream>

//GLEW
#define GLEW_STATIC
#include<GL/glew.h>

//GLFW
#include<GLFW/glfw3.h>
#include"shader.h"
#include"Camera.h"
#include"Light.h"

#include "SOIL2/SOIL2.h"
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtc/type_ptr.hpp>
#include<glm/gtx/rotate_vector.hpp>

const GLint WIDTH = 800, HEIGTH = 600;

void KeyCallback(GLFWwindow* window, int key, int scancode, int action, int mode);
void MouseCallback(GLFWwindow* window, double xPos, double yPos);
void DoMovement();

bool keys[1024];
Camera camera(glm::vec3(0.0f, 0.0f, 2.0f));
GLfloat deltaTime = 0.0f;
GLfloat lastTime = 0.0f;

GLfloat lastX = WIDTH / 2.0;
GLfloat lastY=HEIGTH/2.0;

bool firstMouse = true;

int main()
{
	glfwInit();
	glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
	glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
	glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
	glfwWindowHint(GLFW_RESIZABLE, GL_FALSE);

	GLFWwindow* window = glfwCreateWindow(WIDTH, HEIGTH, "Learn OpenGL", nullptr, nullptr);
	if (nullptr == window)
	{
		std::cout << "Failed to create GLFW window" << std::endl;
		glfwTerminate();
		return -1;
	}
	//next two lines are for mac retina display
	int screenWidth, screenHeight;
	glfwGetFramebufferSize(window, &screenWidth, &screenHeight);

	glfwMakeContextCurrent(window);

	glfwSetKeyCallback(window, KeyCallback);
	glfwSetCursorPosCallback(window, MouseCallback);
	//glfwSetScrollCallback(window, ScrollCallback);

	glewExperimental = GL_TRUE;

	if (GLEW_OK != glewInit())
	{
		std::cout << "Failed to initialise GLEW" << std::endl;
		return -1;
	}
	glViewport(0, 0, screenWidth, screenHeight);

	glEnable(GL_DEPTH_TEST);
	glDepthFunc(GL_LESS);
	glEnable(GL_BLEND);
	glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
	Shader ourShader = Shader("res/shaders/core.vs", "res/shaders/core.fs");
	Shader lightShader= Shader("res/shaders/light.vs", "res/shaders/light.fs");

	Light lightModel = Light();
	glm::vec3 lightPos = glm::vec3(1.0f, 1.0f, 0.0f);//设置光源的起始坐标,既然z坐标为0则下面绕z轴转动
	
	GLfloat vertices[] =
	{
		// position					//color					//normal

		-0.5f,-0.5f,0.5f,			0.0f,1.0f,0.0f,		0.0f,0.0f,-0.1f,
		0.5f,-0.5f,0.5f,			0.0f,1.0f,0.0f,		0.0f,0.0f,-0.1f,
		0.5f,0.5f,0.5f,			0.0f,1.0f,0.0f,		0.0f,0.0f,-0.1f,
		0.5f,0.5f,0.5f,			0.0f,1.0f,0.0f,		0.0f,0.0f,-0.1f,
		-0.5f,0.5f,0.5f,			0.0f,1.0f,0.0f,		0.0f,0.0f,-0.1f,
		-0.5f,-0.5f,0.5f,			0.0f,1.0f,0.0f,		0.0f,0.0f,-0.1f,

		-0.5f,-0.5f,-0.5f,		1.0f,0.0f,0.0f,		0.0f,0.0f,0.1f,
		0.5f,-0.5f,-0.5f,			1.0f,0.0f,0.0f,		0.0f,0.0f,0.1f,
		0.5f,0.5f,-0.5f,			1.0f,0.0f,0.0f,		0.0f,0.0f,0.1f,
		0.5f,0.5f,-0.5f,			1.0f,0.0f,0.0f,		0.0f,0.0f,0.1f,
		-0.5f,0.5f,-0.5f,			1.0f,0.0f,0.0f,		0.0f,0.0f,0.1f,
		-0.5f,-0.5f,-0.5f,		1.0f,0.0f,0.0f,		0.0f,0.0f,0.1f,

		-0.5f,0.5f,0.5f,			0.0f,0.0f,1.0f,	  1.0f,0.0f,0.0f,
		-0.5f,0.5f,-0.5f,			0.0f,0.0f,1.0f,	  1.0f,0.0f,0.0f,
		-0.5f,-0.5f,-0.5f,		0.0f,0.0f,1.0f,	  1.0f,0.0f,0.0f,
		-0.5f,-0.5f,-0.5f,		0.0f,0.0f,1.0f,	  1.0f,0.0f,0.0f,
		-0.5f,-0.5f,0.5f,			0.0f,0.0f,1.0f,	  1.0f,0.0f,0.0f,
		-0.5f,0.5f,0.5f,			0.0f,0.0f,1.0f,	  1.0f,0.0f,0.0f,

		0.5f,0.5f,0.5f,			1.0f,1.0f,0.0f,		-1.0f,0.0f,0.0f,
		0.5f,0.5f,-0.5f,			1.0f,1.0f,0.0f,		-1.0f,0.0f,0.0f,
		0.5f,-0.5f,-0.5f,			1.0f,1.0f,0.0f,		-1.0f,0.0f,0.0f,
		0.5f,-0.5f,-0.5f,			1.0f,1.0f,0.0f,		-1.0f,0.0f,0.0f,
		0.5f,-0.5f,0.5f,			1.0f,1.0f,0.0f,		-1.0f,0.0f,0.0f,
		0.5f,0.5f,0.5f,			1.0f,1.0f,0.0f,		 -1.0f,0.0f,0.0f,

		-0.5f,-0.5f,-0.5f,		1.0f,0.0f,1.0f,		0.0f,-1.0f,0.0f,
		0.5f,-0.5f,-0.5f,			1.0f,0.0f,1.0f,		0.0f,-1.0f,0.0f,
		0.5f,-0.5f,0.5f,			1.0f,0.0f,1.0f,		0.0f,-1.0f,0.0f,
		0.5f,-0.5f,0.5f,			1.0f,0.0f,1.0f,		0.0f,-1.0f,0.0f,
		-0.5f,-0.5f,0.5f,			1.0f,0.0f,1.0f,		0.0f,-1.0f,0.0f,
		-0.5f,-0.5f,-0.5f,		1.0f,0.0f,1.0f,		0.0f,-1.0f,0.0f,

		-0.5f,0.5f,-0.5f,			0.0f,1.0f,1.0f,		0.0f,1.0f,0.0f,
		0.5f,0.5f,-0.5f,			0.0f,1.0f,1.0f,		0.0f,1.0f,0.0f,
		0.5f,0.5f,0.5f,			0.0f,1.0f,1.0f,		0.0f,1.0f,0.0f,
		0.5f,0.5f,0.5f,			0.0f,1.0f,1.0f,		0.0f,1.0f,0.0f,
		-0.5f,0.5f,0.5f,			0.0f,1.0f,1.0f,		0.0f,1.0f,0.0f,
		-0.5f,0.5f,-0.5f,			0.0f,1.0f,1.0f,		0.0f,1.0f,0.0f,
	};																 
	GLuint VAO, VBO;
	glGenVertexArrays(1, &VAO);
	glGenBuffers(1, &VBO);
	glBindVertexArray(VAO);
	glBindBuffer(GL_ARRAY_BUFFER, VBO);
	glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
	glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 9 * sizeof(GLfloat), (GLvoid*)0);
	glEnableVertexAttribArray(0);
	glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 9 * sizeof(GLfloat), (GLvoid*)(3 * sizeof(GLfloat)));
	glEnableVertexAttribArray(1);
	glVertexAttribPointer(2, 3, GL_FLOAT, GL_FALSE, 9 * sizeof(GLfloat), (GLvoid*)(3 * sizeof(GLfloat)));
	glEnableVertexAttribArray(2);

	glBindBuffer(GL_ARRAY_BUFFER, 0);
	glBindVertexArray(0);

	while (!glfwWindowShouldClose(window))
	{
		GLfloat currentTime = glfwGetTime();
		deltaTime = currentTime - lastTime;
		lastTime = currentTime;

		glfwPollEvents();
		DoMovement();
		glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
		glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
		glm::mat4 transform = glm::mat4(1.0f);

		lightPos = glm::rotate(lightPos, glm::radians(0.1f), glm::vec3(0.0f, 0.0f, 1.0f));
		transform = glm::translate(transform, lightPos);
		transform = glm::scale(transform, glm::vec3(0.1f, 0.1f, 0.1f));
		glm::mat4 projection = glm::mat4(1.0f);
		projection = glm::perspective(glm::radians(camera.GetZoom()), float(screenWidth) / float(screenHeight), 0.1f, 100.0f);
		glm::mat4 view = camera.GetViewMatrix();

		lightShader.Use();
		GLuint transLoc = glGetUniformLocation(lightShader.Program, "transform");
		glUniformMatrix4fv(transLoc, 1, GL_FALSE, glm::value_ptr(transform));
		transLoc = glGetUniformLocation(lightShader.Program, "projection");
		glUniformMatrix4fv(transLoc, 1, GL_FALSE, glm::value_ptr(projection));
		transLoc = glGetUniformLocation(lightShader.Program, "view");
		glUniformMatrix4fv(transLoc, 1, GL_FALSE, glm::value_ptr(view));
		lightModel.Draw(lightShader);

		transform = glm::mat4(1.0f);
		transform = glm::rotate(transform, glm::radians(90.0f) * static_cast<GLfloat>(glfwGetTime()), glm::vec3(1.0f, 1.0f, 1.0f));
		//transform = glm::scale(transform, glm::vec3(0.5f, 0.5f, 0.5f));
		//transform = glm::translate(transform, glm::vec3(0.1f, 0.0f,-0.8f));
		

		ourShader.Use();
		transLoc = glGetUniformLocation(ourShader.Program, "transform");
		glUniformMatrix4fv(transLoc, 1, GL_FALSE, glm::value_ptr(transform));
		transLoc= glGetUniformLocation(ourShader.Program, "projection");
		glUniformMatrix4fv(transLoc, 1, GL_FALSE, glm::value_ptr(projection));
		transLoc = glGetUniformLocation(ourShader.Program, "view");
		glUniformMatrix4fv(transLoc, 1, GL_FALSE, glm::value_ptr(view));
		glUniform3f(glGetUniformLocation(ourShader.Program, "LightPos"), lightPos.x, lightPos.y, lightPos.z);
		glUniform3f(glGetUniformLocation(ourShader.Program, "ViewPos"),camera.GetPosition().x, camera.GetPosition().y, camera.GetPosition().z);
		glUniform1f(glGetUniformLocation(ourShader.Program, "material.diffuse"), 0.6f);
		glUniform1f(glGetUniformLocation(ourShader.Program, "material.specular"), 0.9f);

		glBindVertexArray(VAO);
		glDrawArrays(GL_TRIANGLES, 0, 36);
		glBindVertexArray(0);
		glfwSwapBuffers(window);
	}
	glDeleteVertexArrays(1, &VAO);
	glDeleteBuffers(1, &VBO);
	ourShader.~Shader();
	glfwTerminate();
	return 0;
}

void KeyCallback(GLFWwindow* window, int key, int scancode, int action, int mode)
{
	if (key == GLFW_KEY_ESCAPE && action == GLFW_PRESS)
	{
		glfwSetWindowShouldClose(window, GL_TRUE);
	}
	if (key >= 0 && key < 1024)
	{
		if (action == GLFW_PRESS)
			keys[key] = true;
		else if (action == GLFW_RELEASE)
			keys[key] = false;
	}
}

void DoMovement()
{
	if (keys[GLFW_KEY_W] || keys[GLFW_KEY_UP]) {
		camera.ProcessKeyboard(FORWARD, deltaTime);
	}
	if (keys[GLFW_KEY_S] || keys[GLFW_KEY_DOWN]) {
		camera.ProcessKeyboard(BACKWARD, deltaTime);
	}
	if (keys[GLFW_KEY_A] || keys[GLFW_KEY_LEFT]) {
		camera.ProcessKeyboard(LEFT, deltaTime);
	}
	if (keys[GLFW_KEY_D] || keys[GLFW_KEY_RIGHT]) {
		camera.ProcessKeyboard(RIGHT, deltaTime);
	}
}

void MouseCallback(GLFWwindow* window, double xPos, double yPos)
{
	if (firstMouse)
	{
		lastX = xPos;
		lastY = yPos;
		firstMouse = false;
	}
	GLfloat xOffset = xPos - lastX;
	GLfloat yOffset = lastY - yPos;

	lastX = xPos;
	lastY = yPos;
	camera.ProcessMouseMovement(xOffset, yOffset);
}


Camera.h 文件

#pragma once
#ifndef Camera_h
#define Camera_h

#include<vector>
#define GLEW_STATIC
#include<GL/glew.h>

#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>

const GLfloat YAW = -90.0f;
const GLfloat PITCH = 0.0f;
const GLfloat ZOOM = 45.0f;
const GLfloat SPEED = 6.0f;
const GLfloat SENSITIVITY = 0.25f;

enum Camera_Movement
{
	FORWARD,
	BACKWARD,
	LEFT,
	RIGHT
};
class Camera
{
public:
	Camera(glm::vec3 position = glm::vec3(0.0f, 0.0f, 0.0f), glm::vec3 up = glm::vec3(0.0f, 1.0f, 0.0f), GLfloat yaw = YAW, GLfloat pitch = PITCH) :front(glm::vec3(0.0f, 0.0f, -1.0f)), zoom(ZOOM),movementSpeed(SPEED),mouseSensitivity(SENSITIVITY)
	{
		this->position = position;
		this->worldUp = up;
		this->yaw = yaw;
		this->pitch = pitch;
		this->updateCameraVectors();
	}
	glm::mat4 GetViewMatrix()
	{
		return glm::lookAt(this->position, this->position + this->front, this->up);
	}
	GLfloat GetZoom()
	{
		return this->zoom;
	}
	glm::vec3 GetPosition()
	{
		return this->position;
	}
	void ProcessKeyboard(Camera_Movement direction,GLfloat deltaTima)
	{
		GLfloat velocity = this->movementSpeed * deltaTima;
		if (direction == FORWARD) {
			this->position += this->front * velocity;
		}
		if (direction == BACKWARD) {
			this->position -= this->front * velocity;
		}
		if (direction == LEFT) {
			this->position -= this->right * velocity;
		}
		if (direction == RIGHT) {
			this->position += this->right * velocity;
		}
	}
	void ProcessMouseMovement(GLfloat xOffset,GLfloat yOffset)
	{
		xOffset *= this->mouseSensitivity;
		yOffset *= this->mouseSensitivity;

		this->yaw += xOffset;
		this->pitch += yOffset;
		this->updateCameraVectors();
	}
private:
	glm::vec3 front;
	glm::vec3 position;
	glm::vec3 up;
	glm::vec3 right;
	glm::vec3 worldUp;
	GLfloat zoom;
	GLfloat yaw;
	GLfloat pitch;
	GLfloat movementSpeed;
	GLfloat mouseSensitivity;
	void updateCameraVectors()
	{
		glm::vec3 front;
		front.x = cos(glm::radians(this->pitch)) * cos(glm::radians(this->yaw));
		front.y = sin(glm::radians(this->pitch));
		front.z = cos(glm::radians(this->pitch)) * sin(glm::radians(this->yaw));
		this->front = glm::normalize(front);
		this->right = glm::normalize(glm::cross(this->front, this->worldUp));
		this->up = glm::normalize(glm::cross(this->right, this->front));
	}
};



#endif // !Camera

Light.h 文件

#pragma once
#ifndef Light_h
#define Light_h

#include<GL/glew.h>
#include"shader.h"
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>

GLfloat vertices[] =
{
	-0.5f,-0.5f,0.5f,
	0.5f,-0.5f,0.5f,
	0.5f,0.5f,0.5f,
	0.5f,0.5f,0.5f,
	-0.5f,0.5f,0.5f,
	-0.5f,-0.5f,0.5f,

	-0.5f,-0.5f,-0.5f,
	0.5f,-0.5f,-0.5f,
	0.5f,0.5f,-0.5f,
	0.5f,0.5f,-0.5f,
	-0.5f,0.5f,-0.5f,
	-0.5f,-0.5f,-0.5f,

	-0.5f,0.5f,0.5f,
	-0.5f,0.5f,-0.5f,
	-0.5f,-0.5f,-0.5f,
	-0.5f,-0.5f,-0.5f,
	-0.5f,-0.5f,0.5f,
	-0.5f,0.5f,0.5f,

	0.5f,0.5f,0.5f,
	0.5f,0.5f,-0.5f,
	0.5f,-0.5f,-0.5f,
	0.5f,-0.5f,-0.5f,
	0.5f,-0.5f,0.5f,
	0.5f,0.5f,0.5f,

	-0.5f,-0.5f,-0.5f,
	0.5f,-0.5f,-0.5f,
	0.5f,-0.5f,0.5f,
	0.5f,-0.5f,0.5f,
	-0.5f,-0.5f,0.5f,
	-0.5f,-0.5f,-0.5f,

	-0.5f,0.5f,-0.5f,
	0.5f,0.5f,-0.5f,
	0.5f,0.5f,0.5f,
	0.5f,0.5f,0.5f,
	-0.5f,0.5f,0.5f,
	-0.5f,0.5f,-0.5f,
};

class Light
{
public:
	Light()
	{
		this->update();
	}
	void Draw(Shader &shader)
	{
		glBindVertexArray(this->VAO);
		glDrawArrays(GL_TRIANGLES, 0, 36);
		glBindVertexArray(0);
	}
private:
	GLuint VAO, VBO;
	void update()
	{
		glGenVertexArrays(1, &this->VAO);
		glGenBuffers(1, &this->VBO);
		glBindVertexArray(this->VAO);
		glBindBuffer(GL_ARRAY_BUFFER, this->VBO);
		glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
		glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(GLfloat), (GLvoid*)0);
		glEnableVertexAttribArray(0);
		glBindBuffer(GL_ARRAY_BUFFER, 0);
		glBindVertexArray(0);
	}
};


#endif // !Light_h

core.vs 文件

 #version 330 core
layout(location = 0) in vec3 position;
layout(location = 1) in vec3 color;
layout(location = 2) in vec3 normal;

out vec3 ourColor;
out vec3 Normal;
out vec3 FragPos;
uniform mat4 transform;
uniform mat4 projection;
uniform mat4 view;


void main()
{
	gl_Position =projection*view*transform* vec4(position,1.0f);
	FragPos=vec3(transform*vec4(position,1.0f));
	ourColor=color;
	Normal=vec3(transpose(inverse(transform)));
}

core.fs

#version 330 core
in vec3 ourColor;
in vec3 Normal;
in vec3 FragPos;
out vec4 color;

uniform vec3 LightPos;
uniform vec3 ViewPos;

struct Material
{
    float specular;
    float diffuse;
};

uniform Material material;

void main()
{
      // color = vec4(ourColor,0.5f);
      vec3 lightDirection=normalize(LightPos-FragPos);
      vec3 viewDirection=normalize(ViewPos-FragPos);
      vec3 norm=normalize(Normal);

      //环境光
      vec3 ambient=0.6f*ourColor;
      //漫反射
      float diff =material.diffuse *max(dot(norm,lightDirection),0.0f);
      vec3 diffuse=diff*ourColor;

      //镜面反射
      vec3 halfAngle=normalize(viewDirection+lightDirection);
      float spec=material.specular*pow(max(dot(norm,halfAngle),0.0f),32.0f);
      vec3 specular=spec*ourColor;

      color=vec4(ambient+diffuse+specular,1.0f);
}

light.vs 文件

 #version 330 core
layout(location = 0) in vec3 position;

uniform mat4 transform;
uniform mat4 projection;
uniform mat4 view;

void main()
{
	gl_Position =projection*view*transform* vec4(position,1.0f);
}

light.fs 文件

#version 330 core
out vec4 color;

void main()
{
       color = vec4(1.0f,1.0f,1.0f,1.0f);
}
  • 5
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论
实验一 OpenGL+GLUT开发平台搭建 5 小实验1: 开发环境设置 5 小实验2: 控制窗口位置和大小 6 小实验3:默认的可视化范围 6 小实验4:自定义可视化范围 7 小实验5: 几何对象变形的原因 8 小实验6: 视口坐标系及视口定义 8 小实验7:动态调整长宽比例,保证几何对象不变形 9 实验二 动画和交互 10 小实验1: 单缓冲动画技术 10 小实验2: 双缓冲动画技术 11 小实验3:键盘控制 13 小实验4:鼠标控制【试着单击鼠标左键或者右键,试着按下鼠标左键后再移动】 14 实验 几何变换、观察变换、维对象 16 小实验1:二维几何变换 16 小实验2:建模观察(MODELVIEW)矩阵堆栈 17 小实验3:正平行投影1 19 小实验4:正平行投影2 19 小实验5:正平行投影3 20 小实验6:透射投影1 21 小实验6:透射投影2 22 小实验7:维对象 24 实验四 光照模型和纹理映射 26 小实验1:光照模型1----OpenGL简单光照效果的关键步骤。 26 小实验2:光照模型2----光源位置的问题 28 小实验3:光照模型3----光源位置的问题 31 小实验4:光照模型4----光源位置的问题 33 小实验5:光照模型5----光源位置的问题 35 小实验6:光照模型6----光源位置的问题 38 小实验7:光照模型7----光源位置的动态变化 40 小实验8:光照模型8----光源位置的动态变化 43 小实验9:光照模型9---光源位置的动态变化 45 小实验10:光照模型10---聚光灯效果模拟 48 小实验11:光照模型11---多光源效果模拟 50 小实验12:光照效果和雾效果的结合 53 小实验13:纹理映射初步—掌握OpenGL纹理映射的一般步骤 56 小实验13:纹理映射—纹理坐标的自动生成(基于参数的曲面映射) 59 小实验14:纹理映射—纹理坐标的自动生成(基于参考面距离) 61

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

岚-岚岚岚岚岚

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值